SLING-1954 : Launchpad installer should not depend on SCR

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1063204 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 9bdaa82..ac8d459 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,31 +38,16 @@
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
+                        <Bundle-Activator>
+                            org.apache.sling.launchpad.installer.impl.Activator
+                        </Bundle-Activator>
                     </instructions>
                 </configuration>
             </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>generate-scr-scrdescriptor</id>
-                        <goals>
-                            <goal>scr</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
     </build>
     <dependencies>
         <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-            <version>1.4.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.launchpad.api</artifactId>
             <version>0.0.1-SNAPSHOT</version>
@@ -71,26 +56,16 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.installer.core</artifactId>
-            <version>3.0.0</version>
+            <version>3.1.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
-            <version>4.2.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-            <version>4.2.0</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
-            <version>1.5.2</version>
-            <scope>provided</scope>
         </dependency>
     </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/launchpad/installer/impl/Activator.java b/src/main/java/org/apache/sling/launchpad/installer/impl/Activator.java
new file mode 100644
index 0000000..4363e19
--- /dev/null
+++ b/src/main/java/org/apache/sling/launchpad/installer/impl/Activator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.sling.launchpad.installer.impl;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The <code>Activator</code>
+ */
+public class Activator implements BundleActivator {
+
+    /** The services listener will activate the installer. */
+    private ServicesListener servicesListener;
+
+    /**
+     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+     */
+    public void start(final BundleContext context) {
+        this.servicesListener = new ServicesListener(context);
+    }
+
+    /**
+     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+     */
+    public void stop(final BundleContext context) {
+        this.servicesListener.deactivate();
+        this.servicesListener = null;
+    }
+}
diff --git a/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadConfigInstaller.java b/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadConfigInstaller.java
index 91fa78b..82ce5c2 100644
--- a/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadConfigInstaller.java
+++ b/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadConfigInstaller.java
@@ -5,9 +5,9 @@
  * 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
@@ -21,45 +21,36 @@
 import java.util.HashSet;
 import java.util.Iterator;
 
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.sling.launchpad.api.LaunchpadContentProvider;
 import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.OsgiInstaller;
-import org.osgi.service.component.ComponentContext;
+import org.apache.sling.launchpad.api.LaunchpadContentProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Component
 public class LaunchpadConfigInstaller {
 
-    /** Resources supplied under this path by 
+    /** Resources supplied under this path by
      *  LaunchpadContentProvider are considered for installation
      */
     private static final String ROOT_CONFIG_PATH = "resources/config";
 
-    @Reference
-    private OsgiInstaller installer;
+    private static Logger LOGGER = LoggerFactory.getLogger(LaunchpadConfigInstaller.class);
 
-    @Reference
-    private LaunchpadContentProvider resourceProvider;
-
-    private Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    protected void activate(ComponentContext componentContext) {
-        logger.info("Activating launchpad config installer, resources path={}", ROOT_CONFIG_PATH);
+    public static void install(final OsgiInstaller installer,
+            final LaunchpadContentProvider resourceProvider) {
+        LOGGER.info("Activating launchpad config installer, resources path={}", ROOT_CONFIG_PATH);
         Collection<InstallableResource> installables = new HashSet<InstallableResource>();
 
         Iterator<String> configPaths = resourceProvider.getChildren(ROOT_CONFIG_PATH);
         while (configPaths.hasNext()) {
             String path = configPaths.next();
-            logger.info("Config launchpad file will be installed: {}", path);
+            LOGGER.info("Config launchpad file will be installed: {}", path);
             InputStream stream = resourceProvider.getResourceAsStream(path);
-            installables.add(new InstallableResource(path, stream, null, null, InstallableResource.TYPE_CONFIG, 0));
+            installables.add(new InstallableResource(path, stream, null, null, InstallableResource.TYPE_PROPERTIES, 0));
         }
 
         final InstallableResource [] toInstall = installables.toArray(new InstallableResource []{});
         installer.registerResources("launchpad", (toInstall));
-        logger.info("{} resources registered with OsgiInstaller", toInstall.length);
+        LOGGER.info("{} resources registered with OsgiInstaller", toInstall.length);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java b/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java
new file mode 100644
index 0000000..170c2d0
--- /dev/null
+++ b/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java
@@ -0,0 +1,135 @@
+/*
+ * 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.sling.launchpad.installer.impl;
+
+import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.launchpad.api.LaunchpadContentProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The <code>ServicesListener</code> listens for the required services
+ * and starts/stops the scanners based on the availability of the
+ * services.
+ */
+public class ServicesListener {
+
+    /** The bundle context. */
+    private final BundleContext bundleContext;
+
+    /** The listener for the installer. */
+    private final Listener installerListener;
+
+    /** The listener for the provider. */
+    private final Listener providerListener;
+
+    public ServicesListener(final BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+        this.installerListener = new Listener(OsgiInstaller.class.getName());
+        this.providerListener = new Listener(LaunchpadContentProvider.class.getName());
+        this.installerListener.start();
+        this.providerListener.start();
+    }
+
+    public synchronized void notifyChange() {
+        // check if all services are available
+        final OsgiInstaller installer = (OsgiInstaller)this.installerListener.getService();
+        final LaunchpadContentProvider lcp = (LaunchpadContentProvider)this.providerListener.getService();
+
+        if ( installer != null && lcp != null ) {
+            LaunchpadConfigInstaller.install(installer, lcp);
+        }
+    }
+
+    /**
+     * Deactivate this listener.
+     */
+    public void deactivate() {
+        this.installerListener.deactivate();
+        this.providerListener.deactivate();
+    }
+
+    protected final class Listener implements ServiceListener {
+
+        private final String serviceName;
+
+        private ServiceReference reference;
+        private Object service;
+
+        public Listener(final String serviceName) {
+            this.serviceName = serviceName;
+        }
+
+        public void start() {
+            this.retainService();
+            try {
+                bundleContext.addServiceListener(this, "("
+                        + Constants.OBJECTCLASS + "=" + serviceName + ")");
+            } catch (final InvalidSyntaxException ise) {
+                // this should really never happen
+                throw new RuntimeException("Unexpected exception occured.", ise);
+            }
+        }
+
+        public void deactivate() {
+            bundleContext.removeServiceListener(this);
+        }
+
+        public synchronized Object getService() {
+            return this.service;
+        }
+        private synchronized void retainService() {
+            if ( this.reference == null ) {
+                this.reference = bundleContext.getServiceReference(this.serviceName);
+                if ( this.reference != null ) {
+                    this.service = bundleContext.getService(this.reference);
+                    if ( this.service == null ) {
+                        this.reference = null;
+                    } else {
+                        notifyChange();
+                    }
+                }
+            }
+        }
+
+        private synchronized void releaseService() {
+            if ( this.reference != null ) {
+                this.service = null;
+                bundleContext.ungetService(this.reference);
+                this.reference = null;
+                notifyChange();
+            }
+        }
+
+        /**
+         * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+         */
+        public void serviceChanged(ServiceEvent event) {
+            if (event.getType() == ServiceEvent.REGISTERED && this.service == null ) {
+                this.retainService();
+            } else if ( event.getType() == ServiceEvent.UNREGISTERING && this.service != null ) {
+                this.releaseService();
+            }
+        }
+    }
+}