SLING-3981 : Make dependency to config admin optional

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1628645 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index acc17d8..5f09f76 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,10 +71,11 @@
                             org.apache.sling.settings.impl.Activator
                         </Bundle-Activator>
                         <DynamicImport-Package>
-                            org.osgi.service.cm
+                            org.osgi.service.cm,
+                            org.apache.felix.shell
                         </DynamicImport-Package>
                         <Import-Package>
-                            !org.osgi.service.cm,
+                            org.osgi.service.cm;resolution:=optional,
                             org.apache.felix.shell;resolution:=optional, 
                             *
                         </Import-Package>
diff --git a/src/main/java/org/apache/sling/settings/SlingSettingsService.java b/src/main/java/org/apache/sling/settings/SlingSettingsService.java
index 563f7b5..15bf795 100644
--- a/src/main/java/org/apache/sling/settings/SlingSettingsService.java
+++ b/src/main/java/org/apache/sling/settings/SlingSettingsService.java
@@ -89,24 +89,28 @@
      * Utility method to generate an absolute path
      * within Sling Home.
      *
+     * @return the absolute including the sling home directory.
      * @since 1.1.0
      */
     String getAbsolutePathWithinSlingHome(String relativePath);
 
     /**
      * The identifier of the running Sling instance.
+     * @return The unique Sling identifier.
      */
     String getSlingId();
 
     /**
      * Returns the value of the {@link #SLING_HOME}
      * property.
+     * @return The sling home.
      */
     String getSlingHomePath();
 
     /**
      * Returns the value of the {@link #SLING_HOME_URL}
      * property.
+     * @return Sling home as a URL.
      */
     URL getSlingHome();
 
@@ -120,12 +124,14 @@
     /**
      * Return the optional name of the instance.
      * @return The name of the instance or <code>null</code>.
+     * @since 1.3
      */
     String getSlingName();
 
     /**
      * Return the optional description of the instance.
      * @return The description of the instance or <code>null</code>.
+     * @since 1.3
      */
     String getSlingDescription();
 }
