FELIX-1591: fileinstall should have an optional import on org.osgi.service.cm package

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@825122 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/pom.xml b/fileinstall/pom.xml
index 28875bb..a24d862 100644
--- a/fileinstall/pom.xml
+++ b/fileinstall/pom.xml
@@ -53,14 +53,14 @@
         <configuration>
           <instructions>
             <Export-Package>
-                org.apache.felix.fileinstall;version=${project.version},
-                org.osgi.service.cm
+                org.apache.felix.fileinstall;version=${project.version}
             </Export-Package>
             <Private-Package>
                 org.apache.felix.fileinstall.internal
             </Private-Package>
             <Import-Package>
                 org.osgi.service.log;resolution:=optional,
+                org.osgi.service.cm;resolution:=optional,
                 *
             </Import-Package>
             <Bundle-Activator>org.apache.felix.fileinstall.internal.FileInstall</Bundle-Activator>
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java
index feb6045..37a755f 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java
@@ -28,6 +28,7 @@
 import org.apache.felix.fileinstall.ArtifactInstaller;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
 
 /**
  * ArtifactInstaller for configurations.
@@ -35,11 +36,13 @@
  */
 public class ConfigInstaller implements ArtifactInstaller
 {
-    BundleContext context;
+    private final BundleContext context;
+    private final ConfigurationAdmin configAdmin;
 
-    ConfigInstaller(BundleContext context)
+    ConfigInstaller(BundleContext context, ConfigurationAdmin configAdmin)
     {
         this.context = context;
+        this.configAdmin = configAdmin;
     }
 
     public boolean canHandle(File artifact)
@@ -62,6 +65,11 @@
         deleteConfig(artifact);
     }
 
+    ConfigurationAdmin getConfigurationAdmin()
+    {
+        return configAdmin;
+    }
+
     /**
      * Set the configuration based on the config file.
      *
@@ -156,11 +164,11 @@
             Configuration newConfiguration;
             if (factoryPid != null)
             {
-                newConfiguration = FileInstall.getConfigurationAdmin().createFactoryConfiguration(pid, null);
+                newConfiguration = getConfigurationAdmin().createFactoryConfiguration(pid, null);
             }
             else
             {
-                newConfiguration = FileInstall.getConfigurationAdmin().getConfiguration(pid, null);
+                newConfiguration = getConfigurationAdmin().getConfiguration(pid, null);
             }
             return newConfiguration;
         }
@@ -171,7 +179,7 @@
         String suffix = factoryPid == null ? ".cfg" : "-" + factoryPid + ".cfg";
 
         String filter = "(" + DirectoryWatcher.FILENAME + "=" + pid + suffix + ")";
-        Configuration[] configurations = FileInstall.getConfigurationAdmin().listConfigurations(filter);
+        Configuration[] configurations = getConfigurationAdmin().listConfigurations(filter);
         if (configurations != null && configurations.length > 0)
         {
             return configurations[0];
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
index 2929265..21092c0 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
@@ -48,49 +48,38 @@
  * fragment).
  * 
  */
