Add more missing commands and do a little refactoring. (FELIX-2042)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@941893 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/felixcommands/pom.xml b/gogo/felixcommands/pom.xml
index f8be0ef..e026e84 100644
--- a/gogo/felixcommands/pom.xml
+++ b/gogo/felixcommands/pom.xml
@@ -41,6 +41,11 @@
       <version>4.2.0</version>
     </dependency>
     <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <version>4.0.0</version>
+    </dependency>
+    <dependency>
       <groupId>org.apache.felix.gogo</groupId>
       <artifactId>org.apache.felix.gogo.runtime</artifactId>
       <version>0.5.0-SNAPSHOT</version>
@@ -65,6 +70,7 @@
         <extensions>true</extensions>
         <configuration>
           <instructions>
+            <Export-Package>org.osgi.service.log</Export-Package>
             <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
             <Private-Package>${pom.artifactId}</Private-Package>
             <Bundle-Activator>${artifactId}.Activator</Bundle-Activator>
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java
index a77b60e..9ecd1e6 100644
--- a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Activator.java
@@ -29,9 +29,10 @@
         Hashtable props = new Hashtable();
         props.put("osgi.command.scope", "basic");
         props.put("osgi.command.function", new String[] {
-            "bundlelevel", "frameworklevel", "headers", "help",
-            "install", "lb", "refresh", "resolve", "start",
-            "stop", "uninstall", "update", "which" });
+            "bundlelevel", "frameworklevel", "headers",
+            "help", "install", "inspect", "lb", "log", "refresh",
+            "resolve", "start", "stop", "uninstall", "update",
+            "which" });
         bc.registerService(
             Basic.class.getName(), new Basic(bc), props);
 
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java
index 985c5eb..b7d56e8 100644
--- a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Basic.java
@@ -21,12 +21,16 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Iterator;
@@ -44,13 +48,15 @@
 import org.osgi.service.command.Descriptor;
 import org.osgi.service.command.Flag;
 import org.osgi.service.command.Option;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.service.startlevel.StartLevel;
 
 public class Basic
 {
     private final BundleContext m_bc;
-    private final List<ServiceReference> m_usedRefs = new ArrayList(0);
 
     public Basic(BundleContext bc)
     {
@@ -59,11 +65,13 @@
 
     @Descriptor(description="query bundle start level")
     public void bundlelevel(
-        @Descriptor(description="bundle identifier to query") Long id)
+        @Descriptor(description="bundle to query") Bundle bundle)
     {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get start level service.
-        ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
-        StartLevel sl = getService(StartLevel.class, ref);
+        StartLevel sl = Util.getService(m_bc, StartLevel.class, refs);
         if (sl == null)
         {
             System.out.println("Start Level service is unavailable.");
@@ -71,14 +79,13 @@
         // Get the bundle start level.
         else
         {
-            Bundle bundle = getBundle(m_bc, id);
             if (bundle != null)
             {
                 System.out.println(bundle + " is level " + sl.getBundleStartLevel(bundle));
             }
         }
 
-        ungetServices();
+        Util.ungetServices(m_bc, refs);
     }
 
     @Descriptor(description="set bundle start level or initial bundle start level")
@@ -86,11 +93,13 @@
         @Flag(name="-s", description="set the specified bundle's start level") boolean set,
         @Flag(name="-i", description="set the initial bundle start level") boolean initial,
         @Descriptor(description="target level") int level,
-        @Descriptor(description="target bundle identifiers") Long[] ids)
+        @Descriptor(description="target identifiers") Bundle[] bundles)
     {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get start level service.
-        ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
-        StartLevel sl = getService(StartLevel.class, ref);
+        StartLevel sl = Util.getService(m_bc, StartLevel.class, refs);
         if (sl == null)
         {
             System.out.println("Start Level service is unavailable.");
@@ -110,7 +119,7 @@
         // Set the initial bundle start level.
         else if (initial)
         {
-            if ((ids != null) && (ids.length == 0))
+            if ((bundles != null) && (bundles.length == 0))
             {
                 sl.setInitialBundleStartLevel(level);
             }
@@ -123,8 +132,7 @@
         // Set the bundle start level.
         else if (set)
         {
-            List<Bundle> bundles = getBundles(m_bc, ids);
-            if (bundles != null)
+            if ((bundles != null) && (bundles.length == 0))
             {
                 for (Bundle bundle: bundles)
                 {
@@ -137,36 +145,40 @@
             }
         }
 
-        ungetServices();
+        Util.ungetServices(m_bc, refs);
     }
 
     @Descriptor(description="query framework active start level")
     public void frameworklevel()
     {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get start level service.
-        ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
-        StartLevel sl = getService(StartLevel.class, ref);
+        StartLevel sl = Util.getService(m_bc, StartLevel.class, refs);
         if (sl == null)
         {
             System.out.println("Start Level service is unavailable.");
         }
         System.out.println("Level is " + sl.getStartLevel());
-        ungetServices();
+        Util.ungetServices(m_bc, refs);
     }
 
     @Descriptor(description="set framework active start level")
     public void frameworklevel(
         @Descriptor(description="target start level") int level)
     {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get start level service.
-        ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
-        StartLevel sl = getService(StartLevel.class, ref);
+        StartLevel sl = Util.getService(m_bc, StartLevel.class, refs);
         if (sl == null)
         {
             System.out.println("Start Level service is unavailable.");
         }
         sl.setStartLevel(level);
-        ungetServices();
+        Util.ungetServices(m_bc, refs);
     }
 
     @Descriptor(description="display bundle headers")
@@ -347,6 +359,15 @@
         return commands;
     }
 
+    @Descriptor(description="inspects bundle dependency information")
+    public void inspect(
+        @Descriptor(description="(package | bundle | fragment | service)") String type,
+        @Descriptor(description="(capability | requirement)") String direction,
+        @Descriptor(description="target bundles") Bundle[] bundles)
+    {
+        Inspect.inspect(m_bc, type, direction, bundles);
+    }
+
     @Descriptor(description="install bundle using URLs")
     public void install(
         @Descriptor(description="target URLs") String[] urls)
@@ -399,31 +420,174 @@
         }
     }
 