diff --git a/src/main/java/org/apache/sling/settings/impl/RunModeCommand.java b/src/main/java/org/apache/sling/settings/impl/RunModeCommand.java
index 990b6a3..06b0dd3 100644
--- a/src/main/java/org/apache/sling/settings/impl/RunModeCommand.java
+++ b/src/main/java/org/apache/sling/settings/impl/RunModeCommand.java
@@ -33,35 +33,25 @@
  */
 public class RunModeCommand implements Command {
 
-    private static ServiceRegistration pluginReg;
+    private static final String CMD_NAME = "runmodes";
 
-    public static void initPlugin(final BundleContext bundleContext,
-            final Set<String> modes) {
-        final RunModeCommand command = new RunModeCommand(modes);
+    private final ServiceRegistration pluginReg;
+
+    private final Set<String> modes;
+
+    public RunModeCommand(final BundleContext btx, final Set<String> modes) {
+        this.modes = modes;
 
         final Dictionary<String, String> props = new Hashtable<String, String>();
         props.put(Constants.SERVICE_DESCRIPTION,
             "Apache Sling Sling Run Mode Shell Command");
         props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
 
-        pluginReg = bundleContext.registerService(Command.class.getName(),
-                command,
-                props);
+        pluginReg = btx.registerService(Command.class.getName(), this, props);
     }
 
-    public static void destroyPlugin() {
-        if ( pluginReg != null) {
-            pluginReg.unregister();
-            pluginReg = null;
-        }
-    }
-
-    private static final String CMD_NAME = "runmodes";
-
-    private Set<String> modes;
-
-    public RunModeCommand(final Set<String> modes) {
-        this.modes = modes;
+    public void destroy() {
+        pluginReg.unregister();
     }
 
     /**
diff --git a/src/main/java/org/apache/sling/settings/impl/ServicesListener.java b/src/main/java/org/apache/sling/settings/impl/ServicesListener.java
index 0494219..d0dd139 100644
--- a/src/main/java/org/apache/sling/settings/impl/ServicesListener.java
+++ b/src/main/java/org/apache/sling/settings/impl/ServicesListener.java
@@ -23,16 +23,13 @@
 
 import org.apache.sling.launchpad.api.StartupHandler;
 import org.apache.sling.settings.SlingSettingsService;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.ManagedService;
 
 /**
  * The <code>ServicesListener</code> listens for the required services
@@ -47,12 +44,16 @@
     /** The listener for the startup handler. */
     private final Listener startupListener;
 
+    /** The listener for configuration admin. */
+    private ConfigAdminListener configAdminListener;
+
+    /** The listener for the shell. */
+    private ShellListener shellListener;
+
+
     /** The registration of the settings service. */
     private ServiceRegistration settingsReg;
 
-    /** The registration of the managed service. */
-    private ServiceRegistration managedServiceReg;
-
     /**
      * Start listeners
      */
@@ -87,47 +88,34 @@
                                                settingsService, props);
         SlingPropertiesPrinter.initPlugin(bundleContext);
         SlingSettingsPrinter.initPlugin(bundleContext, settingsService);
-        try {
-            RunModeCommand.initPlugin(bundleContext, settingsService.getRunModes());
-        } catch (final Throwable ignore) {
-            // we just ignore this
-        }
-        // setup manager service for configuration handling
-        final Dictionary<String, String> msProps = new Hashtable<String, String>();
-        msProps.put(Constants.SERVICE_PID, settingsService.getClass().getName());
-        msProps.put(Constants.SERVICE_DESCRIPTION,
-            "Apache Sling Managed Service for the Settings Service");
-        msProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
-        managedServiceReg = this.bundleContext.registerService(ManagedService.class.getName(), new ServiceFactory() {
 
-            public void ungetService(final Bundle bundle, final ServiceRegistration registration,
-                    final Object service) {
-                // nothing to do
-            }
+        // add config admin support
+        this.configAdminListener = new ConfigAdminListener(settingsService);
+        this.configAdminListener.start();
 
-            public Object getService(final Bundle bundle, final ServiceRegistration registration) {
-                return new SettingsServiceConfigurator(settingsService);
-            }
-        }, msProps);
+        // add shell support
+        this.shellListener = new ShellListener(settingsService);
+        this.shellListener.start();
     }
+
     /**
      * Deactivate this listener.
      */
     public void deactivate() {
-        if ( this.managedServiceReg != null ) {
-            this.managedServiceReg.unregister();
-            this.managedServiceReg = null;
+        if ( this.shellListener != null ) {
+            this.shellListener.deactivate();
+            this.shellListener = null;
+        }
+        if ( this.configAdminListener != null ) {
+            this.configAdminListener.deactivate();
+            this.configAdminListener = null;
         }
         this.startupListener.deactivate();
         if ( this.settingsReg != null ) {
             this.settingsReg.unregister();
             this.settingsReg = null;
         }
-        try {
-            RunModeCommand.destroyPlugin();
-        } catch (Throwable ignore) {
-            // we just ignore this
-        }
+
         SlingSettingsPrinter.destroyPlugin();
         SlingPropertiesPrinter.destroyPlugin();
     }
@@ -135,7 +123,7 @@
     /**
      * Helper class listening for service events for a defined service.
      */
-    protected final class Listener implements ServiceListener {
+    private abstract class AbstractListener implements ServiceListener {
 
         /** The name of the service. */
         private final String serviceName;
@@ -149,7 +137,7 @@
         /**
          * Constructor
          */
-        public Listener(final String serviceName) {
+        public AbstractListener(final String serviceName) {
             this.serviceName = serviceName;
         }
 
@@ -193,7 +181,7 @@
                     if ( this.service == null ) {
                         this.reference = null;
                     } else {
-                        notifyChange();
+                        serviceChanged();
                     }
                 }
             }
@@ -207,7 +195,7 @@
                 this.service = null;
                 bundleContext.ungetService(this.reference);
                 this.reference = null;
-                notifyChange();
+                serviceChanged();
             }
         }
 
@@ -221,5 +209,95 @@
                 this.releaseService();
             }
         }