-public class FileInstall implements BundleActivator, ManagedServiceFactory
+public class FileInstall implements BundleActivator
 {
     static ServiceTracker padmin;
     static ServiceTracker startLevel;
-    static ServiceTracker cmTracker;
+    static Runnable cmSupport;
     static List /* <ArtifactListener> */ listeners = new ArrayList /* <ArtifactListener> */();
     BundleContext context;
     Map watchers = new HashMap();
-    ConfigInstaller configInstaller;
     ServiceTracker listenersTracker;
 
     public void start(BundleContext context) throws Exception
     {
         this.context = context;
         addListener(new BundleTransformer());
+
         Hashtable props = new Hashtable();
-        props.put(Constants.SERVICE_PID, getName());
-        context.registerService(ManagedServiceFactory.class.getName(), this, props);
-        props = new Hashtable();
         props.put("url.handler.protocol", JarDirUrlHandler.PROTOCOL);
         context.registerService(org.osgi.service.url.URLStreamHandlerService.class.getName(), new JarDirUrlHandler(), props);
 
+        try
+        {
+            cmSupport = new ConfigAdminSupport(context, this);
+        }
+        catch (NoClassDefFoundError e)
+        {
+            Util.log(context, 0, "ConfigAdmin is not available, some features will be disabled", e);
+        }
+
         padmin = new ServiceTracker(context, PackageAdmin.class.getName(), null);
         padmin.open();
         startLevel = new ServiceTracker(context, StartLevel.class.getName(), null);
         startLevel.open();
-        cmTracker = new ServiceTracker(context, ConfigurationAdmin.class.getName(), null)
-        {
-            public Object addingService(ServiceReference serviceReference)
-            {
-                ConfigurationAdmin cm = (ConfigurationAdmin) super.addingService(serviceReference);
-                configInstaller = new ConfigInstaller(context);
-                addListener(configInstaller);
-                return cm;
-            }
-            public void removedService(ServiceReference serviceReference, Object o)
-            {
-                configInstaller = null;
-                removeListener(configInstaller);
-                super.removedService(serviceReference, o);
-            }
-        };
-        cmTracker.open();
         String flt = "(|(" + Constants.OBJECTCLASS + "=" + ArtifactInstaller.class.getName() + ")"
                      + "(" + Constants.OBJECTCLASS + "=" + ArtifactTransformer.class.getName() + ")"
                      + "(" + Constants.OBJECTCLASS + "=" + ArtifactUrlTransformer.class.getName() + "))";
@@ -140,10 +129,13 @@
     public void stop(BundleContext context) throws Exception
     {
         List /*<DirectoryWatcher>*/ toClose = new ArrayList /*<DirectoryWatcher>*/();
-        synchronized (watchers)
+        if (watchers != null)
         {
-            toClose.addAll(watchers.values());
-            watchers.clear();
+            synchronized (watchers)
+            {
+                toClose.addAll(watchers.values());
+                watchers.clear();
+            }
         }
         for (Iterator w = toClose.iterator(); w.hasNext();)
         {
@@ -157,9 +149,18 @@
                 // Ignore
             }
         }
-        listenersTracker.close();
-        cmTracker.close();
-        padmin.close();
+        if (listenersTracker != null)
+        {
+            listenersTracker.close();
+        }
+        if (cmSupport != null)
+        {
+            cmSupport.run();
+        }
+        if (padmin != null)
+        {
+            padmin.close();
+        }
     }
 
     public void deleted(String pid)
@@ -175,13 +176,7 @@
         }
     }
 
-    public String getName()
-    {
-        return "org.apache.felix.fileinstall";
-    }
-
     public void updated(String pid, Dictionary properties)
-        throws ConfigurationException
     {
         deleted(pid);
         Util.performSubstitution(properties);    
@@ -270,21 +265,64 @@
         }
     }
 
-    static ConfigurationAdmin getConfigurationAdmin()
+    private static class ConfigAdminSupport implements Runnable
     {
-        return getConfigurationAdmin(10000);
-    }
+        private Tracker tracker;
 
-    static ConfigurationAdmin getConfigurationAdmin(long timeout)
-    {
-        try
+        private ConfigAdminSupport(BundleContext context, FileInstall fileInstall)
         {
-            return (ConfigurationAdmin) cmTracker.waitForService(timeout);
+            tracker = new Tracker(context, fileInstall);
+            Hashtable props = new Hashtable();
+            props.put(Constants.SERVICE_PID, tracker.getName());
+            context.registerService(ManagedServiceFactory.class.getName(), this, props);
+            tracker.open();
         }
-        catch (InterruptedException e)
+
+        public void run()
         {
-            Thread.currentThread().interrupt();
-            return null;
+            tracker.close();
+        }
+
+        private class Tracker extends ServiceTracker implements ManagedServiceFactory {
+
+            private final FileInstall fileInstall;
+            private ConfigInstaller configInstaller;
+
+            private Tracker(BundleContext bundleContext, FileInstall fileInstall)
+            {
+                super(bundleContext, ConfigurationAdmin.class.getName(), null);
+                this.fileInstall = fileInstall;
+            }
+
+            public String getName()
+            {
+                return "org.apache.felix.fileinstall";
+            }
+
+            public void updated(String s, Dictionary dictionary) throws ConfigurationException
+            {
+                fileInstall.updated(s, dictionary);
+            }
+
+            public void deleted(String s)
+            {
+                fileInstall.deleted(s);
+            }
+
+            public Object addingService(ServiceReference serviceReference)
+            {
+                ConfigurationAdmin cm = (ConfigurationAdmin) super.addingService(serviceReference);
+                configInstaller = new ConfigInstaller(context, cm);
+                fileInstall.addListener(configInstaller);
+                return cm;
+            }
+
+            public void removedService(ServiceReference serviceReference, Object o)
+            {
+                configInstaller = null;
+                fileInstall.removeListener(configInstaller);
+                super.removedService(serviceReference, o);
+            }
         }
     }
 