-    @Descriptor(description="list installed bundles")
+    @Descriptor(description="list all installed bundles")
     public void lb(
         @Flag(name="-l", description="show location") boolean showLoc,
         @Flag(name="-s", description="show symbolic name") boolean showSymbolic,
         @Flag(name="-u", description="show update location") boolean showUpdate)
     {
+        lb(showLoc, showSymbolic, showUpdate, null);
+    }
+
+    @Descriptor(description="list installed bundles matching a pattern")
+    public void lb(
+        @Flag(name="-l", description="show location") boolean showLoc,
+        @Flag(name="-s", description="show symbolic name") boolean showSymbolic,
+        @Flag(name="-u", description="show update location") boolean showUpdate,
+        String pattern)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get start level service.
-        ServiceReference ref = m_bc.getServiceReference(StartLevel.class.getName());
-        StartLevel sl = getService(StartLevel.class, ref);
+        StartLevel sl = Util.getService(m_bc, StartLevel.class, refs);
         if (sl == null)
         {
             System.out.println("Start Level service is unavailable.");
         }
 
-        Bundle[] bundles = m_bc.getBundles();
-        if (bundles != null)
+        List<Bundle> found = new ArrayList();
+
+        if (pattern == null)
         {
-            printBundleList(bundles, sl, System.out, showLoc, showSymbolic, showUpdate);
+            found.addAll(Arrays.asList(m_bc.getBundles()));
         }
         else
         {
-            System.out.println("There are no installed bundles.");
+            Bundle[] bundles = m_bc.getBundles();
+
+            for (int i = 0; i < bundles.length; i++)
+            {
+                Bundle bundle = bundles[i];
+                String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+                if (matchBundleName(bundle.getSymbolicName(), pattern)
+                    || matchBundleName(name, pattern))
+                {
+                    found.add(bundle);
+                }
+            }
         }
 