+
+        protected abstract void serviceChanged();
+    }
+
+    /**
+     * Helper class listening for service events for a defined service.
+     */
+    private final class Listener extends AbstractListener {
+
+        /**
+         * Constructor
+         */
+        public Listener(final String serviceName) {
+            super(serviceName);
+        }
+
+        @Override
+        protected void serviceChanged() {
+            notifyChange();
+        }
+    }
+
+    /**
+     * Helper class listening for service events for config admin
+     */
+    private final class ConfigAdminListener extends AbstractListener {
+
+        private Object settingsServiceConfigurator;
+
+        private final SlingSettingsServiceImpl settings;
+
+        /**
+         * Constructor
+         */
+        public ConfigAdminListener(final SlingSettingsServiceImpl settings) {
+            super("org.osgi.service.cm.ConfigurationAdmin");
+            this.settings = settings;
+        }
+
+        @Override
+        protected void serviceChanged() {
+            if ( this.getService() != null && this.settingsServiceConfigurator == null ) {
+                this.settingsServiceConfigurator = new SettingsServiceConfigurator(bundleContext, settings);
+            }
+        }
+
+        @Override
+        public void deactivate() {
+            super.deactivate();
+            if ( settingsServiceConfigurator != null ) {
+                ((SettingsServiceConfigurator)settingsServiceConfigurator).destroy();
+                settingsServiceConfigurator = null;
+            }
+        }
+
+    }
+
+    /**
+     * Helper class listening for service events for config admin
+     */
+    private final class ShellListener extends AbstractListener {
+
+        private Object runModeCommand;
+
+        private final SlingSettingsServiceImpl settings;
+
+        /**
+         * Constructor
+         */
+        public ShellListener(final SlingSettingsServiceImpl settings) {
+            super("org.apache.felix.shell.ShellService");
+            this.settings = settings;
+        }
+
+        @Override
+        protected void serviceChanged() {
+            if ( this.getService() != null && this.runModeCommand == null ) {
+                this.runModeCommand = new RunModeCommand(bundleContext, settings.getRunModes());
+            }
+        }
+
+        @Override
+        public void deactivate() {
+            super.deactivate();
+            if ( runModeCommand != null ) {
+                ((RunModeCommand)runModeCommand).destroy();
+                runModeCommand = null;
+            }
+        }
+
     }
 }
diff --git a/src/main/java/org/apache/sling/settings/impl/SettingsServiceConfigurator.java b/src/main/java/org/apache/sling/settings/impl/SettingsServiceConfigurator.java
index 74228ae..85d0b54 100644
--- a/src/main/java/org/apache/sling/settings/impl/SettingsServiceConfigurator.java
+++ b/src/main/java/org/apache/sling/settings/impl/SettingsServiceConfigurator.java
@@ -19,7 +19,11 @@
 package org.apache.sling.settings.impl;
 
 import java.util.Dictionary;
+import java.util.Hashtable;
 
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
 
@@ -27,12 +31,28 @@
 
     private final SlingSettingsServiceImpl settings;
 
-    public SettingsServiceConfigurator(final SlingSettingsServiceImpl s) {
+    private final ServiceRegistration managedServiceReg;
+
+    public SettingsServiceConfigurator(final BundleContext btx,
+            final SlingSettingsServiceImpl s) {
         this.settings = s;
+        // setup manager service for configuration handling
+        final Dictionary<String, String> msProps = new Hashtable<String, String>();
+        msProps.put(Constants.SERVICE_PID, s.getClass().getName());
+        msProps.put(Constants.SERVICE_DESCRIPTION,
+            "Apache Sling Managed Service for the Settings Service");
+        msProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        managedServiceReg = btx.registerService(ManagedService.class.getName(), this, msProps);
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     public void updated(final Dictionary properties) throws ConfigurationException {
-        this.settings.update(properties);
+        if ( properties != null ) {
+            this.settings.update(properties);
+        }
+    }
+
+    public void destroy() {
+        managedServiceReg.unregister();
     }
 }
diff --git a/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java b/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java
index 1281495..56448c5 100644
--- a/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java
+++ b/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java
@@ -241,6 +241,7 @@
     }
 
 
+    @SuppressWarnings("unchecked")
     private List<Options> readOptions(final BundleContext context) {
         List<Options> optionsList = null;
         final File file = context.getDataFile(OPTIONS_FILE);