Implement "requires" and "requirers" commands. (FELIX-1009)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@759431 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/shell/src/main/java/org/apache/felix/shell/impl/Activator.java b/shell/src/main/java/org/apache/felix/shell/impl/Activator.java
index 3e52769..eb83ff6 100644
--- a/shell/src/main/java/org/apache/felix/shell/impl/Activator.java
+++ b/shell/src/main/java/org/apache/felix/shell/impl/Activator.java
@@ -80,7 +80,7 @@
         // been registered (i.e., we didn't see their service events).
         initializeCommands();
 
-        // Register "exports" command service.
+        // Register "bundlelevel" command service.
         context.registerService(
             org.apache.felix.shell.Command.class.getName(),
             new BundleLevelCommandImpl(m_context), null);
@@ -127,6 +127,16 @@
             org.apache.felix.shell.Command.class.getName(),
             new RefreshCommandImpl(m_context), null);
 
+        // Register "requires" command service.
+        context.registerService(
+            org.apache.felix.shell.Command.class.getName(),
+            new RequiresCommandImpl(m_context), null);
+
+        // Register "requirers" command service.
+        context.registerService(
+            org.apache.felix.shell.Command.class.getName(),
+            new RequirersCommandImpl(m_context), null);
+
         // Register "resolve" command service.
         context.registerService(
             org.apache.felix.shell.Command.class.getName(),
diff --git a/shell/src/main/java/org/apache/felix/shell/impl/ExportsCommandImpl.java b/shell/src/main/java/org/apache/felix/shell/impl/ExportsCommandImpl.java
index 3636c99..8db20eb 100644
--- a/shell/src/main/java/org/apache/felix/shell/impl/ExportsCommandImpl.java
+++ b/shell/src/main/java/org/apache/felix/shell/impl/ExportsCommandImpl.java
@@ -55,13 +55,7 @@
         // 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);
+        PackageAdmin pa = (ref == null) ? null : (PackageAdmin) m_context.getService(ref);
         if (pa == null)
         {
             out.println("PackageAdmin service is unavailable.");
diff --git a/shell/src/main/java/org/apache/felix/shell/impl/ImportsCommandImpl.java b/shell/src/main/java/org/apache/felix/shell/impl/ImportsCommandImpl.java
index 7be2f29..47e4b38 100644
--- a/shell/src/main/java/org/apache/felix/shell/impl/ImportsCommandImpl.java
+++ b/shell/src/main/java/org/apache/felix/shell/impl/ImportsCommandImpl.java
@@ -19,8 +19,6 @@
 package org.apache.felix.shell.impl;
 
 import java.io.PrintStream;
-import java.util.List;
-import java.util.ArrayList;
 import java.util.StringTokenizer;
 
 import org.apache.felix.shell.Command;
diff --git a/shell/src/main/java/org/apache/felix/shell/impl/RequirersCommandImpl.java b/shell/src/main/java/org/apache/felix/shell/impl/RequirersCommandImpl.java
new file mode 100644
index 0000000..42107ff
--- /dev/null
+++ b/shell/src/main/java/org/apache/felix/shell/impl/RequirersCommandImpl.java
@@ -0,0 +1,124 @@
+/* 
+ * 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.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.PackageAdmin;
+import org.osgi.service.packageadmin.RequiredBundle;
+
+public class RequirersCommandImpl implements Command
+{
+    private BundleContext m_context = null;
+
+    public RequirersCommandImpl(BundleContext context)
+    {
+        m_context = context;
+    }
+
+    public String getName()
+    {
+        return "requirers";
+    }
+
+    public String getUsage()
+    {
+        return "requirers <id> ...";
+    }
+
+    public String getShortDescription()
+    {
+        return "list requiring bundles.";
+    }
+
+    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());
+        PackageAdmin pa = (ref == null) ? null : (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())
+        {
+            boolean separatorNeeded = false;
+            while (st.hasMoreTokens())
+            {
+                String id = st.nextToken();
+                try
+                {
+                    long l = Long.parseLong(id);
+                    Bundle bundle = m_context.getBundle(l);
+                    RequiredBundle[] rbs = pa.getRequiredBundles(bundle.getSymbolicName());
+                    for (int i = 0; (rbs != null) && (i < rbs.length); i++)
+                    {
+                        if (rbs[i].getBundle() == bundle)
+                        {
+                            if (separatorNeeded)
+                            {
+                                out.println("");
+                            }
+                            printRequiredBundles(out, bundle, rbs[i].getRequiringBundles());
+                            separatorNeeded = true;
+                        }
+                    }
+                }
+                catch (NumberFormatException ex)
+                {
+                    err.println("Unable to parse id '" + id + "'.");
+                }
+                catch (Exception ex)
+                {
+                    err.println(ex.toString());
+                }
+            }
+        }
+    }
+
+    private void printRequiredBundles(PrintStream out, Bundle target, Bundle[] requirers)
+    {
+        String title = target + " required by:";
+        out.println(title);
+        out.println(Util.getUnderlineString(title));
+        if ((requirers != null) && (requirers.length > 0))
+        {
+            for (int i = 0; i < requirers.length; i++)
+            {
+                out.println(requirers[i]);
+            }
+        }
+        else
+        {
+            out.println("Nothing");
+        }
+    }
+}
\ No newline at end of file
diff --git a/shell/src/main/java/org/apache/felix/shell/impl/RequiresCommandImpl.java b/shell/src/main/java/org/apache/felix/shell/impl/RequiresCommandImpl.java
new file mode 100644
index 0000000..c5b3c57
--- /dev/null
+++ b/shell/src/main/java/org/apache/felix/shell/impl/RequiresCommandImpl.java
@@ -0,0 +1,151 @@
+/* 
+ * 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.shell.impl;
+
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.felix.shell.Command;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.packageadmin.RequiredBundle;
+
+public class RequiresCommandImpl implements Command
+{
+    private final BundleContext m_context;
+    private ServiceReference m_ref = null;
+
+    public RequiresCommandImpl(BundleContext context)
+    {
+        m_context = context;
+    }
+
+    public String getName()
+    {
+        return "requires";
+    }
+
+    public String getUsage()
+    {
+        return "requires <id> ...";
+    }
+
+    public String getShortDescription()
+    {
+        return "list required bundles.";
+    }
+
+    public void execute(String s, PrintStream out, PrintStream err)
+    {
+        StringTokenizer st = new StringTokenizer(s, " ");
+
+        // Ignore the command name.
+        st.nextToken();
+
+        if (st.hasMoreTokens())
+        {
+            boolean separatorNeeded = false;
+            while (st.hasMoreTokens())
+            {
+                String id = st.nextToken().trim();
+
+                try
+                {
+                    long l = Long.parseLong(id);
+                    Bundle bundle = m_context.getBundle(l);
+                    if (bundle != null)
+                    {
+                        if (separatorNeeded)
+                        {
+                            out.println("");
+                        }
+                        getImportedPackages(bundle, out, err);
+                        separatorNeeded = 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());
+                }
+            }
+        }
+    }
+
+    private void getImportedPackages(Bundle bundle, PrintStream out, PrintStream err)
+    {
+        // Get package admin service.
+        PackageAdmin pa = getPackageAdmin();
+        if (pa == null)
+        {
+            out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            RequiredBundle[] rbs = pa.getRequiredBundles(null);
+            String title = bundle + " requires:";
+            out.println(title);
+            out.println(Util.getUnderlineString(title));
+            boolean found = false;
+            for (int rbIdx = 0; rbIdx < rbs.length; rbIdx++)
+            {
+                Bundle[] requirers = rbs[rbIdx].getRequiringBundles();
+                for (int reqIdx = 0; (requirers != null) && (reqIdx < requirers.length); reqIdx++)
+                {
+                    if (requirers[reqIdx] == bundle)
+                    {
+                        out.println(rbs[reqIdx]);
+                        found = true;
+                    }
+                }
+            }
+            if (!found)
+            {
+                out.println("Nothing");
+            }
+            ungetPackageAdmin();
+        }
+    }
+
+    private PackageAdmin getPackageAdmin()
+    {
+        PackageAdmin pa = null;
+        m_ref = m_context.getServiceReference(
+            org.osgi.service.packageadmin.PackageAdmin.class.getName());
+        if (m_ref != null)
+        {
+            pa = (PackageAdmin) m_context.getService(m_ref);
+        }
+        return pa;
+    }
+
+    private void ungetPackageAdmin()
+    {
+        m_context.ungetService(m_ref);
+    }
+}
\ No newline at end of file