-        ungetServices();
+        if (found.size() > 0)
+        {
+            printBundleList(
+                (Bundle[]) found.toArray(new Bundle[found.size()]), sl,
+                showLoc, showSymbolic, showUpdate);
+        }
+        else
+        {
+            System.out.println("No matching bundles found");
+        }
+
+        Util.ungetServices(m_bc, refs);
+    }
+
+    private boolean matchBundleName(String name, String pattern)
+    {
+        return (name != null) && name.toLowerCase().contains(pattern.toLowerCase());
+    }
+
+    @Descriptor(description="display all matching log entries")
+    public void log(
+        @Descriptor(description="minimum log level [ debug | info | warn | error ]")
+            String logLevel)
+    {
+        log(-1, logLevel);
+    }
+
+    @Descriptor(description="display some matching log entries")
+    public void log(
+        @Descriptor(description="maximum number of entries") int maxEntries,
+        @Descriptor(description="minimum log level [ debug | info | warn | error ]")
+            String logLevel)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get start level service.
+        LogReaderService lrs = Util.getService(m_bc, LogReaderService.class, refs);
+        if (lrs == null)
+        {
+            System.out.println("Log reader service is unavailable.");
+        }
+        else
+        {
+            Enumeration entries = lrs.getLog();
+
+            int minLevel = logLevelAsInt(logLevel);
+
+            int index = 0;
+            while (entries.hasMoreElements()
+                && (maxEntries < 0 || index < maxEntries))
+            {
+                LogEntry entry = (LogEntry) entries.nextElement();
+                if (entry.getLevel() <= minLevel)
+                {
+                    display(entry);
+                    index++;
+                }
+            }
+
+            Util.ungetServices(m_bc, refs);
+        }
+    }
+
+    private void display(LogEntry entry)
+    {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
+
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(sdf.format(new Date(entry.getTime()))).append(" ");
+        buffer.append(logLevelAsString(entry.getLevel())).append(" - ");
+        buffer.append("Bundle: ").append(entry.getBundle().getSymbolicName());
+        if (entry.getServiceReference() != null)
+        {
+            buffer.append(" - ");
+            buffer.append(entry.getServiceReference().toString());
+        }
+        buffer.append(" - ").append(entry.getMessage());
+        if (entry.getException() != null)
+        {
+            buffer.append(" - ");
+            StringWriter writer = new StringWriter();
+            PrintWriter  pw = new PrintWriter(writer);
+            entry.getException().printStackTrace(pw);
+            buffer.append(writer.toString());
+        }
+
+        System.out.println(buffer.toString());
+    }
+
+    private static int logLevelAsInt(String logLevel)
+    {
+        if ("error".equalsIgnoreCase(logLevel))
+        {
+            return LogService.LOG_ERROR;
+        }
+        else if ("warn".equalsIgnoreCase(logLevel))
+        {
+            return LogService.LOG_WARNING;
+        }
+        else if ("info".equalsIgnoreCase(logLevel))
+        {
+            return LogService.LOG_INFO;
+        }
+        return LogService.LOG_DEBUG;
+    }
+
+    private static String logLevelAsString(int level)
+    {
+        switch (level)
+        {
+            case LogService.LOG_ERROR:
+                return "ERROR";
+            case LogService.LOG_WARNING:
+                return "WARNING";
+            case LogService.LOG_INFO:
+                return "INFO";
+            default:
+                return "DEBUG";
+        }
     }
 
     @Descriptor(description="refresh any updated or uninstalled bundles")
