Initial porting of some Felix shell commands to Gogo; a lot of this is still
likely to change. (FELIX-2042)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@941338 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/felixcommands/NOTICE b/gogo/felixcommands/NOTICE
new file mode 100644
index 0000000..37f2add
--- /dev/null
+++ b/gogo/felixcommands/NOTICE
@@ -0,0 +1,21 @@
+Apache Felix Gogo Basic Commands
+Copyright 2010 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+
+II. Used Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+
+III. License Summary
+- Apache License 2.0
diff --git a/gogo/felixcommands/pom.xml b/gogo/felixcommands/pom.xml
new file mode 100644
index 0000000..bda815b
--- /dev/null
+++ b/gogo/felixcommands/pom.xml
@@ -0,0 +1,76 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>1.2.0</version>
+ </parent>
+
+ <artifactId>org.apache.felix.gogo.felixcommands</artifactId>
+ <packaging>bundle</packaging>
+ <version>0.9.0-SNAPSHOT</version>
+ <name>Apache Felix Gogo Basic Commands</name>
+
+ <description>
+ Provides basic shell commands for Gogo.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.gogo</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+ <Private-Package>${pom.artifactId}</Private-Package>
+ <Bundle-Activator>${artifactId}.Activator</Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java
new file mode 100644
index 0000000..9d45ab4
--- /dev/null
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.felixcommands;
+
+import java.util.Hashtable;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+ public void start(BundleContext bc) throws Exception
+ {
+ Hashtable props = new Hashtable();
+ props.put("osgi.command.scope", "basic");
+ props.put("osgi.command.function", new String[] {
+ "bundlelevel", "frameworklevel", "headers", "help",
+ "install", "lb", "refresh", "resolve", "start",
+ "stop", "uninstall", "update" });
+ bc.registerService(
+ Basic.class.getName(), new Basic(bc), props);
+
+ props.put("osgi.command.scope", "files");
+ props.put("osgi.command.function", new String[] { "ls" });
+ bc.registerService(
+ Files.class.getName(), new Files(bc), props);
+ }
+
+ public void stop(BundleContext bc) throws Exception
+ {
+ }
+}
\ No newline at end of file
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java
new file mode 100644
index 0000000..ac06a23
--- /dev/null
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java
@@ -0,0 +1,721 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.felixcommands;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.command.Flag;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+
+public class Basic
+{
+ private final BundleContext m_bc;
+ private final List<ServiceReference> m_usedRefs = new ArrayList(0);
+
+ public Basic(BundleContext bc)
+ {
+ m_bc = bc;
+ }
+
+ public void bundlelevel(Long id)
+ {
+ // Get start level service.
+ ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
+ StartLevel sl = getService(StartLevel.class, ref);
+ if (sl == null)
+ {
+ System.out.println("Start Level service is unavailable.");
+ }
+ // Get the bundle start level.
+ else
+ {
+ Bundle bundle = getBundle(m_bc, id);
+ if (bundle != null)
+ {
+ System.out.println(bundle + " is level " + sl.getBundleStartLevel(bundle));
+ }
+ }
+
+ ungetServices();
+ }
+
+ public void bundlelevel(
+ @Flag(name="-s") boolean set,
+ @Flag(name="-i") boolean initial,
+ int level,
+ Long[] ids)
+ {
+ // Get start level service.
+ ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
+ StartLevel sl = getService(StartLevel.class, ref);
+ if (sl == null)
+ {
+ System.out.println("Start Level service is unavailable.");
+ }
+ else if (set && initial)
+ {
+ System.out.println("Cannot specify '-s' and '-i' at the same time.");
+ }
+ else if (!set && !initial)
+ {
+ System.out.println("Must specify either '-s' or '-i'.");
+ }
+ else if (level <= 0)
+ {
+ System.out.println("Specified start level must be greater than zero.");
+ }
+ // Set the initial bundle start level.
+ else if (initial)
+ {
+ if ((ids != null) && (ids.length == 0))
+ {
+ sl.setInitialBundleStartLevel(level);
+ }
+ else
+ {
+ System.out.println(
+ "Cannot specify bundles when setting initial start level.");
+ }
+ }
+ // Set the bundle start level.
+ else if (set)
+ {
+ List<Bundle> bundles = getBundles(m_bc, ids);
+ if (bundles != null)
+ {
+ for (Bundle bundle: bundles)
+ {
+ sl.setBundleStartLevel(bundle, level);
+ }
+ }
+ else
+ {
+ System.out.println("Must specify target bundles.");
+ }
+ }
+
+ ungetServices();
+ }
+
+ public void frameworklevel()
+ {
+ // Get start level service.
+ ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
+ StartLevel sl = getService(StartLevel.class, ref);
+ if (sl == null)
+ {
+ System.out.println("Start Level service is unavailable.");
+ }
+ System.out.println("Level is " + sl.getStartLevel());
+ ungetServices();
+ }
+
+ public void frameworklevel(int level)
+ {
+ // Get start level service.
+ ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
+ StartLevel sl = getService(StartLevel.class, ref);
+ if (sl == null)
+ {
+ System.out.println("Start Level service is unavailable.");
+ }
+ sl.setStartLevel(level);
+ ungetServices();
+ }
+
+ public void headers(Long[] ids)
+ {
+ List<Bundle> bundles = getBundles(m_bc, ids);
+ bundles = (bundles == null) ? Arrays.asList(m_bc.getBundles()) : bundles;
+ for (Bundle bundle : bundles)
+ {
+ String title = Util.getBundleName(bundle);
+ System.out.println("\n" + title);
+ System.out.println(Util.getUnderlineString(title));
+ Dictionary dict = bundle.getHeaders();
+ Enumeration keys = dict.keys();
+ while (keys.hasMoreElements())
+ {
+ Object k = (String) keys.nextElement();
+ Object v = dict.get(k);
+ System.out.println(k + " = " + Util.getValueString(v));
+ }
+ }
+ }
+
+ public void help()
+ {
+ ServiceReference[] refs = null;
+ try
+ {
+ refs = m_bc.getAllServiceReferences(null, "(osgi.command.scope=*)");
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // This should never happen.
+ }
+
+ for (ServiceReference ref : refs)
+ {
+ Object svc = m_bc.getService(ref);
+ if (svc != null)
+ {
+ String[] funcs = (String[]) ref.getProperty("osgi.command.function");
+
+ Map<String, List<Method>> commands = new HashMap();
+ for (String func : funcs)
+ {
+ commands.put(func, new ArrayList());
+ }
+
+ if (!commands.isEmpty())
+ {
+ Method[] methods = svc.getClass().getMethods();
+ for (Method method : methods)
+ {
+ List<Method> commandMethods = commands.get(method.getName());
+ if (commandMethods != null)
+ {
+ commandMethods.add(method);
+ }
+ }
+
+ for (Entry<String, List<Method>> entry : commands.entrySet())
+ {
+ System.out.println(entry.getKey());
+ for (Method m : entry.getValue())
+ {
+ System.out.println("--> " + m);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void install(String[] urls)
+ {
+ StringBuffer sb = new StringBuffer();
+
+ for (String url : urls)
+ {
+ String location = url.trim();
+ Bundle bundle = null;
+ try
+ {
+ bundle = m_bc.installBundle(location, null);
+ }
+ catch (IllegalStateException ex)
+ {
+ System.err.println(ex.toString());
+ }
+ catch (BundleException ex)
+ {
+ if (ex.getNestedException() != null)
+ {
+ System.err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ System.err.println(ex.toString());
+ }
+ }
+ catch (Exception ex)
+ {
+ System.err.println(ex.toString());
+ }
+ if (bundle != null)
+ {
+ if (sb.length() > 0)
+ {
+ sb.append(", ");
+ }
+ sb.append(bundle.getBundleId());
+ }
+ }
+ if (sb.toString().indexOf(',') > 0)
+ {
+ System.out.println("Bundle IDs: " + sb.toString());
+ }
+ else if (sb.length() > 0)
+ {
+ System.out.println("Bundle ID: " + sb.toString());
+ }
+ }
+
+ public void lb(
+ @Flag(name="-l") boolean showLoc,
+ @Flag(name="-s") boolean showSymbolic,
+ @Flag(name="-u") boolean showUpdate)
+ {
+ // Get start level service.
+ ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
+ StartLevel sl = getService(StartLevel.class, ref);
+ if (sl == null)
+ {
+ System.out.println("Start Level service is unavailable.");
+ }
+
+ Bundle[] bundles = m_bc.getBundles();
+ if (bundles != null)
+ {
+ printBundleList(bundles, sl, System.out, showLoc, showSymbolic, showUpdate);
+ }
+ else
+ {
+ System.out.println("There are no installed bundles.");
+ }
+
+ ungetServices();
+ }
+
+ public void refresh()
+ {
+ refresh((List) null);
+ }
+
+ public void refresh(Long[] ids)
+ {
+ List<Bundle> bundles = getBundles(m_bc, ids);
+ if ((bundles != null) && !bundles.isEmpty())
+ {
+ refresh(bundles);
+ }
+ }
+
+ public void refresh(List<Bundle> bundles)
+ {
+ // Get package admin service.
+ ServiceReference ref = m_bc.getServiceReference(PackageAdmin.class.getName());
+ PackageAdmin pa = getService(PackageAdmin.class, ref);
+ if (pa == null)
+ {
+ System.out.println("Package Admin service is unavailable.");
+ }
+ pa.refreshPackages((bundles == null)
+ ? null
+ : (Bundle[]) bundles.toArray(new Bundle[bundles.size()]));
+
+ ungetServices();
+ }
+
+ public void resolve()
+ {
+ resolve((List) null);
+ }
+
+ public void resolve(Long[] ids)
+ {
+ List<Bundle> bundles = getBundles(m_bc, ids);
+ if ((bundles != null) && !bundles.isEmpty())
+ {
+ resolve(bundles);
+ }
+ }
+
+ public void resolve(List<Bundle> bundles)
+ {
+ // Get package admin service.
+ ServiceReference ref = m_bc.getServiceReference(PackageAdmin.class.getName());
+ PackageAdmin pa = getService(PackageAdmin.class, ref);
+ if (pa == null)
+ {
+ System.out.println("Package Admin service is unavailable.");
+ }
+ pa.resolveBundles((bundles == null)
+ ? null
+ : (Bundle[]) bundles.toArray(new Bundle[bundles.size()]));
+
+ ungetServices();
+ }
+
+ public void start(
+ @Flag(name="-t") boolean trans,
+ @Flag(name="-p") boolean policy,
+ String[] ss)
+ {
+ int options = 0;
+
+ // Check for "transient" switch.
+ if (trans)
+ {
+ options |= Bundle.START_TRANSIENT;
+ }
+
+ // Check for "start policy" switch.
+ if (policy)
+ {
+ options |= Bundle.START_ACTIVATION_POLICY;
+ }
+
+ // There should be at least one bundle id.
+ if ((ss != null) && (ss.length >= 1))
+ {
+ for (String s : ss)
+ {
+ String id = s.trim();
+
+ try
+ {
+ Bundle bundle = null;
+
+ // The id may be a number or a URL, so check.
+ if (Character.isDigit(id.charAt(0)))
+ {
+ long l = Long.parseLong(id);
+ bundle = m_bc.getBundle(l);
+ }
+ else
+ {
+ bundle = m_bc.installBundle(id);
+ }
+
+ if (bundle != null)
+ {
+ bundle.start(options);
+ }
+ else
+ {
+ System.err.println("Bundle ID " + id + " is invalid.");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ System.err.println("Unable to parse id '" + id + "'.");
+ }
+ catch (BundleException ex)
+ {
+ if (ex.getNestedException() != null)
+ {
+ ex.printStackTrace();
+ System.err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ System.err.println(ex.toString());
+ }
+ }
+ catch (Exception ex)
+ {
+ System.err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ System.err.println("Incorrect number of arguments");
+ }
+ }
+
+ public void stop(Long[] ids) throws BundleException
+ {
+ List<Bundle> bundles = getBundles(m_bc, ids);
+
+ if (bundles == null)
+ {
+ System.out.println("Please specify the bundles to start.");
+ }
+ else
+ {
+ for (Bundle bundle : bundles)
+ {
+ bundle.stop();
+ }
+ }
+ }
+
+ public void uninstall(Long[] ids) throws BundleException
+ {
+ List<Bundle> bundles = getBundles(m_bc, ids);
+
+ if (bundles == null)
+ {
+ System.out.println("Please specify the bundles to uninstall.");
+ }
+ else
+ {
+ for (Bundle bundle : bundles)
+ {
+ bundle.uninstall();
+ }
+ }
+ }
+
+ public void update(Long id)
+ {
+ try
+ {
+ // Get the bundle.
+ Bundle bundle = getBundle(m_bc, id);
+ if (bundle != null)
+ {
+ bundle.update();
+ }
+ }
+ catch (BundleException ex)
+ {
+ if (ex.getNestedException() != null)
+ {
+ System.err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ System.err.println(ex.toString());
+ }
+ }
+ catch (Exception ex)
+ {
+ System.err.println(ex.toString());
+ }
+ }
+
+ public void update(Long id, String location)
+ {
+ if (location != null)
+ {
+ try
+ {
+ // Get the bundle.
+ Bundle bundle = getBundle(m_bc, id);
+ if (bundle != null)
+ {
+ InputStream is = new URL(location).openStream();
+ bundle.update(is);
+ }
+ else
+ {
+ System.err.println("Bundle ID " + id + " is invalid.");
+ }
+ }
+ catch (MalformedURLException ex)
+ {
+ System.err.println("Unable to parse URL.");
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Unable to open input stream: " + ex);
+ }
+ catch (BundleException ex)
+ {
+ if (ex.getNestedException() != null)
+ {
+ System.err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ System.err.println(ex.toString());
+ }
+ }
+ catch (Exception ex)
+ {
+ System.err.println(ex.toString());
+ }
+ }
+ else
+ {
+ System.err.println("Must specify a location.");
+ }
+ }
+
+ private static void printBundleList(
+ Bundle[] bundles, StartLevel startLevel, PrintStream out, boolean showLoc,
+ boolean showSymbolic, boolean showUpdate)
+ {
+ // Display active start level.
+ if (startLevel != null)
+ {
+ out.println("START LEVEL " + startLevel.getStartLevel());
+ }
+
+ // Print column headers.
+ String msg = " Name";
+ if (showLoc)
+ {
+ msg = " Location";
+ }
+ else if (showSymbolic)
+ {
+ msg = " Symbolic name";
+ }
+ else if (showUpdate)
+ {
+ msg = " Update location";
+ }
+ String level = (startLevel == null) ? "" : " Level ";
+ out.println(" ID " + " State " + level + msg);
+ for (int i = 0; i < bundles.length; i++)
+ {
+ // Get the bundle name or location.
+ String name = (String)
+ bundles[i].getHeaders().get(Constants.BUNDLE_NAME);
+ // If there is no name, then default to symbolic name.
+ name = (name == null) ? bundles[i].getSymbolicName() : name;
+ // If there is no symbolic name, resort to location.
+ name = (name == null) ? bundles[i].getLocation() : name;
+
+ // Overwrite the default value is the user specifically
+ // requested to display one or the other.
+ if (showLoc)
+ {
+ name = bundles[i].getLocation();
+ }
+ else if (showSymbolic)
+ {
+ name = bundles[i].getSymbolicName();
+ name = (name == null)
+ ? "<no symbolic name>" : name;
+ }
+ else if (showUpdate)
+ {
+ name = (String)
+ bundles[i].getHeaders().get(Constants.BUNDLE_UPDATELOCATION);
+ name = (name == null)
+ ? bundles[i].getLocation() : name;
+ }
+ // Show bundle version if not showing location.
+ String version = (String)
+ bundles[i].getHeaders().get(Constants.BUNDLE_VERSION);
+ name = (!showLoc && !showUpdate && (version != null))
+ ? name + " (" + version + ")" : name;
+ long l = bundles[i].getBundleId();
+ String id = String.valueOf(l);
+ if (startLevel == null)
+ {
+ level = "1";
+ }
+ else
+ {
+ level = String.valueOf(startLevel.getBundleStartLevel(bundles[i]));
+ }
+ while (level.length() < 5)
+ {
+ level = " " + level;
+ }
+ while (id.length() < 4)
+ {
+ id = " " + id;
+ }
+ out.println("[" + id + "] ["
+ + getStateString(bundles[i])
+ + "] [" + level + "] " + name);
+ }
+ }
+
+ private <T> T getService(Class<T> clazz, ServiceReference ref)
+ {
+ if (ref == null)
+ {
+ return null;
+ }
+ T t = (T) m_bc.getService(ref);
+ if (t != null)
+ {
+ m_usedRefs.add(ref);
+ }
+ return t;
+ }
+
+ private void ungetServices()
+ {
+ while (m_usedRefs.size() > 0)
+ {
+ m_bc.ungetService(m_usedRefs.remove(0));
+ }
+ }
+
+ private static String getStateString(Bundle bundle)
+ {
+ int state = bundle.getState();
+ if (state == Bundle.ACTIVE)
+ {
+ return "Active ";
+ }
+ else if (state == Bundle.INSTALLED)
+ {
+ return "Installed ";
+ }
+ else if (state == Bundle.RESOLVED)
+ {
+ return "Resolved ";
+ }
+ else if (state == Bundle.STARTING)
+ {
+ return "Starting ";
+ }
+ else if (state == Bundle.STOPPING)
+ {
+ return "Stopping ";
+ }
+ else
+ {
+ return "Unknown ";
+ }
+ }
+
+ private static Bundle getBundle(BundleContext bc, Long id)
+ {
+ Bundle bundle = bc.getBundle(id);
+ if (bundle == null)
+ {
+ System.err.println("Bundle ID " + id + " is invalid");
+ }
+ return bundle;
+ }
+
+ private static List<Bundle> getBundles(BundleContext bc, Long[] ids)
+ {
+ List<Bundle> bundles = new ArrayList<Bundle>();
+ if ((ids != null) && (ids.length > 0))
+ {
+ for (long id : ids)
+ {
+ Bundle bundle = getBundle(bc, id);
+ if (bundle != null)
+ {
+ bundles.add(bundle);
+ }
+ }
+ }
+ else
+ {
+ bundles = null;
+ }
+
+ return bundles;
+ }
+}
\ No newline at end of file
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Files.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Files.java
new file mode 100644
index 0000000..2d2f658
--- /dev/null
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Files.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.felixcommands;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+import org.osgi.framework.BundleContext;
+
+public class Files
+{
+ private final BundleContext m_bc;
+
+ public Files(BundleContext bc)
+ {
+ m_bc = bc;
+ }
+
+ public File[] ls(String pattern)
+ {
+ int idx = pattern.lastIndexOf(File.separatorChar);
+ boolean isWildcarded = (pattern.indexOf('*', idx) >= 0);
+ File[] files;
+ if (isWildcarded)
+ {
+ final List<String> pieces = parseSubstring(pattern.substring(idx + 1));
+ File dir = new File(pattern.substring(0, idx + 1));
+ files = dir.listFiles(new FileFilter() {
+ public boolean accept(File pathname)
+ {
+ return compareSubstring(pieces, pathname.getName());
+ }
+ });
+ }
+ else
+ {
+ File file = new File(pattern);
+ if (file.isDirectory())
+ {
+ files = file.listFiles();
+ }
+ else
+ {
+ files = new File[] { new File(pattern) };
+ }
+ }
+ return files;
+ }
+
+ public static List<String> parseSubstring(String value)
+ {
+ List<String> pieces = new ArrayList();
+ StringBuffer ss = new StringBuffer();
+ // int kind = SIMPLE; // assume until proven otherwise
+ boolean wasStar = false; // indicates last piece was a star
+ boolean leftstar = false; // track if the initial piece is a star
+ boolean rightstar = false; // track if the final piece is a star
+
+ int idx = 0;
+
+ // We assume (sub)strings can contain leading and trailing blanks
+ boolean escaped = false;
+loop: for (;;)
+ {
+ if (idx >= value.length())
+ {
+ if (wasStar)
+ {
+ // insert last piece as "" to handle trailing star
+ rightstar = true;
+ }
+ else
+ {
+ pieces.add(ss.toString());
+ // accumulate the last piece
+ // note that in the case of
+ // (cn=); this might be
+ // the string "" (!=null)
+ }
+ ss.setLength(0);
+ break loop;
+ }
+
+ // Read the next character and account for escapes.
+ char c = value.charAt(idx++);
+ if (!escaped && ((c == '(') || (c == ')')))
+ {
+ throw new IllegalArgumentException(
+ "Illegal value: " + value);
+ }
+ else if (!escaped && (c == '*'))
+ {
+ if (wasStar)
+ {
+ // encountered two successive stars;
+ // I assume this is illegal
+ throw new IllegalArgumentException("Invalid filter string: " + value);
+ }
+ if (ss.length() > 0)
+ {
+ pieces.add(ss.toString()); // accumulate the pieces
+ // between '*' occurrences
+ }
+ ss.setLength(0);
+ // if this is a leading star, then track it
+ if (pieces.size() == 0)
+ {
+ leftstar = true;
+ }
+ wasStar = true;
+ }
+ else if (!escaped && (c == '\\'))
+ {
+ escaped = true;
+ }
+ else
+ {
+ escaped = false;
+ wasStar = false;
+ ss.append(c);
+ }
+ }
+ if (leftstar || rightstar || pieces.size() > 1)
+ {
+ // insert leading and/or trailing "" to anchor ends
+ if (rightstar)
+ {
+ pieces.add("");
+ }
+ if (leftstar)
+ {
+ pieces.add(0, "");
+ }
+ }
+ return pieces;
+ }
+
+ public static boolean compareSubstring(List<String> pieces, String s)
+ {
+ // Walk the pieces to match the string
+ // There are implicit stars between each piece,
+ // and the first and last pieces might be "" to anchor the match.
+ // assert (pieces.length > 1)
+ // minimal case is <string>*<string>
+
+ boolean result = true;
+ int len = pieces.size();
+
+ int index = 0;
+
+loop: for (int i = 0; i < len; i++)
+ {
+ String piece = pieces.get(i);
+
+ // If this is the first piece, then make sure the
+ // string starts with it.
+ if (i == 0)
+ {
+ if (!s.startsWith(piece))
+ {
+ result = false;
+ break loop;
+ }
+ }
+
+ // If this is the last piece, then make sure the
+ // string ends with it.
+ if (i == len - 1)
+ {
+ if (s.endsWith(piece))
+ {
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+ break loop;
+ }
+
+ // If this is neither the first or last piece, then
+ // make sure the string contains it.
+ if ((i > 0) && (i < (len - 1)))
+ {
+ index = s.indexOf(piece, index);
+ if (index < 0)
+ {
+ result = false;
+ break loop;
+ }
+ }
+
+ // Move string index beyond the matching piece.
+ index += piece.length();
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java
new file mode 100644
index 0000000..acd9428
--- /dev/null
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.felixcommands;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+public class Util
+{
+ public static String getBundleName(Bundle bundle)
+ {
+ if (bundle != null)
+ {
+ String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+ return (name == null)
+ ? "Bundle " + Long.toString(bundle.getBundleId())
+ : name + " (" + Long.toString(bundle.getBundleId()) + ")";
+ }
+ return "[STALE BUNDLE]";
+ }
+ private final static StringBuffer m_sb = new StringBuffer();
+
+ public static String getUnderlineString(String s)
+ {
+ synchronized (m_sb)
+ {
+ m_sb.delete(0, m_sb.length());
+ for (int i = 0; i < s.length(); i++)
+ {
+ m_sb.append('-');
+ }
+ return m_sb.toString();
+ }
+ }
+
+ public static String getValueString(Object obj)
+ {
+ synchronized (m_sb)
+ {
+ if (obj instanceof String)
+ {
+ return (String) obj;
+ }
+ else if (obj instanceof String[])
+ {
+ String[] array = (String[]) obj;
+ m_sb.delete(0, m_sb.length());
+ for (int i = 0; i < array.length; i++)
+ {
+ if (i != 0)
+ {
+ m_sb.append(", ");
+ }
+ m_sb.append(array[i].toString());
+ }
+ return m_sb.toString();
+ }
+ else if (obj instanceof Boolean)
+ {
+ return ((Boolean) obj).toString();
+ }
+ else if (obj instanceof Long)
+ {
+ return ((Long) obj).toString();
+ }
+ else if (obj instanceof Integer)
+ {
+ return ((Integer) obj).toString();
+ }
+ else if (obj instanceof Short)
+ {
+ return ((Short) obj).toString();
+ }
+ else if (obj instanceof Double)
+ {
+ return ((Double) obj).toString();
+ }
+ else if (obj instanceof Float)
+ {
+ return ((Float) obj).toString();
+ }
+ else if (obj == null)
+ {
+ return "null";
+ }
+ else
+ {
+ return obj.toString();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gogo/pom.xml b/gogo/pom.xml
index a24d329..b035990 100644
--- a/gogo/pom.xml
+++ b/gogo/pom.xml
@@ -37,6 +37,7 @@
<module>launcher</module>
<module>console</module>
<module>commands</module>
+ <module>felixcommands</module>
</modules>
<dependencyManagement>
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/osgi/OSGiCommands.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/osgi/OSGiCommands.java
index 459e504..9ca2be7 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/osgi/OSGiCommands.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/osgi/OSGiCommands.java
@@ -199,7 +199,7 @@
{
return i;
}
-
+/*
public String[] ls(CommandSession session, File f) throws Exception
{
File cwd = (File) session.get("_cwd");
@@ -232,7 +232,7 @@
return null;
}
-
+*/
public Object cat(CommandSession session, File f) throws Exception
{
File cwd = (File) session.get("_cwd");