diff --git a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/ConfigInstallerTest.java b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/ConfigInstallerTest.java
index 035a896..9794744 100644
--- a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/ConfigInstallerTest.java
+++ b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/ConfigInstallerTest.java
@@ -63,7 +63,7 @@
     public void testParsePidWithoutFactoryPid()
     {
         mockBundleContextControl.replay();
-        ConfigInstaller ci = new ConfigInstaller(null);
+        ConfigInstaller ci = new ConfigInstaller(null, null);
 
         String path = "pid.cfg";
         assertEquals( "Pid without Factory Pid calculated", "pid", ci.parsePid( path )[0] );
@@ -74,7 +74,7 @@
     public void testParsePidWithFactoryPid()
     {
         mockBundleContextControl.replay();
-        ConfigInstaller ci = new ConfigInstaller(null);
+        ConfigInstaller ci = new ConfigInstaller(null, null);
 
         String path = "factory-pid.cfg";
         assertEquals( "Pid with Factory Pid calculated", "factory", ci.parsePid( path )[0] );
@@ -90,13 +90,9 @@
         mockConfigurationAdmin.createFactoryConfiguration( "pid", null );
         mockConfigurationAdminControl.setReturnValue( mockConfiguration );
         mockConfigurationAdminControl.replay();
-        mockBundleContext.createFilter( "" );
-        mockBundleContextControl.setMatcher( MockControl.ALWAYS_MATCHER );
-        mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
 
-        FileInstall.cmTracker = new MockServiceTracker( mockBundleContext, mockConfigurationAdmin );
-        ConfigInstaller ci = new ConfigInstaller( mockBundleContext );
+        ConfigInstaller ci = new ConfigInstaller( mockBundleContext, mockConfigurationAdmin );
 
         assertEquals( "Factory configuration retrieved", mockConfiguration, ci.getConfiguration( "pid", "factoryPid" ) );
 
@@ -115,13 +111,9 @@
         mockConfigurationAdmin.createFactoryConfiguration( "pid", null );
         mockConfigurationAdminControl.setReturnValue( mockConfiguration );
         mockConfigurationAdminControl.replay();
-        mockBundleContext.createFilter( "" );
-        mockBundleContextControl.setMatcher( MockControl.ALWAYS_MATCHER );
-        mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
 
-        FileInstall.cmTracker = new MockServiceTracker( mockBundleContext, mockConfigurationAdmin );
-        ConfigInstaller ci = new ConfigInstaller( mockBundleContext );
+        ConfigInstaller ci = new ConfigInstaller( mockBundleContext, mockConfigurationAdmin );
 
         assertEquals( "Factory configuration retrieved", mockConfiguration, ci.getConfiguration( "pid", "factoryPid" ) );
 
@@ -140,13 +132,9 @@
         mockConfigurationAdmin.getConfiguration( "pid", null );
         mockConfigurationAdminControl.setReturnValue( mockConfiguration );
         mockConfigurationAdminControl.replay();
-        mockBundleContext.createFilter( "" );
-        mockBundleContextControl.setMatcher( MockControl.ALWAYS_MATCHER );
-        mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
 
-        FileInstall.cmTracker = new MockServiceTracker( mockBundleContext, mockConfigurationAdmin );
-        ConfigInstaller ci = new ConfigInstaller( mockBundleContext );
+        ConfigInstaller ci = new ConfigInstaller( mockBundleContext, mockConfigurationAdmin );
 
         assertEquals( "Factory configuration retrieved", mockConfiguration, ci.getConfiguration( "pid", null ) );
 
@@ -166,13 +154,9 @@
         mockConfigurationAdmin.getConfiguration( "pid", null );
         mockConfigurationAdminControl.setReturnValue( mockConfiguration );
         mockConfigurationAdminControl.replay();
-        mockBundleContext.createFilter( "" );
-        mockBundleContextControl.setMatcher( MockControl.ALWAYS_MATCHER );
-        mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
 
-        FileInstall.cmTracker = new MockServiceTracker( mockBundleContext, mockConfigurationAdmin );
-        ConfigInstaller ci = new ConfigInstaller( mockBundleContext );
+        ConfigInstaller ci = new ConfigInstaller( mockBundleContext, mockConfigurationAdmin );
 
         assertTrue( ci.deleteConfig( new File( "pid.cfg" ) ) );
 
@@ -207,13 +191,9 @@
         mockConfigurationAdmin.getConfiguration( "firstcfg", null );
         mockConfigurationAdminControl.setReturnValue( mockConfiguration );
         mockConfigurationAdminControl.replay();
-        mockBundleContext.createFilter( "" );
-        mockBundleContextControl.setMatcher( MockControl.ALWAYS_MATCHER );
-        mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
 
-        FileInstall.cmTracker = new MockServiceTracker( mockBundleContext, mockConfigurationAdmin );
-        ConfigInstaller ci = new ConfigInstaller( mockBundleContext );
+        ConfigInstaller ci = new ConfigInstaller( mockBundleContext, mockConfigurationAdmin );
 
         assertTrue( ci.setConfig( new File( "src/test/resources/watched/firstcfg.cfg" ) ) );