@@ -445,9 +609,11 @@
 
     private void refresh(List<Bundle> bundles)
     {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get package admin service.
-        ServiceReference ref = m_bc.getServiceReference(PackageAdmin.class.getName());
-        PackageAdmin pa = getService(PackageAdmin.class, ref);
+        PackageAdmin pa = Util.getService(m_bc, PackageAdmin.class, refs);
         if (pa == null)
         {
             System.out.println("Package Admin service is unavailable.");
@@ -456,7 +622,7 @@
             ? null
             : (Bundle[]) bundles.toArray(new Bundle[bundles.size()]));
 
-        ungetServices();
+        Util.ungetServices(m_bc, refs);
     }
 
     @Descriptor(description="resolve all bundles")
@@ -478,9 +644,11 @@
 
     private void resolve(List<Bundle> bundles)
     {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
         // Get package admin service.
-        ServiceReference ref = m_bc.getServiceReference(PackageAdmin.class.getName());
-        PackageAdmin pa = getService(PackageAdmin.class, ref);
+        PackageAdmin pa = Util.getService(m_bc, PackageAdmin.class, refs);
         if (pa == null)
         {
             System.out.println("Package Admin service is unavailable.");
@@ -489,7 +657,7 @@
             ? null
             : (Bundle[]) bundles.toArray(new Bundle[bundles.size()]));
 
-        ungetServices();
+        Util.ungetServices(m_bc, refs);
     }
 
     @Descriptor(description="start bundles")
@@ -769,13 +937,13 @@
     }
 
     private static void printBundleList(
-        Bundle[] bundles, StartLevel startLevel, PrintStream out, boolean showLoc,
+        Bundle[] bundles, StartLevel startLevel, boolean showLoc,
         boolean showSymbolic, boolean showUpdate)
     {
         // Display active start level.
         if (startLevel != null)
         {
-            out.println("START LEVEL " + startLevel.getStartLevel());
+            System.out.println("START LEVEL " + startLevel.getStartLevel());
         }
 
         // Print column headers.
@@ -793,7 +961,7 @@
            msg = " Update location";
         }
         String level = (startLevel == null) ? "" : "  Level ";
-        out.println("   ID " + "  State       " + level + msg);
+        System.out.println("   ID " + "  State       " + level + msg);
         for (int i = 0; i < bundles.length; i++)
         {
             // Get the bundle name or location.
@@ -846,34 +1014,12 @@
             {
                 id = " " + id;
             }
-            out.println("[" + id + "] ["
+            System.out.println("[" + id + "] ["
                 + getStateString(bundles[i])
                 + "] [" + level + "] " + name);
         }
     }
 
