merging mavenized branch changes from revision 382466 to the current head
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@383566 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.shell/pom.xml b/org.apache.felix.shell/pom.xml
new file mode 100644
index 0000000..0f2f517
--- /dev/null
+++ b/org.apache.felix.shell/pom.xml
@@ -0,0 +1,31 @@
+<project>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix</artifactId>
+ <version>0.8-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>jar</packaging>
+ <name>Apache Felix Shell Service</name>
+ <artifactId>org.apache.felix.shell</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.osgi</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>src/main/resources/Manifest.mf</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/CdCommand.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/CdCommand.java
new file mode 100644
index 0000000..d7c5a38
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/CdCommand.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell;
+
+/**
+ * This interface defines the <tt>cd</tt> command service interface for the
+ * Felix impl service. The <tt>cd</tt> command does not really change the
+ * directory of the impl, rather it maintains a base URL for
+ * simplifying URL entry.
+ * <p>
+ * For example, if the base URL is <tt>http://www.foo.com/<tt> and you
+ * try to install a bundle <tt>foo.jar</tt>, the actual URL will be
+ * expanded to <tt>http://www.foo.com/foo.jar</tt>. Any bundles wishing
+ * to retrieve or set the current directory of the impl can use this
+ * service interface.
+**/
+public interface CdCommand extends Command
+{
+ /**
+ * Property used to configure the base URL.
+ **/
+ public static final String BASE_URL_PROPERTY = "felix.shell.baseurl";
+
+ /**
+ * Returns the current <i>directory</i> of the impl service.
+ * @return the current impl directory.
+ **/
+ public String getBaseURL();
+
+ /**
+ * Sets the current <i>directory</i> of the impl service.
+ * @param s the new value for the base URL.
+ **/
+ public void setBaseURL(String s);
+}
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/Command.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/Command.java
new file mode 100644
index 0000000..f4bb0cc
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/Command.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell;
+
+import java.io.PrintStream;
+
+/**
+ * This interface is used to define commands for the Felix impl
+ * service. Any bundle wishing to create commands for the
+ * impl service simply needs to create a service object that
+ * implements this interface and then register it with the OSGi
+ * framework. The impl service automatically includes any
+ * registered command services in its list of available commands.
+**/
+public interface Command
+{
+ /**
+ * Returns the name of the command that is implemented by the
+ * interface. The command name should not contain whitespace
+ * and should also be unique.
+ * @return the name of the command.
+ **/
+ public String getName();
+
+ /**
+ * Returns the usage string for the command. The usage string is
+ * a short string that illustrates how to use the command on the
+ * command line. This information is used when generating command
+ * help information. An example usage string for the <tt>install</tt>
+ * command is:
+ * <pre>
+ * install <URL> [<URL> ...]
+ * </pre>
+ * @return the usage string for the command.
+ **/
+ public String getUsage();
+
+ /**
+ * Returns a short description of the command; this description
+ * should be as short as possible. This information is used when
+ * generating the command help information.
+ * @return a short description of the command.
+ **/
+ public String getShortDescription();
+
+ /**
+ * Executes the command using the supplied command line, output
+ * print stream, and error print stream.
+ * @param line the complete command line, including the command name.
+ * @param out the print stream to use for standard output.
+ * @param err the print stream to use for standard error.
+ **/
+ public void execute(String line, PrintStream out, PrintStream err);
+}
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/ShellService.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/ShellService.java
new file mode 100644
index 0000000..82d8b7e
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/ShellService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell;
+
+import java.io.PrintStream;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This interface defines the Felix impl service. The impl service
+ * is an extensible, user interface neutral impl for controlling and
+ * interacting with the framework. In general, the impl service assumes that
+ * it is operating in a command line fashion, i.e., it receives a
+ * complete command line, parses it, and executes the corresponding
+ * command, but graphical interfaces are also possible.
+ * <p>
+ * All commands in the impl service are actually implemented as OSGi
+ * services; these services implement the <tt>Command</tt> service
+ * interface. Any bundle can implement custom commands by creating
+ * command services and registering them with the OSGi framework.
+**/
+public interface ShellService
+{
+ /**
+ * Returns an array of command names available in the impl service.
+ * @return an array of available command names or an empty array.
+ **/
+ public String[] getCommands();
+
+ /**
+ * Returns the usage string associated with the specified command name.
+ * @param name the name of the target command.
+ * @return the usage string of the specified command or null.
+ **/
+ public String getCommandUsage(String name);
+
+ /**
+ * Returns the description associated with the specified command name.
+ * @param name the name of the target command.
+ * @return the description of the specified command or null.
+ **/
+ public String getCommandDescription(String name);
+
+ /**
+ * Returns the service reference associated with the specified
+ * command name.
+ * @param name the name of the target command.
+ * @return the description of the specified command or null.
+ **/
+ public ServiceReference getCommandReference(String name);
+
+ /**
+ *
+ * This method executes the supplied command line using the
+ * supplied output and error print stream. The assumption of
+ * this method is that a command line will be typed by the user
+ * (or perhaps constructed by a GUI) and passed into it for
+ * execution. The command line is interpretted in a very
+ * simplistic fashion; it takes the leading string of characters
+ * terminated by a space character (not including it) and
+ * assumes that this leading token is the command name. For an
+ * example, consider the following command line:
+ * </p>
+ * <pre>
+ * update 3 http://www.foo.com/bar.jar
+ * </pre>
+ * <p>
+ * This is interpretted as an <tt>update</tt> command; as a
+ * result, the entire command line (include command name) is
+ * passed into the <tt>execute()</tt> method of the command
+ * service with the name <tt>update</tt> if one exists. If the
+ * corresponding command service is not found, then an error
+ * message is printed to the error print stream.
+ * @param commandLine the command line to execute.
+ * @param out the standard output print stream.
+ * @param err the standard error print stream.
+ **/
+ public void executeCommand(
+ String commandLine, PrintStream out, PrintStream err)
+ throws Exception;
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/Activator.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/Activator.java
new file mode 100644
index 0000000..3e9a038
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/Activator.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.security.*;
+import java.util.*;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class Activator implements BundleActivator
+{
+ private transient BundleContext m_context = null;
+ private transient ShellServiceImpl m_shell = null;
+
+ public void start(BundleContext context)
+ {
+ m_context = context;
+
+ // Register impl service implementation.
+ String[] classes = {
+ org.apache.felix.shell.ShellService.class.getName(),
+ org.ungoverned.osgi.service.shell.ShellService.class.getName()
+ };
+ context.registerService(classes, m_shell = new ShellServiceImpl(), null);
+
+ // Listen for registering/unregistering of impl command
+ // services so that we can automatically add/remove them
+ // from our list of available commands.
+ ServiceListener sl = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event)
+ {
+ if (event.getType() == ServiceEvent.REGISTERED)
+ {
+ m_shell.addCommand(event.getServiceReference());
+ }
+ else if (event.getType() == ServiceEvent.UNREGISTERING)
+ {
+ m_shell.removeCommand(event.getServiceReference());
+ }
+ else
+ {
+ }
+ }
+ };
+
+ try
+ {
+ m_context.addServiceListener(sl,
+ "(|(objectClass="
+ + org.apache.felix.shell.Command.class.getName()
+ + ")(objectClass="
+ + org.ungoverned.osgi.service.shell.Command.class.getName()
+ + "))");
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ System.err.println("Activator: Cannot register service listener.");
+ System.err.println("Activator: " + ex);
+ }
+
+ // Now manually try to find any commands that have already
+ // been registered (i.e., we didn't see their service events).
+ initializeCommands();
+
+ // Register "exports" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new BundleLevelCommandImpl(m_context), null);
+
+ // Register "cd" command service.
+ classes = new String[2];
+ classes[0] = org.apache.felix.shell.Command.class.getName();
+ classes[1] = org.apache.felix.shell.CdCommand.class.getName();
+ context.registerService(
+ classes, new CdCommandImpl(m_context), null);
+
+ // Register "exports" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new PackagesCommandImpl(m_context), null);
+
+ // Register "headers" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new HeadersCommandImpl(m_context), null);
+
+ // Register "help" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new HelpCommandImpl(m_context), null);
+
+ // Register "install" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new InstallCommandImpl(m_context), null);
+
+ // Register "ps" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new PsCommandImpl(m_context), null);
+
+ // Register "refresh" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new RefreshCommandImpl(m_context), null);
+
+ // Register "services" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new ServicesCommandImpl(m_context), null);
+
+ // Register "startlevel" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new StartLevelCommandImpl(m_context), null);
+
+ // Register "shutdown" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new ShutdownCommandImpl(m_context), null);
+
+ // Register "start" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new StartCommandImpl(m_context), null);
+
+ // Register "stop" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new StopCommandImpl(m_context), null);
+
+ // Register "uninstall" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new UninstallCommandImpl(m_context), null);
+
+ // Register "update" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new UpdateCommandImpl(m_context), null);
+
+ // Register "version" command service.
+ context.registerService(
+ org.apache.felix.shell.Command.class.getName(),
+ new VersionCommandImpl(m_context), null);
+ }
+
+ public void stop(BundleContext context)
+ {
+ m_shell.clearCommands();
+ }
+
+ private void initializeCommands()
+ {
+ synchronized (m_shell)
+ {
+ try
+ {
+ ServiceReference[] refs = m_context.getServiceReferences(
+ org.apache.felix.shell.Command.class.getName(), null);
+ if (refs != null)
+ {
+ for (int i = 0; i < refs.length; i++)
+ {
+ m_shell.addCommand(refs[i]);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ System.err.println("Activator: " + ex);
+ }
+ }
+ }
+
+ private class ShellServiceImpl implements
+ org.apache.felix.shell.ShellService,
+ org.ungoverned.osgi.service.shell.ShellService
+ {
+ private HashMap m_commandRefMap = new HashMap();
+ private TreeMap m_commandNameMap = new TreeMap();
+
+ public synchronized String[] getCommands()
+ {
+ Set ks = m_commandNameMap.keySet();
+ String[] cmds = (ks == null)
+ ? new String[0] : (String[]) ks.toArray(new String[ks.size()]);
+ return cmds;
+ }
+
+ public synchronized String getCommandUsage(String name)
+ {
+ Command command = (Command) m_commandNameMap.get(name);
+ return (command == null) ? null : command.getUsage();
+ }
+
+ public synchronized String getCommandDescription(String name)
+ {
+ Command command = (Command) m_commandNameMap.get(name);
+ return (command == null) ? null : command.getShortDescription();
+ }
+
+ public synchronized ServiceReference getCommandReference(String name)
+ {
+ return (ServiceReference) m_commandNameMap.get(name);
+ }
+
+ public synchronized void removeCommand(ServiceReference ref)
+ {
+ Command command = (Command) m_commandRefMap.remove(ref);
+ if (command != null)
+ {
+ m_commandNameMap.remove(command.getName());
+ }
+ }
+
+ public synchronized void executeCommand(
+ String commandLine, PrintStream out, PrintStream err) throws Exception
+ {
+ commandLine = commandLine.trim();
+ String commandName = (commandLine.indexOf(' ') >= 0)
+ ? commandLine.substring(0, commandLine.indexOf(' ')) : commandLine;
+ Command command = getCommand(commandName);
+ if (command != null)
+ {
+ if (System.getSecurityManager() != null)
+ {
+ try
+ {
+ AccessController.doPrivileged(
+ new ExecutePrivileged(command, commandLine, out, err));
+ }
+ catch (PrivilegedActionException ex)
+ {
+ throw ex.getException();
+ }
+ }
+ else
+ {
+ try
+ {
+ command.execute(commandLine, out, err);
+ }
+ catch (Throwable ex)
+ {
+ err.println("Unable to execute command: " + ex);
+ ex.printStackTrace(err);
+ }
+ }
+ }
+ else
+ {
+ err.println("Command not found.");
+ }
+ }
+
+ protected synchronized Command getCommand(String name)
+ {
+ Command command = (Command) m_commandNameMap.get(name);
+ return (command == null) ? null : command;
+ }
+
+ protected synchronized void addCommand(ServiceReference ref)
+ {
+ Object cmdObj = m_context.getService(ref);
+ Command command =
+ (cmdObj instanceof org.ungoverned.osgi.service.shell.Command)
+ ? new OldCommandWrapper((org.ungoverned.osgi.service.shell.Command) cmdObj)
+ : (Command) cmdObj;
+ m_commandRefMap.put(ref, command);
+ m_commandNameMap.put(command.getName(), command);
+ }
+
+ protected synchronized void clearCommands()
+ {
+ m_commandRefMap.clear();
+ m_commandNameMap.clear();
+ }
+ }
+
+ private static class OldCommandWrapper implements Command
+ {
+ private org.ungoverned.osgi.service.shell.Command m_oldCommand = null;
+
+ public OldCommandWrapper(org.ungoverned.osgi.service.shell.Command oldCommand)
+ {
+ m_oldCommand = oldCommand;
+ }
+
+ public String getName()
+ {
+ return m_oldCommand.getName();
+ }
+
+ public String getUsage()
+ {
+ return m_oldCommand.getUsage();
+ }
+
+ public String getShortDescription()
+ {
+ return m_oldCommand.getShortDescription();
+ }
+
+ public void execute(String line, PrintStream out, PrintStream err)
+ {
+ m_oldCommand.execute(line, out, err);
+ }
+ }
+
+ public static class ExecutePrivileged implements PrivilegedExceptionAction
+ {
+ private Command m_command = null;
+ private String m_commandLine = null;
+ private PrintStream m_out = null;
+ private PrintStream m_err = null;
+
+ public ExecutePrivileged(
+ Command command, String commandLine,
+ PrintStream out, PrintStream err)
+ throws Exception
+ {
+ m_command = command;
+ m_commandLine = commandLine;
+ m_out = out;
+ m_err = err;
+ }
+
+ public Object run() throws Exception
+ {
+ m_command.execute(m_commandLine, m_out, m_err);
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/BundleLevelCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/BundleLevelCommandImpl.java
new file mode 100644
index 0000000..a1ad2b4
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/BundleLevelCommandImpl.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+import org.osgi.service.startlevel.StartLevel;
+
+public class BundleLevelCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public BundleLevelCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "bundlelevel";
+ }
+
+ public String getUsage()
+ {
+ return "bundlelevel <level> <id> ... | <id>";
+ }
+
+ public String getShortDescription()
+ {
+ return "set or get bundle start level.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ // Get start level service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.osgi.service.startlevel.StartLevel.class.getName());
+ if (ref == null)
+ {
+ out.println("StartLevel service is unavailable.");
+ return;
+ }
+
+ StartLevel sl = (StartLevel) m_context.getService(ref);
+ if (sl == null)
+ {
+ out.println("StartLevel service is unavailable.");
+ return;
+ }
+
+ // Parse command line.
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // If there is only one token, then assume it is
+ // a bundle ID for which we must retrieve the bundle
+ // level.
+ if (st.countTokens() == 1)
+ {
+ // Get the bundle and display start level.
+ Bundle bundle = null;
+ String token = null;
+ try
+ {
+ token = st.nextToken();
+ long id = Long.parseLong(token);
+ bundle = m_context.getBundle(id);
+ if (bundle != null)
+ {
+ out.println("Bundle " + token + " is level "
+ + sl.getBundleStartLevel(bundle));
+ }
+ else
+ {
+ err.println("Bundle ID " + token + " is invalid.");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse integer '" + token + "'.");
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ // If there is more than one token, assume the first
+ // token is the new start level and the remaining
+ // tokens are the bundle IDs whose start levels should
+ // be changed.
+ else if (st.countTokens() > 1)
+ {
+ // Get the bundle.
+ Bundle bundle = null;
+ String token = null;
+ int startLevel = -1;
+
+ try
+ {
+ token = st.nextToken();
+ startLevel = Integer.parseInt(token);
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse start level '" + token + "'.");
+ }
+
+ // Ignore invalid start levels.
+ if (startLevel > 0)
+ {
+ // Set the start level for each specified bundle.
+ while (st.hasMoreTokens())
+ {
+ try
+ {
+ token = st.nextToken();
+ long id = Long.parseLong(token);
+ bundle = m_context.getBundle(id);
+ if (bundle != null)
+ {
+ sl.setBundleStartLevel(bundle, startLevel);
+ }
+ else
+ {
+ err.println("Bundle ID '" + token + "' is invalid.");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse bundle ID '" + token + "'.");
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ err.println("Invalid start level.");
+ }
+ }
+ else
+ {
+ err.println("Incorrect number of arguments.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/CdCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/CdCommandImpl.java
new file mode 100644
index 0000000..ed05f4d
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/CdCommandImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.CdCommand;
+import org.osgi.framework.BundleContext;
+
+public class CdCommandImpl implements CdCommand
+{
+ private BundleContext m_context = null;
+ private String m_baseURL = "";
+
+ public CdCommandImpl(BundleContext context)
+ {
+ m_context = context;
+
+ // See if the initial base URL is specified.
+ String baseURL = m_context.getProperty(BASE_URL_PROPERTY);
+ setBaseURL(baseURL);
+ }
+
+ public String getName()
+ {
+ return "cd";
+ }
+
+ public String getUsage()
+ {
+ return "cd [<base-URL>]";
+ }
+
+ public String getShortDescription()
+ {
+ return "change or display base URL.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // No more tokens means to display the base URL,
+ // otherwise set the base URL.
+ if (st.countTokens() == 0)
+ {
+ out.println(m_baseURL);
+ }
+ else if (st.countTokens() == 1)
+ {
+ setBaseURL(st.nextToken());
+ }
+ else
+ {
+ err.println("Incorrect number of arguments");
+ }
+ }
+
+ public String getBaseURL()
+ {
+ return m_baseURL;
+ }
+
+ public void setBaseURL(String s)
+ {
+ m_baseURL = (s == null) ? "" : s;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/HeadersCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/HeadersCommandImpl.java
new file mode 100644
index 0000000..3c4ee0b
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/HeadersCommandImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.*;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class HeadersCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public HeadersCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "headers";
+ }
+
+ public String getUsage()
+ {
+ return "headers [<id> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "display bundle header properties.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // Print the specified bundles or all if none are specified.
+ if (st.hasMoreTokens())
+ {
+ while (st.hasMoreTokens())
+ {
+ String id = st.nextToken().trim();
+
+ try
+ {
+ long l = Long.parseLong(id);
+ Bundle bundle = m_context.getBundle(l);
+ if (bundle != null)
+ {
+ printHeaders(out, bundle);
+ }
+ else
+ {
+ err.println("Bundle ID " + id + " is invalid.");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse id '" + id + "'.");
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ Bundle[] bundles = m_context.getBundles();
+ for (int i = 0; i < bundles.length; i++)
+ {
+ printHeaders(out, bundles[i]);
+ }
+ }
+ }
+
+ private void printHeaders(PrintStream out, Bundle bundle)
+ {
+ String title = Util.getBundleName(bundle);
+ out.println("\n" + title);
+ 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);
+ out.println(k + " = " + Util.getValueString(v));
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/HelpCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/HelpCommandImpl.java
new file mode 100644
index 0000000..54b8601
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/HelpCommandImpl.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+
+import org.apache.felix.shell.Command;
+import org.apache.felix.shell.ShellService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class HelpCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public HelpCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "help";
+ }
+
+ public String getUsage()
+ {
+ return "help";
+ }
+
+ public String getShortDescription()
+ {
+ return "display impl commands.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ try {
+ // Get a reference to the impl service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.apache.felix.shell.ShellService.class.getName());
+
+ if (ref != null)
+ {
+ ShellService ss = (ShellService) m_context.getService(ref);
+ String[] cmds = ss.getCommands();
+ String[] usage = new String[cmds.length];
+ String[] desc = new String[cmds.length];
+ int maxUsage = 0;
+ for (int i = 0; i < cmds.length; i++)
+ {
+ usage[i] = ss.getCommandUsage(cmds[i]);
+ desc[i] = ss.getCommandDescription(cmds[i]);
+ // Just in case the command has gone away.
+ if ((usage[i] != null) && (desc[i] != null))
+ {
+ maxUsage = Math.max(maxUsage, usage[i].length());
+ }
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < cmds.length; i++)
+ {
+ // Just in case the command has gone away.
+ if ((usage[i] != null) && (desc[i] != null))
+ {
+ sb.delete(0, sb.length());
+ for (int j = 0; j < (maxUsage - usage[i].length()); j++)
+ {
+ sb.append(' ');
+ }
+ out.println(usage[i] + sb + " - " + desc[i]);
+ }
+ }
+ }
+ else
+ {
+ err.println("No ShellService is unavailable.");
+ }
+ } catch (Exception ex) {
+ err.println(ex.toString());
+ }
+ }
+}
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/InstallCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/InstallCommandImpl.java
new file mode 100644
index 0000000..0275bca
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/InstallCommandImpl.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.net.URL;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.CdCommand;
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class InstallCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public InstallCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "install";
+ }
+
+ public String getUsage()
+ {
+ return "install <URL> [<URL> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "install bundle(s).";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // There should be at least one URL.
+ if (st.countTokens() >= 1)
+ {
+ while (st.hasMoreTokens())
+ {
+ String location = st.nextToken().trim();
+ install(location, out, err);
+ }
+ }
+ else
+ {
+ err.println("Incorrect number of arguments");
+ }
+ }
+
+ protected Bundle install(String location, PrintStream out, PrintStream err)
+ {
+ String abs = absoluteLocation(location);
+ if (abs == null)
+ {
+ err.println("Malformed location: " + location);
+ }
+ else
+ {
+ try
+ {
+ return m_context.installBundle(abs, null);
+ }
+ catch (IllegalStateException ex)
+ {
+ err.println(ex.toString());
+ }
+ catch (BundleException ex)
+ {
+ if (ex.getNestedException() != null)
+ {
+ err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ err.println(ex.toString());
+ }
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ return null;
+ }
+
+ private String absoluteLocation(String location)
+ {
+ String guess = location;
+ // If the location does not contain a ":", then try to
+ // add the base URL from the 'cd' command service.
+ if (location.indexOf(':') < 0)
+ {
+ // Try to create a valid URL using the base URL
+ // contained in the "cd" command service.
+ String baseURL = "";
+
+ try
+ {
+ // Get a reference to the "cd" command service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.apache.felix.shell.CdCommand.class.getName());
+
+ if (ref != null)
+ {
+ CdCommand cd = (CdCommand) m_context.getService(ref);
+ baseURL = cd.getBaseURL();
+ baseURL = (baseURL == null) ? "" : baseURL;
+ m_context.ungetService(ref);
+ }
+
+ String theURL = baseURL + guess;
+ new URL(theURL);
+ }
+ catch (Exception ex2)
+ {
+ // If that fails, then just return the original.
+ return location;
+ }
+ guess = baseURL + guess;
+ }
+ return guess;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/PackagesCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/PackagesCommandImpl.java
new file mode 100644
index 0000000..b88ec41
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/PackagesCommandImpl.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class PackagesCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public PackagesCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "packages";
+ }
+
+ public String getUsage()
+ {
+ return "packages [<id> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "list exported packages.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ // Get package admin service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.osgi.service.packageadmin.PackageAdmin.class.getName());
+ if (ref == null)
+ {
+ out.println("PackageAdmin service is unavailable.");
+ return;
+ }
+
+ PackageAdmin pa = (PackageAdmin) m_context.getService(ref);
+ if (pa == null)
+ {
+ out.println("PackageAdmin service is unavailable.");
+ return;
+ }
+
+ // Parse command line.
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ if (st.hasMoreTokens())
+ {
+ while (st.hasMoreTokens())
+ {
+ String id = st.nextToken();
+ try
+ {
+ long l = Long.parseLong(id);
+ Bundle bundle = m_context.getBundle(l);
+ ExportedPackage[] exports = pa.getExportedPackages(bundle);
+ printExports(out, bundle, exports);
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse id '" + id + "'.");
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ ExportedPackage[] exports = pa.getExportedPackages((Bundle) null);
+ printExports(out, null, exports);
+ }
+ }
+
+ private void printExports(PrintStream out, Bundle target, ExportedPackage[] exports)
+ {
+ if ((exports != null) && (exports.length > 0))
+ {
+ for (int i = 0; i < exports.length; i++)
+ {
+ Bundle bundle = exports[i].getExportingBundle();
+ out.print(Util.getBundleName(bundle));
+ out.println(": " + exports[i]);
+ }
+ }
+ else
+ {
+ out.println(Util.getBundleName(target)
+ + ": No active exported packages.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/PsCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/PsCommandImpl.java
new file mode 100644
index 0000000..303f831
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/PsCommandImpl.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.Dictionary;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+import org.osgi.service.startlevel.StartLevel;
+
+public class PsCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public PsCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "ps";
+ }
+
+ public String getUsage()
+ {
+ return "ps [-l | -u]";
+ }
+
+ public String getShortDescription()
+ {
+ return "list installed bundles.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ // Get start level service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.osgi.service.startlevel.StartLevel.class.getName());
+ StartLevel sl = null;
+ if (ref != null)
+ {
+ sl = (StartLevel) m_context.getService(ref);
+ }
+
+ if (sl == null)
+ {
+ out.println("StartLevel service is unavailable.");
+ }
+
+ // Parse command line.
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // Check for optional argument.
+ boolean showLoc = false;
+ boolean showUpdate = false;
+ if (st.countTokens() >= 1)
+ {
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken().trim();
+ if (token.equals("-l"))
+ {
+ showLoc = true;
+ }
+ else if (token.equals("-u"))
+ {
+ showUpdate = true;
+ }
+ }
+ }
+ Bundle[] bundles = m_context.getBundles();
+ if (bundles != null)
+ {
+ // Display active start level.
+ if (sl != null)
+ {
+ out.println("START LEVEL " + sl.getStartLevel());
+ }
+
+ // Print column headers.
+ String msg = " Name";
+ if (showLoc)
+ {
+ msg = " Location";
+ }
+ else if (showUpdate)
+ {
+ msg = " Update location";
+ }
+ String level = (sl == 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 (showLoc)
+ {
+ name = bundles[i].getLocation();
+ }
+ else if (showUpdate)
+ {
+ Dictionary dict = bundles[i].getHeaders();
+ name = (String) dict.get(Constants.BUNDLE_UPDATELOCATION);
+ if (name == null)
+ {
+ name = bundles[i].getLocation();
+ }
+ }
+ // 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 (sl == null)
+ {
+ level = "1";
+ }
+ else
+ {
+ level = String.valueOf(sl.getBundleStartLevel(bundles[i]));
+ }
+ while (level.length() < 5)
+ {
+ level = " " + level;
+ }
+ while (id.length() < 4)
+ {
+ id = " " + id;
+ }
+ out.println("[" + id + "] ["
+ + getStateString(bundles[i].getState())
+ + "] [" + level + "] " + name);
+ }
+ }
+ else
+ {
+ out.println("There are no installed bundles.");
+ }
+ }
+
+ public String getStateString(int i)
+ {
+ if (i == Bundle.ACTIVE)
+ return "Active ";
+ else if (i == Bundle.INSTALLED)
+ return "Installed ";
+ else if (i == Bundle.RESOLVED)
+ return "Resolved ";
+ else if (i == Bundle.STARTING)
+ return "Starting ";
+ else if (i == Bundle.STOPPING)
+ return "Stopping ";
+ return "Unknown ";
+ }
+}
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/RefreshCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/RefreshCommandImpl.java
new file mode 100644
index 0000000..4cff498
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/RefreshCommandImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class RefreshCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public RefreshCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "refresh";
+ }
+
+ public String getUsage()
+ {
+ return "refresh";
+ }
+
+ public String getShortDescription()
+ {
+ return "refresh packages.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ // Get package admin service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.osgi.service.packageadmin.PackageAdmin.class.getName());
+ if (ref == null)
+ {
+ out.println("PackageAdmin service is unavailable.");
+ return;
+ }
+
+ PackageAdmin pa = (PackageAdmin) m_context.getService(ref);
+ if (pa == null)
+ {
+ out.println("PackageAdmin service is unavailable.");
+ return;
+ }
+
+ pa.refreshPackages(null);
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/ServicesCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/ServicesCommandImpl.java
new file mode 100644
index 0000000..c1bb3a4
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/ServicesCommandImpl.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.*;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class ServicesCommandImpl implements Command
+{
+ private static final String IN_USE_SWITCH = "-u";
+ private static final String SHOW_ALL_SWITCH = "-a";
+
+ private BundleContext m_context = null;
+
+ public ServicesCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "services";
+ }
+
+ public String getUsage()
+ {
+ return "services [-u] [-a] [<id> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "list registered or used services.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // Put the remaining tokens into a list.
+ List tokens = new ArrayList();
+ for (int i = 0; st.hasMoreTokens(); i++)
+ {
+ tokens.add(st.nextToken());
+ }
+
+ // Default switch values.
+ boolean inUse = false;
+ boolean showAll = false;
+
+ // Check for "in use" switch.
+ if (tokens.contains(IN_USE_SWITCH))
+ {
+ // Remove the switch and set boolean flag.
+ tokens.remove(IN_USE_SWITCH);
+ inUse = true;
+ }
+
+ // Check for "show all" switch.
+ if (tokens.contains(SHOW_ALL_SWITCH))
+ {
+ // Remove the switch and set boolean flag.
+ tokens.remove(SHOW_ALL_SWITCH);
+ showAll = true;
+ }
+
+ // If there are bundle IDs specified then print their
+ // services and associated service properties, otherwise
+ // list all bundles and services.
+ if (tokens.size() >= 1)
+ {
+ while (tokens.size() > 0)
+ {
+ String id = (String) tokens.remove(0);
+
+ boolean headerPrinted = false;
+ boolean needSeparator = false;
+
+ try
+ {
+ long l = Long.parseLong(id);
+ Bundle bundle = m_context.getBundle(l);
+ if (bundle != null)
+ {
+ ServiceReference[] refs = null;
+
+ // Get registered or in-use services.
+ if (inUse)
+ {
+ refs = bundle.getServicesInUse();
+ }
+ else
+ {
+ refs = bundle.getRegisteredServices();
+ }
+
+ // Print properties for each service.
+ for (int refIdx = 0;
+ (refs != null) && (refIdx < refs.length);
+ refIdx++)
+ {
+ String[] objectClass = (String[])
+ refs[refIdx].getProperty("objectClass");
+
+ // Determine if we need to print the service, depending
+ // on whether it is a command service or not.
+ boolean print = true;
+ for (int ocIdx = 0;
+ !showAll && (ocIdx < objectClass.length);
+ ocIdx++)
+ {
+ if (objectClass[ocIdx].equals(
+ org.apache.felix.shell.Command.class.getName()))
+ {
+ print = false;
+ }
+ }
+
+ // Print header if we have not already done so.
+ if (!headerPrinted)
+ {
+ headerPrinted = true;
+ String title = Util.getBundleName(bundle);
+ title = (inUse)
+ ? title + " uses:"
+ : title + " provides:";
+ out.println("");
+ out.println(title);
+ out.println(Util.getUnderlineString(title));
+ }
+
+ if (showAll || print)
+ {
+ // Print service separator if necessary.
+ if (needSeparator)
+ {
+ out.println("----");
+ }
+
+ // Print service properties.
+ String[] keys = refs[refIdx].getPropertyKeys();
+ for (int keyIdx = 0;
+ (keys != null) && (keyIdx < keys.length);
+ keyIdx++)
+ {
+ Object v = refs[refIdx].getProperty(keys[keyIdx]);
+ out.println(
+ keys[keyIdx] + " = " + Util.getValueString(v));
+ }
+
+ needSeparator = true;
+ }
+ }
+ }
+ else
+ {
+ err.println("Bundle ID " + id + " is invalid.");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse id '" + id + "'.");
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ Bundle[] bundles = m_context.getBundles();
+ if (bundles != null)
+ {
+ // TODO: Sort list.
+ for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+ {
+ boolean headerPrinted = false;
+ ServiceReference[] refs = null;
+
+ // Get registered or in-use services.
+ if (inUse)
+ {
+ refs = bundles[bundleIdx].getServicesInUse();
+ }
+ else
+ {
+ refs = bundles[bundleIdx].getRegisteredServices();
+ }
+
+ for (int refIdx = 0; (refs != null) && (refIdx < refs.length); refIdx++)
+ {
+ String[] objectClass = (String[])
+ refs[refIdx].getProperty("objectClass");
+
+ // Determine if we need to print the service, depending
+ // on whether it is a command service or not.
+ boolean print = true;
+ for (int ocIdx = 0;
+ !showAll && (ocIdx < objectClass.length);
+ ocIdx++)
+ {
+ if (objectClass[ocIdx].equals(
+ org.apache.felix.shell.Command.class.getName()))
+ {
+ print = false;
+ }
+ }
+
+ // Print the service if necessary.
+ if (showAll || print)
+ {
+ if (!headerPrinted)
+ {
+ headerPrinted = true;
+ String title = Util.getBundleName(bundles[bundleIdx]);
+ title = (inUse)
+ ? title + " uses:"
+ : title + " provides:";
+ out.println("\n" + title);
+ out.println(Util.getUnderlineString(title));
+ }
+ out.println(Util.getValueString(objectClass));
+ }
+ }
+ }
+ }
+ else
+ {
+ out.println("There are no registered services.");
+ }
+ }
+ }
+}
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/ShutdownCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/ShutdownCommandImpl.java
new file mode 100644
index 0000000..0555ff4
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/ShutdownCommandImpl.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class ShutdownCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public ShutdownCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "shutdown";
+ }
+
+ public String getUsage()
+ {
+ return "shutdown";
+ }
+
+ public String getShortDescription()
+ {
+ return "shutdown framework.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ // Get system bundle and use it to shutdown Felix.
+ try
+ {
+ Bundle bundle = m_context.getBundle(0);
+ bundle.stop();
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StartCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StartCommandImpl.java
new file mode 100644
index 0000000..3efe6b1
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StartCommandImpl.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class StartCommandImpl extends InstallCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public StartCommandImpl(BundleContext context)
+ {
+ super(context);
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "start";
+ }
+
+ public String getUsage()
+ {
+ return "start <id> [<id> <URL> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "start bundle(s).";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // There should be at least one bundle id.
+ if (st.countTokens() >= 1)
+ {
+ while (st.hasMoreTokens())
+ {
+ String id = st.nextToken().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_context.getBundle(l);
+ }
+ else
+ {
+ bundle = install(id, out, err);
+ }
+
+ if (bundle != null)
+ {
+ bundle.start();
+ }
+ else
+ {
+ err.println("Bundle ID " + id + " is invalid.");
+ }
+ } catch (NumberFormatException ex) {
+ err.println("Unable to parse id '" + id + "'.");
+ } catch (BundleException ex) {
+ if (ex.getNestedException() != null)
+ {
+ ex.printStackTrace();
+ err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ err.println(ex.toString());
+ }
+ } catch (Exception ex) {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ err.println("Incorrect number of arguments");
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StartLevelCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StartLevelCommandImpl.java
new file mode 100644
index 0000000..12c440a
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StartLevelCommandImpl.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.startlevel.StartLevel;
+
+public class StartLevelCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public StartLevelCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "startlevel";
+ }
+
+ public String getUsage()
+ {
+ return "startlevel [<level>]";
+ }
+
+ public String getShortDescription()
+ {
+ return "get or set framework start level.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ // Get start level service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.osgi.service.startlevel.StartLevel.class.getName());
+ if (ref == null)
+ {
+ out.println("StartLevel service is unavailable.");
+ return;
+ }
+
+ StartLevel sl = (StartLevel) m_context.getService(ref);
+ if (sl == null)
+ {
+ out.println("StartLevel service is unavailable.");
+ return;
+ }
+
+ // Parse command line.
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ if (st.countTokens() == 0)
+ {
+ out.println("Level " + sl.getStartLevel());
+ }
+ else if (st.countTokens() >= 1)
+ {
+ String levelStr = st.nextToken().trim();
+
+ try {
+ int level = Integer.parseInt(levelStr);
+ sl.setStartLevel(level);
+ } catch (NumberFormatException ex) {
+ err.println("Unable to parse integer '" + levelStr + "'.");
+ } catch (Exception ex) {
+ err.println(ex.toString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StopCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StopCommandImpl.java
new file mode 100644
index 0000000..5ff0f40
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/StopCommandImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class StopCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public StopCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "stop";
+ }
+
+ public String getUsage()
+ {
+ return "stop <id> [<id> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "stop bundle(s).";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // There should be at least one bundle id.
+ if (st.countTokens() >= 1)
+ {
+ while (st.hasMoreTokens())
+ {
+ String id = st.nextToken().trim();
+
+ try {
+ long l = Long.parseLong(id);
+ Bundle bundle = m_context.getBundle(l);
+ if (bundle != null)
+ {
+ bundle.stop();
+ }
+ else
+ {
+ err.println("Bundle ID " + id + " is invalid.");
+ }
+ } catch (NumberFormatException ex) {
+ err.println("Unable to parse id '" + id + "'.");
+ } catch (BundleException ex) {
+ if (ex.getNestedException() != null)
+ err.println(ex.getNestedException().toString());
+ else
+ err.println(ex.toString());
+ } catch (Exception ex) {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ err.println("Incorrect number of arguments");
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/UninstallCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/UninstallCommandImpl.java
new file mode 100644
index 0000000..c0b7b4d
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/UninstallCommandImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class UninstallCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public UninstallCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "uninstall";
+ }
+
+ public String getUsage()
+ {
+ return "uninstall <id> [<id> ...]";
+ }
+
+ public String getShortDescription()
+ {
+ return "uninstall bundle(s).";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // There must be at least one bundle ID.
+ if (st.countTokens() >= 1)
+ {
+ while (st.hasMoreTokens())
+ {
+ String id = st.nextToken().trim();
+
+ try {
+ long l = Long.parseLong(id);
+ Bundle bundle = m_context.getBundle(l);
+ if (bundle != null)
+ {
+ bundle.uninstall();
+ }
+ else
+ {
+ err.println("Bundle ID " + id + " is invalid.");
+ }
+ } catch (NumberFormatException ex) {
+ err.println("Unable to parse id '" + id + "'.");
+ } catch (BundleException ex) {
+ if (ex.getNestedException() != null)
+ err.println(ex.getNestedException().toString());
+ else
+ err.println(ex.toString());
+ } catch (Exception ex) {
+ err.println(ex.toString());
+ }
+ }
+ }
+ else
+ {
+ err.println("Incorrect number of arguments");
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/UpdateCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/UpdateCommandImpl.java
new file mode 100644
index 0000000..167397c
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/UpdateCommandImpl.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.CdCommand;
+import org.apache.felix.shell.Command;
+import org.osgi.framework.*;
+
+public class UpdateCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public UpdateCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "update";
+ }
+
+ public String getUsage()
+ {
+ return "update <id> [<URL>]";
+ }
+
+ public String getShortDescription()
+ {
+ return "update bundle.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ");
+
+ // Ignore the command name.
+ st.nextToken();
+
+ // There should be at least a bundle ID, but there may
+ // also be a URL.
+ if ((st.countTokens() == 1) || (st.countTokens() == 2))
+ {
+ String id = st.nextToken().trim();
+ String location = st.countTokens() == 0 ? null : st.nextToken().trim();
+
+ if (location != null)
+ {
+ location = absoluteLocation(location);
+
+ if (location == null)
+ {
+ err.println("Malformed location: " + location);
+ }
+ }
+
+ try
+ {
+ // Get the bundle id.
+ long l = Long.parseLong(id);
+
+ // Get the bundle.
+ Bundle bundle = m_context.getBundle(l);
+ if (bundle != null)
+ {
+ // Create input stream from location if present
+ // and use it to update, otherwise just update.
+ if (location != null)
+ {
+ InputStream is = new URL(location).openStream();
+ bundle.update(is);
+ }
+ else
+ {
+ bundle.update();
+ }
+ }
+ else
+ {
+ err.println("Bundle ID " + id + " is invalid.");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ err.println("Unable to parse id '" + id + "'.");
+ }
+ catch (MalformedURLException ex)
+ {
+ err.println("Unable to parse URL.");
+ }
+ catch (IOException ex)
+ {
+ err.println("Unable to open input stream: " + ex);
+ }
+ catch (BundleException ex)
+ {
+ if (ex.getNestedException() != null)
+ {
+ err.println(ex.getNestedException().toString());
+ }
+ else
+ {
+ err.println(ex.toString());
+ }
+ }
+ catch (Exception ex)
+ {
+ err.println(ex.toString());
+ }
+ }
+ else
+ {
+ err.println("Incorrect number of arguments");
+ }
+ }
+
+ private String absoluteLocation(String location)
+ {
+ if (!location.endsWith(".jar"))
+ {
+ location = location + ".jar";
+ }
+ try
+ {
+ new URL(location);
+ }
+ catch (MalformedURLException ex)
+ {
+ // Try to create a valid URL using the base URL
+ // contained in the "cd" command service.
+ String baseURL = "";
+
+ try
+ {
+ // Get a reference to the "cd" command service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.apache.felix.shell.CdCommand.class.getName());
+
+ if (ref != null)
+ {
+ CdCommand cd = (CdCommand) m_context.getService(ref);
+ baseURL = cd.getBaseURL();
+ baseURL = (baseURL == null) ? "" : baseURL;
+ m_context.ungetService(ref);
+ }
+
+ String theURL = baseURL + location;
+ new URL(theURL);
+
+ }
+ catch (Exception ex2)
+ {
+ return null;
+ }
+ location = baseURL + location;
+ }
+ return location;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/Util.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/Util.java
new file mode 100644
index 0000000..77a46a3
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/Util.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+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 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();
+ }
+
+ return "<unknown value type>";
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/VersionCommandImpl.java b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/VersionCommandImpl.java
new file mode 100644
index 0000000..a952bb3
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/apache/felix/shell/impl/VersionCommandImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.shell.impl;
+
+import java.io.PrintStream;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.BundleContext;
+
+public class VersionCommandImpl implements Command
+{
+ private BundleContext m_context = null;
+
+ public VersionCommandImpl(BundleContext context)
+ {
+ m_context = context;
+ }
+
+ public String getName()
+ {
+ return "version";
+ }
+
+ public String getUsage()
+ {
+ return "version";
+ }
+
+ public String getShortDescription()
+ {
+ return "display version of framework.";
+ }
+
+ public void execute(String s, PrintStream out, PrintStream err)
+ {
+ out.println(m_context.getProperty("felix.version"));
+ }
+}
diff --git a/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/CdCommand.java b/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/CdCommand.java
new file mode 100644
index 0000000..98bc27e
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/CdCommand.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.ungoverned.osgi.service.shell;
+
+/**
+ * This interface defines the <tt>cd</tt> command service interface for the
+ * Felix impl service. The <tt>cd</tt> command does not really change the
+ * directory of the impl, rather it maintains a base URL for
+ * simplifying URL entry.
+ * <p>
+ * For example, if the base URL is <tt>http://www.foo.com/<tt> and you
+ * try to install a bundle <tt>foo.jar</tt>, the actual URL will be
+ * expanded to <tt>http://www.foo.com/foo.jar</tt>. Any bundles wishing
+ * to retrieve or set the current directory of the impl can use this
+ * service interface.
+**/
+public interface CdCommand extends Command
+{
+ /**
+ * Property used to configure the base URL.
+ **/
+ public static final String BASE_URL_PROPERTY = "felix.impl.baseurl";
+
+ /**
+ * Returns the current <i>directory</i> of the impl service.
+ * @return the current impl directory.
+ **/
+ public String getBaseURL();
+
+ /**
+ * Sets the current <i>directory</i> of the impl service.
+ * @param s the new value for the base URL.
+ **/
+ public void setBaseURL(String s);
+}
diff --git a/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/Command.java b/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/Command.java
new file mode 100644
index 0000000..c3a8363
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/Command.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.ungoverned.osgi.service.shell;
+
+import java.io.PrintStream;
+
+/**
+ * This interface is used to define commands for the Felix impl
+ * service. Any bundle wishing to create commands for the
+ * impl service simply needs to create a service object that
+ * implements this interface and then register it with the OSGi
+ * framework. The impl service automatically includes any
+ * registered command services in its list of available commands.
+**/
+public interface Command
+{
+ /**
+ * Returns the name of the command that is implemented by the
+ * interface. The command name should not contain whitespace
+ * and should also be unique.
+ * @return the name of the command.
+ **/
+ public String getName();
+
+ /**
+ * Returns the usage string for the command. The usage string is
+ * a short string that illustrates how to use the command on the
+ * command line. This information is used when generating command
+ * help information. An example usage string for the <tt>install</tt>
+ * command is:
+ * <pre>
+ * install <URL> [<URL> ...]
+ * </pre>
+ * @return the usage string for the command.
+ **/
+ public String getUsage();
+
+ /**
+ * Returns a short description of the command; this description
+ * should be as short as possible. This information is used when
+ * generating the command help information.
+ * @return a short description of the command.
+ **/
+ public String getShortDescription();
+
+ /**
+ * Executes the command using the supplied command line, output
+ * print stream, and error print stream.
+ * @param line the complete command line, including the command name.
+ * @param out the print stream to use for standard output.
+ * @param err the print stream to use for standard error.
+ **/
+ public void execute(String line, PrintStream out, PrintStream err);
+}
diff --git a/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/ShellService.java b/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/ShellService.java
new file mode 100644
index 0000000..8ba31f3
--- /dev/null
+++ b/org.apache.felix.shell/src/main/java/org/ungoverned/osgi/service/shell/ShellService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.ungoverned.osgi.service.shell;
+
+import java.io.PrintStream;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This interface defines the Felix impl service. The impl service
+ * is an extensible, user interface neutral impl for controlling and
+ * interacting with the framework. In general, the impl service assumes that
+ * it is operating in a command line fashion, i.e., it receives a
+ * complete command line, parses it, and executes the corresponding
+ * command, but graphical interfaces are also possible.
+ * <p>
+ * All commands in the impl service are actually implemented as OSGi
+ * services; these services implement the <tt>Command</tt> service
+ * interface. Any bundle can implement custom commands by creating
+ * command services and registering them with the OSGi framework.
+**/
+public interface ShellService
+{
+ /**
+ * Returns an array of command names available in the impl service.
+ * @return an array of available command names or an empty array.
+ **/
+ public String[] getCommands();
+
+ /**
+ * Returns the usage string associated with the specified command name.
+ * @param name the name of the target command.
+ * @return the usage string of the specified command or null.
+ **/
+ public String getCommandUsage(String name);
+
+ /**
+ * Returns the description associated with the specified command name.
+ * @param name the name of the target command.
+ * @return the description of the specified command or null.
+ **/
+ public String getCommandDescription(String name);
+
+ /**
+ * Returns the service reference associated with the specified
+ * command name.
+ * @param name the name of the target command.
+ * @return the description of the specified command or null.
+ **/
+ public ServiceReference getCommandReference(String name);
+
+ /**
+ *
+ * This method executes the supplied command line using the
+ * supplied output and error print stream. The assumption of
+ * this method is that a command line will be typed by the user
+ * (or perhaps constructed by a GUI) and passed into it for
+ * execution. The command line is interpretted in a very
+ * simplistic fashion; it takes the leading string of characters
+ * terminated by a space character (not including it) and
+ * assumes that this leading token is the command name. For an
+ * example, consider the following command line:
+ * </p>
+ * <pre>
+ * update 3 http://www.foo.com/bar.jar
+ * </pre>
+ * <p>
+ * This is interpretted as an <tt>update</tt> command; as a
+ * result, the entire command line (include command name) is
+ * passed into the <tt>execute()</tt> method of the command
+ * service with the name <tt>update</tt> if one exists. If the
+ * corresponding command service is not found, then an error
+ * message is printed to the error print stream.
+ * @param commandLine the command line to execute.
+ * @param out the standard output print stream.
+ * @param err the standard error print stream.
+ **/
+ public void executeCommand(
+ String commandLine, PrintStream out, PrintStream err)
+ throws Exception;
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell/src/main/resources/Manifest.mf b/org.apache.felix.shell/src/main/resources/Manifest.mf
new file mode 100644
index 0000000..e97c4a6
--- /dev/null
+++ b/org.apache.felix.shell/src/main/resources/Manifest.mf
@@ -0,0 +1,20 @@
+Bundle-Name: ShellService
+Bundle-SymbolicName: org.apache.felix.shell.impl
+Bundle-Description: A simple command shell service for Felix (or any other OSGi framework).
+Bundle-DocURL: http://oscar-osgi.sf.net/obr2/shell/
+Bundle-Source: http://oscar-osgi.sf.net/obr2/shell/org.apache.felix.shell.impl-src.jar
+Bundle-Version: 1.0.3
+Bundle-Activator: org.apache.felix.shell.impl.Activator
+Bundle-ClassPath: .
+Import-Package:
+ org.osgi.framework,
+ org.osgi.service.startlevel,
+ org.osgi.service.packageadmin
+Export-Package:
+ org.apache.felix.shell; specification-version="1.0.0",
+ org.ungoverned.osgi.service.shell; specification-version="1.0.0"
+Export-Service: org.apache.felix.shell.ShellService,
+ org.ungoverned.osgi.service.shell.ShellService
+Import-Service: org.osgi.service.startlevel.StartLevel,
+ org.osgi.service.packageadmin.PackageAdmin
+