You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/03/24 17:32:09 UTC

[11/24] git commit: [KARAF-2833] Make deployer/* independent of blueprint

[KARAF-2833] Make deployer/* independent of blueprint


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/7373515e
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/7373515e
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/7373515e

Branch: refs/heads/master
Commit: 7373515e77fc9ab19e32526dcb7c545af471c5d6
Parents: 60c0f82
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Sun Mar 23 15:50:16 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Mon Mar 24 17:30:13 2014 +0100

----------------------------------------------------------------------
 .../standard/src/main/feature/feature.xml       |  19 ++-
 deployer/blueprint/pom.xml                      |   7 +-
 .../deployer/blueprint/osgi/Activator.java      |  59 ++++++++
 .../OSGI-INF/blueprint/blueprint-deployer.xml   |  40 -----
 deployer/features/pom.xml                       |  10 +-
 .../features/FeatureDeploymentListener.java     |   2 +-
 .../karaf/deployer/features/osgi/Activator.java | 147 +++++++++++++++++++
 .../OSGI-INF/blueprint/features-deployer.xml    |  47 ------
 deployer/kar/pom.xml                            |  18 ++-
 .../karaf/deployer/kar/osgi/Activator.java      |  81 ++++++++++
 .../OSGI-INF/blueprint/kar-deployer.xml         |  34 -----
 deployer/spring/pom.xml                         |   7 +-
 .../karaf/deployer/spring/osgi/Activator.java   |  59 ++++++++
 .../OSGI-INF/blueprint/spring-deployer.xml      |  40 -----
 deployer/wrap/pom.xml                           |   8 +-
 .../karaf/deployer/wrap/osgi/Activator.java     |  74 ++++++++++
 .../OSGI-INF/blueprint/wrap-deployer.xml        |  30 ----
 .../util/tracker/SingleServiceTracker.java      |  40 +++--
 18 files changed, 491 insertions(+), 231 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/assemblies/features/standard/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml
index 8979b32..4d49c44 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -96,11 +96,20 @@
     </feature>
 
     <feature name="deployer" description="Karaf Deployer" version="${project.version}">
-        <feature version="${project.version}">aries-blueprint</feature>
-        <bundle start="true" start-level="24">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/${project.version}</bundle>
-        <bundle start="true" start-level="24">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.blueprint/${project.version}</bundle>
         <bundle start="true" start-level="24">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.wrap/${project.version}</bundle>
         <bundle start="true" start-level="26">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.features/${project.version}</bundle>
+        <conditional>
+            <condition>aries-blueprint</condition>
+            <bundle start="true" start-level="24">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.blueprint/${project.version}</bundle>
+        </conditional>
+        <conditional>
+            <condition>spring</condition>
+            <bundle start="true" start-level="24">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/${project.version}</bundle>
+        </conditional>
+        <conditional>
+            <condition>kar</condition>
+            <bundle start="true" start-level="24">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.kar/${project.version}</bundle>
+        </conditional>
     </feature>
 
     <!-- NB: this file is not the one really used. This file is used by the karaf-maven-plugin to define the start-level of bundles in the generated feature.xml -->
@@ -205,10 +214,6 @@
     <feature name="kar" description="Provide KAR (KARaf archive) support" version="${project.version}" resolver="(obr)">
         <bundle start-level="30">mvn:org.apache.karaf.kar/org.apache.karaf.kar.core/${project.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.kar/org.apache.karaf.kar.command/${project.version}</bundle>
-        <conditional>
-            <condition>deployer</condition>
-            <bundle start-level="30">mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.kar/${project.version}</bundle>
-        </conditional>
     </feature>
 
     <feature name="webconsole" description="Base support of the Karaf WebConsole" version="${project.version}" resolver="(obr)">

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/blueprint/pom.xml
----------------------------------------------------------------------
diff --git a/deployer/blueprint/pom.xml b/deployer/blueprint/pom.xml
index ef21812..c04c571 100644
--- a/deployer/blueprint/pom.xml
+++ b/deployer/blueprint/pom.xml
@@ -88,14 +88,15 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <!-- Set the blueprint.graceperiod flag to false to allow the bundle to start
-                             See the blueprint config file -->
-                        <Bundle-SymbolicName>${project.artifactId};blueprint.graceperiod:=false</Bundle-SymbolicName>
                         <Export-Package />
                         <Private-Package>
                             org.apache.karaf.deployer.blueprint,
+                            org.apache.karaf.deployer.blueprint.osgi,
                             org.apache.karaf.util
                         </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.deployer.blueprint.osgi.Activator
+                        </Bundle-Activator>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/blueprint/src/main/java/org/apache/karaf/deployer/blueprint/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/deployer/blueprint/src/main/java/org/apache/karaf/deployer/blueprint/osgi/Activator.java b/deployer/blueprint/src/main/java/org/apache/karaf/deployer/blueprint/osgi/Activator.java
new file mode 100644
index 0000000..96057bb
--- /dev/null
+++ b/deployer/blueprint/src/main/java/org/apache/karaf/deployer/blueprint/osgi/Activator.java
@@ -0,0 +1,59 @@
+/**
+ *
+ * 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.karaf.deployer.blueprint.osgi;
+
+import java.util.Hashtable;
+
+import org.apache.felix.fileinstall.ArtifactListener;
+import org.apache.felix.fileinstall.ArtifactUrlTransformer;
+import org.apache.karaf.deployer.blueprint.BlueprintDeploymentListener;
+import org.apache.karaf.deployer.blueprint.BlueprintURLHandler;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.url.URLStreamHandlerService;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration urlHandlerRegistration;
+    private ServiceRegistration urlTransformerRegistration;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        Hashtable<String, Object> props = new Hashtable<String, Object>();
+        props.put("url.handler.protocol", "blueprint");
+        urlHandlerRegistration = context.registerService(
+                URLStreamHandlerService.class,
+                new BlueprintURLHandler(),
+                props);
+
+        urlTransformerRegistration = context.registerService(
+                new String[] {
+                        ArtifactUrlTransformer.class.getName(),
+                        ArtifactListener.class.getName()
+                },
+                new BlueprintDeploymentListener(),
+                null);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        urlTransformerRegistration.unregister();
+        urlHandlerRegistration.unregister();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint-deployer.xml
----------------------------------------------------------------------
diff --git a/deployer/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint-deployer.xml b/deployer/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint-deployer.xml
deleted file mode 100644
index 8f94e4c..0000000
--- a/deployer/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint-deployer.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" default-activation="lazy">
-
-    <service id="blueprintUrlHandler" interface="org.osgi.service.url.URLStreamHandlerService">
-        <service-properties>
-            <entry key="url.handler.protocol" value="blueprint"/>
-        </service-properties>
-        <bean class="org.apache.karaf.deployer.blueprint.BlueprintURLHandler"/>
-    </service>
-
-    <bean id="blueprintDeploymentListener" class="org.apache.karaf.deployer.blueprint.BlueprintDeploymentListener"/>
-
-    <!-- Force a reference to the url handler above from the bundles registry to (try to) make sure
-         the url handler is registered inside the framework.  Else we can run into timing issues
-         where fileinstall will use the featureDeploymentListener before the url can be actually
-         used.  In order to not block the bundle, the blueprint.graceperiod=false flag must be
-         set on the SymbolicName bundles header -->
-    <reference id="blueprintUrlHandlerRef" interface="org.osgi.service.url.URLStreamHandlerService" filter="url.handler.protocol=blueprint" />
-
-    <service ref="blueprintDeploymentListener" auto-export="interfaces" depends-on="blueprintDeploymentListener" />
-
-</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/features/pom.xml
----------------------------------------------------------------------
diff --git a/deployer/features/pom.xml b/deployer/features/pom.xml
index ebcbed1..93cb36a 100644
--- a/deployer/features/pom.xml
+++ b/deployer/features/pom.xml
@@ -91,14 +91,16 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <!-- Set the blueprint.graceperiod flag to false to allow the bundle to start
-                             See the blueprint config file -->
-                        <Bundle-SymbolicName>${project.artifactId};blueprint.graceperiod:=false</Bundle-SymbolicName>
                         <Export-Package />
                         <Private-Package>
                             org.apache.karaf.deployer.features,
-                            org.apache.karaf.util
+                            org.apache.karaf.deployer.features.osgi,
+                            org.apache.karaf.util,
+                            org.apache.karaf.util.tracker
                         </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.deployer.features.osgi.Activator
+                        </Bundle-Activator>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/features/src/main/java/org/apache/karaf/deployer/features/FeatureDeploymentListener.java
----------------------------------------------------------------------
diff --git a/deployer/features/src/main/java/org/apache/karaf/deployer/features/FeatureDeploymentListener.java b/deployer/features/src/main/java/org/apache/karaf/deployer/features/FeatureDeploymentListener.java
index 1ef86c3..5f95daa 100644
--- a/deployer/features/src/main/java/org/apache/karaf/deployer/features/FeatureDeploymentListener.java
+++ b/deployer/features/src/main/java/org/apache/karaf/deployer/features/FeatureDeploymentListener.java
@@ -98,7 +98,7 @@ public class FeatureDeploymentListener implements ArtifactUrlTransformer, Bundle
         }
     }
 
-    public void destroy() throws Exception {
+    public void destroy() {
         bundleContext.removeBundleListener(this);
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/features/src/main/java/org/apache/karaf/deployer/features/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/deployer/features/src/main/java/org/apache/karaf/deployer/features/osgi/Activator.java b/deployer/features/src/main/java/org/apache/karaf/deployer/features/osgi/Activator.java
new file mode 100644
index 0000000..51f9725
--- /dev/null
+++ b/deployer/features/src/main/java/org/apache/karaf/deployer/features/osgi/Activator.java
@@ -0,0 +1,147 @@
+/**
+ *
+ * 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.karaf.deployer.features.osgi;
+
+import java.util.Hashtable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.felix.fileinstall.ArtifactListener;
+import org.apache.felix.fileinstall.ArtifactUrlTransformer;
+import org.apache.karaf.deployer.features.FeatureDeploymentListener;
+import org.apache.karaf.deployer.features.FeatureURLHandler;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.url.URLStreamHandlerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator, SingleServiceTracker.SingleServiceListener {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(Activator.class);
+
+    private ExecutorService executor = Executors.newSingleThreadExecutor();
+    private AtomicBoolean scheduled = new AtomicBoolean();
+    private BundleContext bundleContext;
+    private ServiceRegistration urlHandlerRegistration;
+    private ServiceRegistration urlTransformerRegistration;
+    private SingleServiceTracker<FeaturesService> featuresServiceTracker;
+    private FeatureDeploymentListener listener;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        bundleContext = context;
+        scheduled.set(true);
+
+        featuresServiceTracker = new SingleServiceTracker<FeaturesService>(
+                context, FeaturesService.class, this);
+        featuresServiceTracker.open();
+
+        scheduled.set(false);
+        reconfigure();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        featuresServiceTracker.close();
+        executor.shutdown();
+        executor.awaitTermination(30, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void serviceFound() {
+        reconfigure();
+    }
+
+    @Override
+    public void serviceLost() {
+        reconfigure();
+    }
+
+    @Override
+    public void serviceReplaced() {
+        reconfigure();
+    }
+
+    protected void reconfigure() {
+        if (scheduled.compareAndSet(false, true)) {
+            executor.submit(new Runnable() {
+                @Override
+                public void run() {
+                    scheduled.set(false);
+                    doStop();
+                    try {
+                        doStart();
+                    } catch (Exception e) {
+                        LOGGER.warn("Error starting features deployer", e);
+                        doStop();
+                    }
+                }
+            });
+        }
+    }
+
+    protected void doStart() throws Exception {
+        FeaturesService service = featuresServiceTracker.getService();
+        if (service == null) {
+            return;
+        }
+
+        Hashtable<String, Object> props = new Hashtable<String, Object>();
+        props.put("url.handler.protocol", "feature");
+        FeatureURLHandler handler = new FeatureURLHandler();
+        urlHandlerRegistration = bundleContext.registerService(
+                URLStreamHandlerService.class,
+                handler,
+                props);
+
+        listener = new FeatureDeploymentListener();
+        listener.setFeaturesService(service);
+        listener.setBundleContext(bundleContext);
+        listener.init();
+
+        urlTransformerRegistration = bundleContext.registerService(
+                new String[] {
+                        ArtifactUrlTransformer.class.getName(),
+                        ArtifactListener.class.getName()
+                },
+                listener,
+                null);
+    }
+
+    protected void doStop() {
+        if (urlTransformerRegistration != null) {
+            urlTransformerRegistration.unregister();
+            urlTransformerRegistration = null;
+        }
+        if (urlHandlerRegistration != null) {
+            urlHandlerRegistration.unregister();
+            urlHandlerRegistration = null;
+        }
+        if (listener != null) {
+            listener.destroy();
+            listener = null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml
----------------------------------------------------------------------
diff --git a/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml b/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml
deleted file mode 100644
index 40585cc..0000000
--- a/deployer/features/src/main/resources/OSGI-INF/blueprint/features-deployer.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           default-activation="lazy">
-
-    <service id="featureUrlHandler" interface="org.osgi.service.url.URLStreamHandlerService">
-    	<service-properties>
-            <entry key="url.handler.protocol" value="feature"/>
-        </service-properties>
-        <bean class="org.apache.karaf.deployer.features.FeatureURLHandler"/>
-    </service>
-
-    <bean id="featureDeploymentListener" class="org.apache.karaf.deployer.features.FeatureDeploymentListener"
-          init-method="init" destroy-method="destroy" activation="lazy">
-        <property name="bundleContext" ref="blueprintBundleContext"/>
-        <property name="featuresService">
-            <reference interface="org.apache.karaf.features.FeaturesService"/>
-        </property>
-    </bean>
-
-    <!-- Force a reference to the url handler above from the bundles registry to (try to) make sure
-         the url handler is registered inside the framework.  Else we can run into timing issues
-         where fileinstall will use the featureDeploymentListener before the url can be actually
-         used.  In order to not block the bundle, the blueprint.graceperiod=false flag must be
-         set on the SymbolicName bundles header -->
-    <reference id="featureUrlHandlerRef" interface="org.osgi.service.url.URLStreamHandlerService" filter="url.handler.protocol=feature" />
-
-    <service ref="featureDeploymentListener" auto-export="interfaces" depends-on="featureUrlHandlerRef"/>
-
-</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/kar/pom.xml
----------------------------------------------------------------------
diff --git a/deployer/kar/pom.xml b/deployer/kar/pom.xml
index 607a89b..7b6d26b 100644
--- a/deployer/kar/pom.xml
+++ b/deployer/kar/pom.xml
@@ -60,6 +60,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.fileinstall</artifactId>
             <scope>provided</scope>
@@ -88,11 +94,15 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <!-- Set the blueprint.graceperiod flag to false to allow the bundle to start
-                             See the blueprint config file -->
-                        <Bundle-SymbolicName>${project.artifactId};blueprint.graceperiod:=false</Bundle-SymbolicName>
                         <Export-Package />
-                        <Private-Package>org.apache.karaf.deployer.kar</Private-Package>
+                        <Private-Package>
+                            org.apache.karaf.deployer.kar,
+                            org.apache.karaf.deployer.kar.osgi,
+                            org.apache.karaf.util.tracker
+                        </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.deployer.kar.osgi.Activator
+                        </Bundle-Activator>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/osgi/Activator.java b/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/osgi/Activator.java
new file mode 100644
index 0000000..1b5038f
--- /dev/null
+++ b/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/osgi/Activator.java
@@ -0,0 +1,81 @@
+/**
+ *
+ * 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.karaf.deployer.kar.osgi;
+
+import java.util.Hashtable;
+
+import org.apache.felix.fileinstall.ArtifactInstaller;
+import org.apache.felix.fileinstall.ArtifactListener;
+import org.apache.karaf.deployer.kar.KarArtifactInstaller;
+import org.apache.karaf.kar.KarService;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator, SingleServiceTracker.SingleServiceListener {
+
+    private BundleContext bundleContext;
+    private ServiceRegistration urlTransformerRegistration;
+    private SingleServiceTracker<KarService> karServiceTracker;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        bundleContext = context;
+        karServiceTracker = new SingleServiceTracker<KarService>(
+                context, KarService.class, this);
+        karServiceTracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        karServiceTracker.close();
+    }
+
+    @Override
+    public void serviceFound() {
+        KarService service = karServiceTracker.getService();
+        if (urlTransformerRegistration == null && service != null) {
+            KarArtifactInstaller installer = new KarArtifactInstaller();
+            installer.setKarService(service);
+            Hashtable<String, Object> props = new Hashtable<String, Object>();
+            urlTransformerRegistration = bundleContext.registerService(
+                    new String[] {
+                            ArtifactInstaller.class.getName(),
+                            ArtifactListener.class.getName()
+                    },
+                    installer,
+                    null);
+        }
+    }
+
+    @Override
+    public void serviceLost() {
+        if (urlTransformerRegistration != null) {
+            urlTransformerRegistration.unregister();
+            urlTransformerRegistration = null;
+        }
+    }
+
+    @Override
+    public void serviceReplaced() {
+        serviceLost();
+        serviceFound();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/kar/src/main/resources/OSGI-INF/blueprint/kar-deployer.xml
----------------------------------------------------------------------
diff --git a/deployer/kar/src/main/resources/OSGI-INF/blueprint/kar-deployer.xml b/deployer/kar/src/main/resources/OSGI-INF/blueprint/kar-deployer.xml
deleted file mode 100644
index 7095a31..0000000
--- a/deployer/kar/src/main/resources/OSGI-INF/blueprint/kar-deployer.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-	<!--
-
-		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.
-	-->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-	xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
-	default-activation="lazy">
-
-	<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]" />
-	
-	<bean id="karArtifactInstaller" class="org.apache.karaf.deployer.kar.KarArtifactInstaller" activation="lazy">
-	        <property name="karService">
-	            <reference interface="org.apache.karaf.kar.KarService"/>
-	        </property>
-	</bean>
-			
-	<service id="karArtifactInstallerService" 
-		ref="karArtifactInstaller"
-		auto-export="interfaces"/>
-
-</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/spring/pom.xml
----------------------------------------------------------------------
diff --git a/deployer/spring/pom.xml b/deployer/spring/pom.xml
index 8f73714..f5427b8 100644
--- a/deployer/spring/pom.xml
+++ b/deployer/spring/pom.xml
@@ -92,14 +92,15 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <!-- Set the blueprint.graceperiod flag to false to allow the bundle to start
-                             See the blueprint config file -->
-                        <Bundle-SymbolicName>${project.artifactId};blueprint.graceperiod:=false</Bundle-SymbolicName>
                         <Export-Package />
                         <Private-Package>
                             org.apache.karaf.deployer.spring,
+                            org.apache.karaf.deployer.spring.osgi,
                             org.apache.karaf.util
                         </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.deployer.spring.osgi.Activator
+                        </Bundle-Activator>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/spring/src/main/java/org/apache/karaf/deployer/spring/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/deployer/spring/src/main/java/org/apache/karaf/deployer/spring/osgi/Activator.java b/deployer/spring/src/main/java/org/apache/karaf/deployer/spring/osgi/Activator.java
new file mode 100644
index 0000000..146928b
--- /dev/null
+++ b/deployer/spring/src/main/java/org/apache/karaf/deployer/spring/osgi/Activator.java
@@ -0,0 +1,59 @@
+/**
+ *
+ * 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.karaf.deployer.spring.osgi;
+
+import java.util.Hashtable;
+
+import org.apache.felix.fileinstall.ArtifactListener;
+import org.apache.felix.fileinstall.ArtifactUrlTransformer;
+import org.apache.karaf.deployer.spring.SpringDeploymentListener;
+import org.apache.karaf.deployer.spring.SpringURLHandler;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.url.URLStreamHandlerService;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration urlHandlerRegistration;
+    private ServiceRegistration urlTransformerRegistration;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        Hashtable<String, Object> props = new Hashtable<String, Object>();
+        props.put("url.handler.protocol", "spring");
+        urlHandlerRegistration = context.registerService(
+                URLStreamHandlerService.class,
+                new SpringURLHandler(),
+                props);
+
+        urlTransformerRegistration = context.registerService(
+                new String[] {
+                        ArtifactUrlTransformer.class.getName(),
+                        ArtifactListener.class.getName()
+                },
+                new SpringDeploymentListener(),
+                null);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        urlTransformerRegistration.unregister();
+        urlHandlerRegistration.unregister();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/spring/src/main/resources/OSGI-INF/blueprint/spring-deployer.xml
----------------------------------------------------------------------
diff --git a/deployer/spring/src/main/resources/OSGI-INF/blueprint/spring-deployer.xml b/deployer/spring/src/main/resources/OSGI-INF/blueprint/spring-deployer.xml
deleted file mode 100644
index e8fa854..0000000
--- a/deployer/spring/src/main/resources/OSGI-INF/blueprint/spring-deployer.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" default-activation="lazy">
-
-    <service id="springUrlHandler" interface="org.osgi.service.url.URLStreamHandlerService">
-    	<service-properties>
-            <entry key="url.handler.protocol" value="spring"/>
-        </service-properties>
-        <bean class="org.apache.karaf.deployer.spring.SpringURLHandler"/>
-    </service>
-
-    <bean id="springDeploymentListener" class="org.apache.karaf.deployer.spring.SpringDeploymentListener"/>
-
-    <!-- Force a reference to the url handler above from the bundles registry to (try to) make sure
-         the url handler is registered inside the framework.  Else we can run into timing issues
-         where fileinstall will use the featureDeploymentListener before the url can be actually
-         used.  In order to not block the bundle, the blueprint.graceperiod=false flag must be
-         set on the SymbolicName bundles header -->
-    <reference id="springUrlHandlerRef" interface="org.osgi.service.url.URLStreamHandlerService" filter="url.handler.protocol=spring" />
-
-    <service ref="springDeploymentListener" auto-export="interfaces" depends-on="springDeploymentListener" />
-
-</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/wrap/pom.xml
----------------------------------------------------------------------
diff --git a/deployer/wrap/pom.xml b/deployer/wrap/pom.xml
index 5cf0343..6777f2b 100644
--- a/deployer/wrap/pom.xml
+++ b/deployer/wrap/pom.xml
@@ -77,12 +77,16 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                         <Export-Package />
                         <Private-Package>
                             org.apache.karaf.deployer.wrap,
-                            org.apache.karaf.util
+                            org.apache.karaf.deployer.wrap.osgi,
+                            org.apache.karaf.util,
+                            org.apache.karaf.util.tracker
                         </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.deployer.wrap.osgi.Activator
+                        </Bundle-Activator>
                         <_versionpolicy>${bnd.version.policy}</_versionpolicy>
                     </instructions>
                 </configuration>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/wrap/src/main/java/org/apache/karaf/deployer/wrap/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/deployer/wrap/src/main/java/org/apache/karaf/deployer/wrap/osgi/Activator.java b/deployer/wrap/src/main/java/org/apache/karaf/deployer/wrap/osgi/Activator.java
new file mode 100644
index 0000000..4f4001b
--- /dev/null
+++ b/deployer/wrap/src/main/java/org/apache/karaf/deployer/wrap/osgi/Activator.java
@@ -0,0 +1,74 @@
+/**
+ *
+ * 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.karaf.deployer.wrap.osgi;
+
+import java.util.Hashtable;
+
+import org.apache.felix.fileinstall.ArtifactUrlTransformer;
+import org.apache.karaf.deployer.wrap.WrapDeploymentListener;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.url.URLStreamHandlerService;
+
+public class Activator implements BundleActivator, SingleServiceTracker.SingleServiceListener {
+
+    private BundleContext bundleContext;
+    private ServiceRegistration<ArtifactUrlTransformer> urlTransformerRegistration;
+    private SingleServiceTracker<URLStreamHandlerService> urlHandlerTracker;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        bundleContext = context;
+        urlHandlerTracker = new SingleServiceTracker<URLStreamHandlerService>(
+                context, URLStreamHandlerService.class,
+                "(url.handler.protocol=wrap)", this);
+        urlHandlerTracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        urlHandlerTracker.close();
+    }
+
+    @Override
+    public void serviceFound() {
+        if (urlTransformerRegistration == null) {
+            Hashtable<String, Object> props = new Hashtable<String, Object>();
+            props.put("service.ranking", -1);
+            urlTransformerRegistration = bundleContext.registerService(
+                    ArtifactUrlTransformer.class,
+                    new WrapDeploymentListener(),
+                    props);
+        }
+    }
+
+    @Override
+    public void serviceLost() {
+        if (urlTransformerRegistration != null) {
+            urlTransformerRegistration.unregister();
+            urlTransformerRegistration = null;
+        }
+    }
+
+    @Override
+    public void serviceReplaced() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/deployer/wrap/src/main/resources/OSGI-INF/blueprint/wrap-deployer.xml
----------------------------------------------------------------------
diff --git a/deployer/wrap/src/main/resources/OSGI-INF/blueprint/wrap-deployer.xml b/deployer/wrap/src/main/resources/OSGI-INF/blueprint/wrap-deployer.xml
deleted file mode 100644
index c5295a5..0000000
--- a/deployer/wrap/src/main/resources/OSGI-INF/blueprint/wrap-deployer.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           default-activation="lazy">
-
-    <bean id="wrapDeploymentListener" class="org.apache.karaf.deployer.wrap.WrapDeploymentListener"/>
-
-    <reference id="wrapUrlHandlerRef" interface="org.osgi.service.url.URLStreamHandlerService" filter="url.handler.protocol=wrap"/>
-
-    <service ref="wrapDeploymentListener" auto-export="interfaces" depends-on="wrapDeploymentListener" ranking="-1"/>
-
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/7373515e/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java b/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
index a946c48..85c6caa 100644
--- a/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
+++ b/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
@@ -20,6 +20,7 @@
 
 package org.apache.karaf.util.tracker;
 
+import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -99,25 +100,32 @@ public final class SingleServiceTracker<T> {
     }
 
     private void findMatchingReference(ServiceReference original) {
-        boolean clear = true;
-        ServiceReference ref = ctx.getServiceReference(className);
-        if (ref != null && (filter == null || filter.match(ref))) {
-            @SuppressWarnings("unchecked")
-            T service = (T) ctx.getService(ref);
-            if (service != null) {
-                clear = false;
-
-                // We do the unget out of the lock so we don't exit this class while holding a lock.
-                if (!!!update(original, ref, service)) {
-                    ctx.ungetService(ref);
+        try {
+            boolean clear = true;
+            ServiceReference[] refs = ctx.getServiceReferences(className, filterString);
+            if (refs != null && refs.length > 0) {
+                if (refs.length > 1) {
+                    Arrays.sort(refs);
+                }
+                @SuppressWarnings("unchecked")
+                T service = (T) ctx.getService(refs[0]);
+                if (service != null) {
+                    clear = false;
+
+                    // We do the unget out of the lock so we don't exit this class while holding a lock.
+                    if (!!!update(original, refs[0], service)) {
+                        ctx.ungetService(refs[0]);
+                    }
                 }
+            } else if (original == null) {
+                clear = false;
             }
-        } else if (original == null) {
-            clear = false;
-        }
 
-        if (clear) {
-            update(original, null, null);
+            if (clear) {
+                update(original, null, null);
+            }
+        } catch (InvalidSyntaxException e) {
+            // this can never happen. (famous last words :)
         }
     }