-    private <T> T getService(Class<T> clazz, ServiceReference ref)
-    {
-        if (ref == null)
-        {
-            return null;
-        }
-        T t = (T) m_bc.getService(ref);
-        if (t != null)
-        {
-            m_usedRefs.add(ref);
-        }
-        return t;
-    }
-
-    private void ungetServices()
-    {
-        while (m_usedRefs.size() > 0)
-        {
-            m_bc.ungetService(m_usedRefs.remove(0));
-        }
-    }
-
     private static String getStateString(Bundle bundle)
     {
         int state = bundle.getState();
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Inspect.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Inspect.java
new file mode 100644
index 0000000..d17c344
--- /dev/null
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Inspect.java
@@ -0,0 +1,640 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.felixcommands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.packageadmin.RequiredBundle;
+
+public class Inspect
+{
+    public static final String PACKAGE_TYPE = "package";
+    public static final String BUNDLE_TYPE = "bundle";
+    public static final String FRAGMENT_TYPE = "fragment";
+    public static final String SERVICE_TYPE = "service";
+
+    public static final String CAPABILITY = "capability";
+    public static final String REQUIREMENT = "requirement";
+
+    public static void inspect(
+        BundleContext bc, String type, String direction, Bundle[] bundles)
+    {
+        // Verify arguments.
+        if (isValidType(type) && isValidDirection(direction))
+        {
+            // Now determine what needs to be printed.
+            if (PACKAGE_TYPE.startsWith(type))
+            {
+                if (CAPABILITY.startsWith(direction))
+                {
+                    printExportedPackages(bc, bundles);
+                }
+                else
+                {
+                    printImportedPackages(bc, bundles);
+                }
+            }
+            else if (BUNDLE_TYPE.startsWith(type))
+            {
+                if (CAPABILITY.startsWith(direction))
+                {
+                    printRequiringBundles(bc, bundles);
+                }
+                else
+                {
+                    printRequiredBundles(bc, bundles);
+                }
+            }
+            else if (FRAGMENT_TYPE.startsWith(type))
+            {
+                if (CAPABILITY.startsWith(direction))
+                {
+                    printFragmentHosts(bc, bundles);
+                }
+                else
+                {
+                    printHostedFragments(bc, bundles);
+                }
+            }
+            else
+            {
+                if (CAPABILITY.startsWith(direction))
+                {
+                    printExportedServices(bc, bundles);
+                }
+                else
+                {
+                    printImportedServices(bc, bundles);
+                }
+            }
+        }
+        else
+        {
+            if (!isValidType(type))
+            {
+                System.out.println("Invalid argument: " + type);
+            }
+            if (!isValidDirection(direction))
+            {
+                System.out.println("Invalid argument: " + direction);
+            }
+        }
+    }
+
+    public static void printExportedPackages(BundleContext bc, Bundle[] bundles)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get package admin service.
+        PackageAdmin pa = Util.getService(bc, PackageAdmin.class, refs);
+        if (pa == null)
+        {
+            System.out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            boolean separatorNeeded = false;
+
+            if ((bundles == null) || (bundles.length == 0))
+            {
+                bundles = bc.getBundles();
+            }
+
+            for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+            {
+                try
+                {
+                    if (bundles[bundleIdx] != null)
+                    {
+                        ExportedPackage[] exports = pa.getExportedPackages(bundles[bundleIdx]);
+                        if (separatorNeeded)
+                        {
+                            System.out.println("");
+                        }
+                        String title = bundles[bundleIdx] + " exports packages:";
+                        System.out.println(title);
+                        System.out.println(Util.getUnderlineString(title));
+                        if ((exports != null) && (exports.length > 0))
+                        {
+                            for (int expIdx = 0; expIdx < exports.length; expIdx++)
+                            {
+                                System.out.print(exports[expIdx]);
+                                Bundle[] importers = exports[expIdx].getImportingBundles();
+                                if ((importers == null) || (importers.length == 0))
+                                {
+                                    System.out.println(" UNUSED");
+                                }
+                                else
+                                {
+                                    System.out.println(" imported by:");
+                                    for (int impIdx = 0; impIdx < importers.length; impIdx++)
+                                    {
+                                        System.out.println("   " + importers[impIdx]);
+                                    }
+                                }
+                            }
+                        }
+                        else
+                        {
+                            System.out.println("Nothing");
+                        }
+                        separatorNeeded = true;
+                    }
+                }
+                catch (Exception ex)
+                {
+                    System.err.println(ex.toString());
+                }
+            }
+            Util.ungetServices(bc, refs);
+        }
+    }
+
+    public static void printImportedPackages(BundleContext bc, Bundle[] bundles)
+    {
+        boolean separatorNeeded = false;
+
+        if ((bundles == null) || (bundles.length == 0))
+        {
+            bundles = bc.getBundles();
+        }
+
+        for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+        {
+            try
+            {
+                if (bundles[bundleIdx] != null)
+                {
+                    if (separatorNeeded)
+                    {
+                        System.out.println("");
+                    }
+                    _printImportedPackages(bc, bundles[bundleIdx]);
+                    separatorNeeded = true;
+                }
+            }
+            catch (Exception ex)
+            {
+                System.err.println(ex.toString());
+            }
+        }
+    }
+
+    private static void _printImportedPackages(BundleContext bc, Bundle bundle)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get package admin service.
+        PackageAdmin pa = Util.getService(bc, PackageAdmin.class, refs);
+        if (pa == null)
+        {
+            System.out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            ExportedPackage[] exports = pa.getExportedPackages((Bundle) null);
+            String title = bundle + " imports packages:";
+            System.out.println(title);
+            System.out.println(Util.getUnderlineString(title));
+            boolean found = false;
+            for (int expIdx = 0; expIdx < exports.length; expIdx++)
+            {
+                Bundle[] importers = exports[expIdx].getImportingBundles();
+                for (int impIdx = 0; (importers != null) && (impIdx < importers.length); impIdx++)
+                {
+                    if (importers[impIdx] == bundle)
+                    {
+                        System.out.println(exports[expIdx]
+                            + " -> " + exports[expIdx].getExportingBundle());
+                        found = true;
+                    }
+                }
+            }
+            if (!found)
+            {
+                System.out.println("Nothing");
+            }
+            Util.ungetServices(bc, refs);
+        }
+    }
+
+    public static void printRequiringBundles(BundleContext bc, Bundle[] bundles)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get package admin service.
+        PackageAdmin pa = Util.getService(bc, PackageAdmin.class, refs);
+        if (pa == null)
+        {
+            System.out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            boolean separatorNeeded = false;
+
+            if ((bundles == null) || (bundles.length == 0))
+            {
+                bundles = bc.getBundles();
+            }
+
+            for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+            {
+                try
+                {
+                    if (bundles[bundleIdx] != null)
+                    {
+                        RequiredBundle[] rbs = pa.getRequiredBundles(
+                            bundles[bundleIdx].getSymbolicName());
+                        for (int rbIdx = 0; (rbs != null) && (rbIdx < rbs.length); rbIdx++)
+                        {
+                            if (rbs[rbIdx].getBundle() == bundles[bundleIdx])
+                            {
+                                if (separatorNeeded)
+                                {
+                                    System.out.println("");
+                                }
+                                String title = bundles[bundleIdx] + " is required by:";
+                                System.out.println(title);
+                                System.out.println(Util.getUnderlineString(title));
+                                if ((rbs[rbIdx].getRequiringBundles() != null)
+                                    && (rbs[rbIdx].getRequiringBundles().length > 0))
+                                {
+                                    for (int reqIdx = 0;
+                                        reqIdx < rbs[rbIdx].getRequiringBundles().length;
+                                        reqIdx++)
+                                    {
+                                        System.out.println(rbs[rbIdx].getRequiringBundles()[reqIdx]);
+                                    }
+                                }
+                                else
+                                {
+                                    System.out.println("Nothing");
+                                }
+                                separatorNeeded = true;
+                            }
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    System.err.println(ex.toString());
+                }
+            }
+            Util.ungetServices(bc, refs);
+        }
+    }
+
+    public static void printRequiredBundles(BundleContext bc, Bundle[] bundles)
+    {
+        boolean separatorNeeded = false;
+
+        if ((bundles == null) || (bundles.length == 0))
+        {
+            bundles = bc.getBundles();
+        }
+
+        for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+        {
+            try
+            {
+                if (bundles[bundleIdx] != null)
+                {
+                    if (separatorNeeded)
+                    {
+                        System.out.println("");
+                    }
+                    _printRequiredBundles(bc, bundles[bundleIdx]);
+                    separatorNeeded = true;
+                }
+            }
+            catch (Exception ex)
+            {
+                System.err.println(ex.toString());
+            }
+        }
+    }
+
+    private static void _printRequiredBundles(BundleContext bc, Bundle bundle)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get package admin service.
+        PackageAdmin pa = Util.getService(bc, PackageAdmin.class, refs);
+        if (pa == null)
+        {
+            System.out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            RequiredBundle[] rbs = pa.getRequiredBundles(null);
+            String title = bundle + " requires bundles:";
+            System.out.println(title);
+            System.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)
+                    {
+                        System.out.println(rbs[reqIdx]);
+                        found = true;
+                    }
+                }
+            }
+            if (!found)
+            {
+                System.out.println("Nothing");
+            }
+            Util.ungetServices(bc, refs);
+        }
+    }
+
+    public static void printFragmentHosts(BundleContext bc, Bundle[] bundles)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get package admin service.
+        PackageAdmin pa = Util.getService(bc, PackageAdmin.class, refs);
+        if (pa == null)
+        {
+            System.out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            if ((bundles == null) || (bundles.length == 0))
+            {
+                bundles = bc.getBundles();
+            }
+
+            for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+            {
+                // Print a separator for some whitespace.
+                if (bundleIdx > 0)
+                {
+                    System.out.println("");
+                }
+
+                try
+                {
+                    if ((bundles[bundleIdx] != null) && isFragment(bundles[bundleIdx]))
+                    {
+                        String title = bundles[bundleIdx] + " is attached to:";
+                        System.out.println(title);
+                        System.out.println(Util.getUnderlineString(title));
+                        Bundle[] hosts = pa.getHosts(bundles[bundleIdx]);
+                        for (int hostIdx = 0;
+                            (hosts != null) && (hostIdx < hosts.length);
+                            hostIdx++)
+                        {
+                            System.out.println(hosts[hostIdx]);
+                        }
+                        if ((hosts == null) || (hosts.length == 0))
+                        {
+                            System.out.println("Nothing");
+                        }
+                    }
+                    else if ((bundles[bundleIdx] != null) && !isFragment(bundles[bundleIdx]))
+                    {
+                        System.out.println("Bundle " + bundles[bundleIdx] + " is not a fragment.");
+                    }
+                }
+                catch (Exception ex)
+                {
+                    System.err.println(ex.toString());
+                }
+            }
+            Util.ungetServices(bc, refs);
+        }
+    }
+
+    public static void printHostedFragments(BundleContext bc, Bundle[] bundles)
+    {
+        // Keep track of service references.
+        List<ServiceReference> refs = new ArrayList();
+
+        // Get package admin service.
+        PackageAdmin pa = Util.getService(bc, PackageAdmin.class, refs);
+        if (pa == null)
+        {
+            System.out.println("PackageAdmin service is unavailable.");
+        }
+        else
+        {
+            if ((bundles == null) || (bundles.length == 0))
+            {
+                bundles = bc.getBundles();
+            }
+
+            for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+            {
+                // Print a separator for some whitespace.
+                if (bundleIdx > 0)
+                {
+                    System.out.println("");
+                }
+
+                try
+                {
+                    if ((bundles[bundleIdx] != null) && !isFragment(bundles[bundleIdx]))
+                    {
+                        String title = bundles[bundleIdx] + " hosts:";
+                        System.out.println(title);
+                        System.out.println(Util.getUnderlineString(title));
+                        Bundle[] fragments = pa.getFragments(bundles[bundleIdx]);
+                        for (int fragIdx = 0;
+                            (fragments != null) && (fragIdx < fragments.length);
+                            fragIdx++)
+                        {
+                            System.out.println(fragments[fragIdx]);
+                        }
+                        if ((fragments == null) || (fragments.length == 0))
+                        {
+                            System.out.println("Nothing");
+                        }
+                    }
+                    else if ((bundles[bundleIdx] != null) && isFragment(bundles[bundleIdx]))
+                    {
+                        System.out.println("Bundle " + bundles[bundleIdx] + " is a fragment.");
+                    }
+                }
+                catch (Exception ex)
+                {
+                    System.err.println(ex.toString());
+                }
+            }
+            Util.ungetServices(bc, refs);
+        }
+    }
+
+    public static void printExportedServices(BundleContext bc, Bundle[] bundles)
+    {
+        if ((bundles == null) || (bundles.length == 0))
+        {
+            bundles = bc.getBundles();
+        }
+
+        for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+        {
+            // Print a separator for some whitespace.
+            if (bundleIdx > 0)
+            {
+                System.out.println("");
+            }
+
+            try
+            {
+                if (bundles[bundleIdx] != null)
+                {
+                    ServiceReference[] refs = bundles[bundleIdx].getRegisteredServices();
+
+                    // Print header if we have not already done so.
+                    String title = Util.getBundleName(bundles[bundleIdx]) + " provides services:";
+                    System.out.println(title);
+                    System.out.println(Util.getUnderlineString(title));
+
+                    if ((refs == null) || (refs.length == 0))
+                    {
+                        System.out.println("Nothing");
+                    }
+
+                    // Print properties for each service.
+                    for (int refIdx = 0;
+                        (refs != null) && (refIdx < refs.length);
+                        refIdx++)
+                    {
+                        // 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]);
+                            System.out.println(
+                                keys[keyIdx] + " = " + Util.getValueString(v));
+                        }
+
+                        // Print service separator if necessary.
+                        if ((refIdx + 1) < refs.length)
+                        {
+                            System.out.println("----");
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                System.err.println(ex.toString());
+            }
+        }
+    }
+
+    public static void printImportedServices(BundleContext bc, Bundle[] bundles)
+    {
+        if ((bundles == null) || (bundles.length == 0))
+        {
+            bundles = bc.getBundles();
+        }
+
+        for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+        {
+            // Print a separator for some whitespace.
+            if (bundleIdx > 0)
+            {
+                System.out.println("");
+            }
+
+            try
+            {
+                if (bundles[bundleIdx] != null)
+                {
+                    ServiceReference[] refs = bundles[bundleIdx].getServicesInUse();
+
+                    // Print header if we have not already done so.
+                    String title = Util.getBundleName(bundles[bundleIdx]) + " requires services:";
+                    System.out.println(title);
+                    System.out.println(Util.getUnderlineString(title));
+
+                    if ((refs == null) || (refs.length == 0))
+                    {
+                        System.out.println("Nothing");
+                    }
+
+                    // Print properties for each service.
+                    for (int refIdx = 0;
+                        (refs != null) && (refIdx < refs.length);
+                        refIdx++)
+                    {
+                        // Print the registering bundle.
+                        System.out.println("Registering bundle = " + refs[refIdx].getBundle());
+                        // 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]);
+                            System.out.println(
+                                keys[keyIdx] + " = " + Util.getValueString(v));
+                        }
+
+                        // Print service separator if necessary.
+                        if ((refIdx + 1) < refs.length)
+                        {
+                            System.out.println("----");
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                System.err.println(ex.toString());
+            }
+        }
+    }
+
+    private static boolean isValidType(String type)
+    {
+        return (PACKAGE_TYPE.startsWith(type) || BUNDLE_TYPE.startsWith(type)
+            || FRAGMENT_TYPE.startsWith(type) || SERVICE_TYPE.startsWith(type));
+    }
+
+    private static boolean isValidDirection(String direction)
+    {
+        return (CAPABILITY.startsWith(direction) || REQUIREMENT.startsWith(direction));
+    }
+
+    private static boolean isFragment(Bundle bundle)
+    {
+        return bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null;
+    }
+}
\ No newline at end of file
diff --git a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java
index acd9428..03021dc 100644
--- a/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java
+++ b/gogo/felixcommands/src/main/java/org/apache/felix/gogo/felixcommands/Util.java
@@ -18,8 +18,11 @@
  */
 package org.apache.felix.gogo.felixcommands;
 
+import java.util.List;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 
 public class Util
 {
@@ -105,4 +108,28 @@
             }
         }
     }
+
+    public static <T> T getService(
+        BundleContext bc, Class<T> clazz, List<ServiceReference> refs)
+    {
+        ServiceReference ref = bc.getServiceReference(clazz.getName());
+        if (ref == null)
+        {
+            return null;
+        }
+        T t = (T) bc.getService(ref);
+        if (t != null)
+        {
+            refs.add(ref);
+        }
+        return t;
+    }
+
+    public static void ungetServices(BundleContext bc, List<ServiceReference> refs)
+    {
+        while (refs.size() > 0)
+        {
+            bc.ungetService(refs.remove(0));
+        }
+    }
 }
\ No newline at end of file