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:02 UTC

[04/24] git commit: [KARAF-2833] Make bundle/core independent of blueprint

[KARAF-2833] Make bundle/core 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/766e7dd2
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/766e7dd2
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/766e7dd2

Branch: refs/heads/master
Commit: 766e7dd2ee38df0cb1c519a684931764135a9179
Parents: ae10408
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Mar 21 18:14:19 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Mon Mar 24 17:30:12 2014 +0100

----------------------------------------------------------------------
 .../standard/src/main/feature/feature.xml       |   5 +-
 bundle/blueprintstate/pom.xml                   | 101 ++++++++++
 .../state/blueprint/internal/Activator.java     |  44 +++++
 .../internal/BlueprintStateService.java         | 140 ++++++++++++++
 .../karaf/bundle/command/ListServicesTest.java  |   2 +-
 bundle/core/pom.xml                             |   5 +
 .../bundle/core/internal/BlueprintListener.java | 140 --------------
 .../bundle/core/internal/BundleServiceImpl.java |  14 +-
 .../bundle/core/internal/osgi/Activator.java    | 192 +++++++++++++++++++
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  66 -------
 bundle/pom.xml                                  |   1 +
 .../bundle/state/spring/internal/Activator.java |  18 +-
 .../spring/internal/SpringStateService.java     |   3 +-
 pom.xml                                         |   5 +
 14 files changed, 512 insertions(+), 224 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/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 b334606..0bfb302 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -61,6 +61,10 @@
         <bundle start-level="20">mvn:org.apache.aries.blueprint/org.apache.aries.blueprint.cm/${aries.blueprint.cm.version}</bundle>
         <bundle start-level="20">mvn:org.apache.aries.blueprint/org.apache.aries.blueprint.core.compatibility/${aries.blueprint.core.compatibility.version}</bundle>
         <bundle start-level="20">mvn:org.apache.aries.blueprint/org.apache.aries.blueprint.core/${aries.blueprint.core.version}</bundle>
+        <conditional>
+            <condition>bundle</condition>
+            <bundle start-level="30">mvn:org.apache.karaf.bundle/org.apache.karaf.bundle.blueprintstate/${project.version}</bundle>
+        </conditional>
     </feature>
 
     <feature name="aries-annotation" description="Aries Annotations" version="${project.version}">
@@ -121,7 +125,6 @@
     </feature>
 
     <feature name="bundle" description="Provide Bundle support" version="${project.version}">
-        <feature version="${project.version}">aries-blueprint</feature>
         <bundle start-level="30" start="true">mvn:org.apache.karaf.bundle/org.apache.karaf.bundle.core/${project.version}</bundle>
         <bundle start-level="30" start="true">mvn:org.apache.karaf.bundle/org.apache.karaf.bundle.command/${project.version}</bundle>
     </feature>

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/blueprintstate/pom.xml
----------------------------------------------------------------------
diff --git a/bundle/blueprintstate/pom.xml b/bundle/blueprintstate/pom.xml
new file mode 100644
index 0000000..b3c0449
--- /dev/null
+++ b/bundle/blueprintstate/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf.bundle</groupId>
+        <artifactId>bundle</artifactId>
+        <version>3.1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.karaf.bundle.blueprintstate</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Bundle :: BlueprintStateService</name>
+    <description>Provide State Support for Blueprint bundles</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.karaf.bundle</groupId>
+            <artifactId>org.apache.karaf.bundle.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+		<dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.aries.blueprint</groupId>
+            <artifactId>org.apache.aries.blueprint.api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.apache.karaf.bundle.state.blueprint.internal.Activator</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/Activator.java
----------------------------------------------------------------------
diff --git a/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/Activator.java b/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/Activator.java
new file mode 100644
index 0000000..6f44143
--- /dev/null
+++ b/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/Activator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.bundle.state.blueprint.internal;
+
+import org.apache.karaf.bundle.core.BundleStateService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.blueprint.container.BlueprintListener;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration registration;
+
+    public void start(BundleContext bundleContext) {
+        BlueprintStateService service = new BlueprintStateService();
+	    String[] classes = new String[] {
+                BlueprintListener.class.getName(),
+				BundleStateService.class.getName(),
+                BundleListener.class.getName()
+			};
+        registration = bundleContext.registerService(classes, service, null);
+	}
+
+    public void stop(BundleContext context) {
+        registration.unregister();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/BlueprintStateService.java
----------------------------------------------------------------------
diff --git a/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/BlueprintStateService.java b/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/BlueprintStateService.java
new file mode 100644
index 0000000..89fde18
--- /dev/null
+++ b/bundle/blueprintstate/src/main/java/org/apache/karaf/bundle/state/blueprint/internal/BlueprintStateService.java
@@ -0,0 +1,140 @@
+/*
+ * 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.bundle.state.blueprint.internal;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.karaf.bundle.core.BundleState;
+import org.apache.karaf.bundle.core.BundleStateService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO: use event instance to receive WAIT topics notifications from blueprint
+ * extender
+ */
+public class BlueprintStateService implements org.osgi.service.blueprint.container.BlueprintListener, BundleListener,
+    BundleStateService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BlueprintStateService.class);
+
+    private final Map<Long, BlueprintEvent> states;
+
+    public BlueprintStateService() {
+        states = new ConcurrentHashMap<Long, BlueprintEvent>();
+    }
+
+    @Override
+    public String getName() {
+        return BundleStateService.NAME_BLUEPRINT;
+    }
+
+    @Override
+    public String getDiag(Bundle bundle) {
+        BlueprintEvent event = states.get(bundle.getBundleId());
+        if (event == null) {
+            return null;
+        }
+        if (event.getType() != BlueprintEvent.FAILURE && event.getType() != BlueprintEvent.GRACE_PERIOD
+            && event.getType() != BlueprintEvent.WAITING) {
+            return null;
+        }
+        StringBuilder message = new StringBuilder();
+        Date date = new Date(event.getTimestamp());
+        SimpleDateFormat df = new SimpleDateFormat();
+        message.append(df.format(date) + "\n");
+        if (event.getCause() != null) {
+            message.append("Exception: \n");
+            addMessages(message, event.getCause());
+        }
+        if (event.getDependencies() != null) {
+            message.append("Missing dependencies: \n");
+            for (String dep : event.getDependencies()) {
+                message.append(dep + " ");
+            }
+            message.append("\n");
+        }
+        return message.toString();
+    }
+
+    public void addMessages(StringBuilder message, Throwable ex) {
+        message.append(ex.getMessage());
+        message.append("\n");
+        StringWriter errorWriter = new StringWriter();
+        ex.printStackTrace(new PrintWriter(errorWriter));
+        message.append(errorWriter.toString());
+        message.append("\n");
+    }
+
+    @Override
+    public BundleState getState(Bundle bundle) {
+        BlueprintEvent event = states.get(bundle.getBundleId());
+        BundleState state = getState(event);
+        return (bundle.getState() != Bundle.ACTIVE) ? BundleState.Unknown : state;
+    }
+
+    @Override
+    public void blueprintEvent(BlueprintEvent blueprintEvent) {
+        if (LOG.isDebugEnabled()) {
+            BundleState state = getState(blueprintEvent);
+            LOG.debug("Blueprint app state changed to " + state + " for bundle "
+                      + blueprintEvent.getBundle().getBundleId());
+        }
+        states.put(blueprintEvent.getBundle().getBundleId(), blueprintEvent);
+    }
+
+    @Override
+    public void bundleChanged(BundleEvent event) {
+        if (event.getType() == BundleEvent.UNINSTALLED) {
+            states.remove(event.getBundle().getBundleId());
+        }
+    }
+
+    private BundleState getState(BlueprintEvent blueprintEvent) {
+        if (blueprintEvent == null) {
+            return BundleState.Unknown;
+        }
+        switch (blueprintEvent.getType()) {
+        case BlueprintEvent.CREATING:
+            return BundleState.Starting;
+        case BlueprintEvent.CREATED:
+            return BundleState.Active;
+        case BlueprintEvent.DESTROYING:
+            return BundleState.Stopping;
+        case BlueprintEvent.DESTROYED:
+            return BundleState.Resolved;
+        case BlueprintEvent.FAILURE:
+            return BundleState.Failure;
+        case BlueprintEvent.GRACE_PERIOD:
+            return BundleState.GracePeriod;
+        case BlueprintEvent.WAITING:
+            return BundleState.Waiting;
+        default:
+            return BundleState.Unknown;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java b/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
index 2c25a44..876f605 100644
--- a/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
+++ b/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
@@ -32,7 +32,7 @@ public class ListServicesTest {
         listServices = new ListBundleServices();
         BundleContext bundleContext = new TestBundleFactory().createBundleContext();
         listServices.setBundleContext(bundleContext);
-        listServices.setBundleService(new BundleServiceImpl(bundleContext, Collections.EMPTY_LIST));
+        listServices.setBundleService(new BundleServiceImpl(bundleContext));
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/core/pom.xml
----------------------------------------------------------------------
diff --git a/bundle/core/pom.xml b/bundle/core/pom.xml
index dbcd62a..2d73be4 100644
--- a/bundle/core/pom.xml
+++ b/bundle/core/pom.xml
@@ -112,10 +112,15 @@
                         </Export-Package>
                         <Private-Package>
                             org.apache.karaf.bundle.core.internal,
+                            org.apache.karaf.bundle.core.internal.osgi,
                             org.apache.karaf.util.maven,
+                            org.apache.karaf.util.tracker,
                             org.apache.felix.utils.version,
                             org.apache.felix.utils.manifest
                         </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.bundle.core.internal.osgi.Activator
+                        </Bundle-Activator>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BlueprintListener.java
----------------------------------------------------------------------
diff --git a/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BlueprintListener.java b/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BlueprintListener.java
deleted file mode 100644
index 9840924..0000000
--- a/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BlueprintListener.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.bundle.core.internal;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.karaf.bundle.core.BundleState;
-import org.apache.karaf.bundle.core.BundleStateService;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.BundleListener;
-import org.osgi.service.blueprint.container.BlueprintEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * TODO: use event instance to receive WAIT topics notifications from blueprint
- * extender
- */
-public class BlueprintListener implements org.osgi.service.blueprint.container.BlueprintListener, BundleListener,
-    BundleStateService {
-
-    private static final Logger LOG = LoggerFactory.getLogger(BlueprintListener.class);
-
-    private final Map<Long, BlueprintEvent> states;
-
-    public BlueprintListener() {
-        states = new ConcurrentHashMap<Long, BlueprintEvent>();
-    }
-
-    @Override
-    public String getName() {
-        return BundleStateService.NAME_BLUEPRINT;
-    }
-
-    @Override
-    public String getDiag(Bundle bundle) {
-        BlueprintEvent event = states.get(bundle.getBundleId());
-        if (event == null) {
-            return null;
-        }
-        if (event.getType() != BlueprintEvent.FAILURE && event.getType() != BlueprintEvent.GRACE_PERIOD
-            && event.getType() != BlueprintEvent.WAITING) {
-            return null;
-        }
-        StringBuilder message = new StringBuilder();
-        Date date = new Date(event.getTimestamp());
-        SimpleDateFormat df = new SimpleDateFormat();
-        message.append(df.format(date) + "\n");
-        if (event.getCause() != null) {
-            message.append("Exception: \n");
-            addMessages(message, event.getCause());
-        }
-        if (event.getDependencies() != null) {
-            message.append("Missing dependencies: \n");
-            for (String dep : event.getDependencies()) {
-                message.append(dep + " ");
-            }
-            message.append("\n");
-        }
-        return message.toString();
-    }
-
-    public void addMessages(StringBuilder message, Throwable ex) {
-        message.append(ex.getMessage());
-        message.append("\n");
-        StringWriter errorWriter = new StringWriter();
-        ex.printStackTrace(new PrintWriter(errorWriter));
-        message.append(errorWriter.toString());
-        message.append("\n");
-    }
-
-    @Override
-    public BundleState getState(Bundle bundle) {
-        BlueprintEvent event = states.get(bundle.getBundleId());
-        BundleState state = getState(event);
-        return (bundle.getState() != Bundle.ACTIVE) ? BundleState.Unknown : state;
-    }
-
-    @Override
-    public void blueprintEvent(BlueprintEvent blueprintEvent) {
-        if (LOG.isDebugEnabled()) {
-            BundleState state = getState(blueprintEvent);
-            LOG.debug("Blueprint app state changed to " + state + " for bundle "
-                      + blueprintEvent.getBundle().getBundleId());
-        }
-        states.put(blueprintEvent.getBundle().getBundleId(), blueprintEvent);
-    }
-
-    @Override
-    public void bundleChanged(BundleEvent event) {
-        if (event.getType() == BundleEvent.UNINSTALLED) {
-            states.remove(event.getBundle().getBundleId());
-        }
-    }
-
-    private BundleState getState(BlueprintEvent blueprintEvent) {
-        if (blueprintEvent == null) {
-            return BundleState.Unknown;
-        }
-        switch (blueprintEvent.getType()) {
-        case BlueprintEvent.CREATING:
-            return BundleState.Starting;
-        case BlueprintEvent.CREATED:
-            return BundleState.Active;
-        case BlueprintEvent.DESTROYING:
-            return BundleState.Stopping;
-        case BlueprintEvent.DESTROYED:
-            return BundleState.Resolved;
-        case BlueprintEvent.FAILURE:
-            return BundleState.Failure;
-        case BlueprintEvent.GRACE_PERIOD:
-            return BundleState.GracePeriod;
-        case BlueprintEvent.WAITING:
-            return BundleState.Waiting;
-        default:
-            return BundleState.Unknown;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BundleServiceImpl.java
----------------------------------------------------------------------
diff --git a/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BundleServiceImpl.java b/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BundleServiceImpl.java
index f908a26..fbf047f 100644
--- a/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BundleServiceImpl.java
+++ b/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/BundleServiceImpl.java
@@ -26,6 +26,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.karaf.bundle.core.BundleInfo;
 import org.apache.karaf.bundle.core.BundleService;
@@ -54,11 +55,18 @@ public class BundleServiceImpl implements BundleService {
     private static final String ORIGINAL_WIRES = "Original-Wires";
 
     private final BundleContext bundleContext;
-    private final List<BundleStateService> stateServices;
+    private final List<BundleStateService> stateServices = new CopyOnWriteArrayList<BundleStateService>();
 
-    public BundleServiceImpl(BundleContext bundleContext, List<BundleStateService> stateServices) {
+    public BundleServiceImpl(BundleContext bundleContext) {
         this.bundleContext = bundleContext;
-        this.stateServices = stateServices;
+    }
+
+    public void registerBundleStateService(BundleStateService service) {
+        stateServices.add(service);
+    }
+
+    public void unregisterBundleStateService(BundleStateService service) {
+        stateServices.remove(service);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/osgi/Activator.java b/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/osgi/Activator.java
new file mode 100644
index 0000000..df3899e
--- /dev/null
+++ b/bundle/core/src/main/java/org/apache/karaf/bundle/core/internal/osgi/Activator.java
@@ -0,0 +1,192 @@
+/*
+ * 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.bundle.core.internal.osgi;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.NotCompliantMBeanException;
+
+import org.apache.karaf.bundle.core.BundleService;
+import org.apache.karaf.bundle.core.BundleStateService;
+import org.apache.karaf.bundle.core.BundleWatcher;
+import org.apache.karaf.bundle.core.internal.BundleServiceImpl;
+import org.apache.karaf.bundle.core.internal.BundleWatcherImpl;
+import org.apache.karaf.bundle.core.internal.BundlesMBeanImpl;
+import org.apache.karaf.bundle.core.internal.MavenConfigService;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+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 BundleContext bundleContext;
+    private SingleServiceTracker<ConfigurationAdmin> configurationAdminTracker;
+    private ServiceTracker<BundleStateService, BundleStateService> bundleStateServicesTracker;
+
+    private BundleWatcherImpl bundleWatcher;
+    private ServiceRegistration<BundleWatcher> bundleWatcherRegistration;
+    private ServiceRegistration<BundleService> bundleServiceRegistration;
+    private ServiceRegistration bundleServiceMBeanRegistration;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        bundleContext = context;
+        configurationAdminTracker = new SingleServiceTracker<ConfigurationAdmin>(
+                bundleContext, ConfigurationAdmin.class, this
+        );
+        configurationAdminTracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        configurationAdminTracker.close();
+        executor.shutdown();
+        executor.awaitTermination(30, TimeUnit.SECONDS);
+    }
+
+    protected void doStart() {
+        ConfigurationAdmin configurationAdmin = configurationAdminTracker.getService();
+
+        if (configurationAdmin == null) {
+            return;
+        }
+
+        final BundleServiceImpl bundleService = new BundleServiceImpl(bundleContext);
+        bundleServiceRegistration = bundleContext.registerService(BundleService.class, bundleService, null);
+        bundleStateServicesTracker = new ServiceTracker<BundleStateService, BundleStateService>(
+                bundleContext, BundleStateService.class, new ServiceTrackerCustomizer<BundleStateService, BundleStateService>() {
+            @Override
+            public BundleStateService addingService(ServiceReference<BundleStateService> reference) {
+                BundleStateService service = bundleContext.getService(reference);
+                bundleService.registerBundleStateService(service);
+                return service;
+            }
+            @Override
+            public void modifiedService(ServiceReference<BundleStateService> reference, BundleStateService service) {
+            }
+            @Override
+            public void removedService(ServiceReference<BundleStateService> reference, BundleStateService service) {
+                bundleService.unregisterBundleStateService(service);
+                bundleContext.ungetService(reference);
+            }
+        }
+        );
+        bundleStateServicesTracker.open();
+
+        bundleWatcher = new BundleWatcherImpl(bundleContext, new MavenConfigService(configurationAdmin), bundleService);
+        bundleWatcher.start();
+        bundleWatcherRegistration = bundleContext.registerService(BundleWatcher.class, bundleWatcher, null);
+
+        try {
+            BundlesMBeanImpl bundlesMBeanImpl = new BundlesMBeanImpl(bundleContext, bundleService);
+            Hashtable<String, Object> props = new Hashtable<String, Object>();
+            props.put("jmx.objectname", "org.apache.karaf:type=bundle,name=" + System.getProperty("karaf.name"));
+            bundleServiceMBeanRegistration = bundleContext.registerService(
+                    getInterfaceNames(bundlesMBeanImpl),
+                    bundlesMBeanImpl,
+                    props
+            );
+        } catch (NotCompliantMBeanException e) {
+            LOGGER.warn("Error creating FeaturesService mbean", e);
+        }
+    }
+
+    protected void doStop() {
+        if (bundleStateServicesTracker != null) {
+            bundleStateServicesTracker.close();
+            bundleStateServicesTracker = null;
+        }
+        if (bundleWatcher != null) {
+            bundleWatcher.stop();
+            bundleWatcher = null;
+        }
+        if (bundleServiceMBeanRegistration != null) {
+            bundleServiceMBeanRegistration.unregister();
+            bundleServiceMBeanRegistration = null;
+        }
+        if (bundleServiceRegistration != null) {
+            bundleServiceRegistration.unregister();
+            bundleServiceRegistration = null;
+        }
+        if (bundleWatcherRegistration != null) {
+            bundleWatcherRegistration.unregister();
+            bundleWatcherRegistration = null;
+        }
+        if (bundleWatcher != null) {
+            bundleWatcher.stop();
+            bundleWatcher = null;
+        }
+    }
+
+    @Override
+    public void serviceFound() {
+        executor.submit(new Runnable() {
+            @Override
+            public void run() {
+                doStop();
+                try {
+                    doStart();
+                } catch (Exception e) {
+                    LOGGER.warn("Error starting FeaturesService", e);
+                    doStop();
+                }
+            }
+        });
+    }
+
+    @Override
+    public void serviceLost() {
+        serviceFound();
+    }
+
+    @Override
+    public void serviceReplaced() {
+        serviceFound();
+    }
+
+    private String[] getInterfaceNames(Object object) {
+        List<String> names = new ArrayList<String>();
+        for (Class cl = object.getClass(); cl != Object.class; cl = cl.getSuperclass()) {
+            addSuperInterfaces(names, cl);
+        }
+        return names.toArray(new String[names.size()]);
+    }
+
+    private void addSuperInterfaces(List<String> names, Class clazz) {
+        for (Class cl : clazz.getInterfaces()) {
+            names.add(cl.getName());
+            addSuperInterfaces(names, cl);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/bundle/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/bundle/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
deleted file mode 100644
index e0512d8..0000000
--- a/bundle/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ /dev/null
@@ -1,66 +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">
-
-    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
-    
-    <reference id="configurationAdmin" interface="org.osgi.service.cm.ConfigurationAdmin"/>
-    <reference-list id="bundleStateServices" interface="org.apache.karaf.bundle.core.BundleStateService" availability="optional" />
-
-    <bean id="bundleService" class="org.apache.karaf.bundle.core.internal.BundleServiceImpl">
-        <argument ref="blueprintBundleContext"/>
-        <argument ref="bundleStateServices"/>
-    </bean>
-
-    <bean id="blueprintListener" class="org.apache.karaf.bundle.core.internal.BlueprintListener" />
-
-
-    <bean id="bundlesMBean" class="org.apache.karaf.bundle.core.internal.BundlesMBeanImpl">
-        <argument ref="blueprintBundleContext" />
-        <argument ref="bundleService" />
-    </bean>
-
-    <bean id="watcher" class="org.apache.karaf.bundle.core.internal.BundleWatcherImpl" init-method="start" destroy-method="stop">
-        <argument ref="blueprintBundleContext"/>
-        <argument ref="mavenConfigService"/>
-        <argument ref="bundleService"/>
-    </bean>
-
-    <bean id="mavenConfigService" class="org.apache.karaf.bundle.core.internal.MavenConfigService">
-        <argument ref="configurationAdmin"/>
-    </bean>
-
-    <service ref="blueprintListener">
-        <interfaces>
-            <value>org.osgi.service.blueprint.container.BlueprintListener</value>
-            <value>org.osgi.framework.BundleListener</value>
-            <value>org.apache.karaf.bundle.core.BundleStateService</value>
-        </interfaces>
-    </service>
-    <service interface="org.apache.karaf.bundle.core.BundleService" ref="bundleService"/>
-    <service ref="bundlesMBean" auto-export="interfaces">
-         <service-properties>
-              <entry key="jmx.objectname" value="org.apache.karaf:type=bundle,name=$[karaf.name]"/>
-          </service-properties>
-    </service>
-    <service ref="watcher" interface="org.apache.karaf.bundle.core.BundleWatcher"/>
-
-</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/pom.xml
----------------------------------------------------------------------
diff --git a/bundle/pom.xml b/bundle/pom.xml
index ec6178d..925102d 100644
--- a/bundle/pom.xml
+++ b/bundle/pom.xml
@@ -36,6 +36,7 @@
     <modules>
         <module>core</module>
         <module>command</module>
+        <module>blueprintstate</module>
         <module>springstate</module>
     </modules>
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/Activator.java
----------------------------------------------------------------------
diff --git a/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/Activator.java b/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/Activator.java
index 2845a56..09a4949 100644
--- a/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/Activator.java
+++ b/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/Activator.java
@@ -16,31 +16,27 @@
  */
 package org.apache.karaf.bundle.state.spring.internal;
 
-import java.util.Dictionary;
-import java.util.Hashtable;
-
 import org.apache.karaf.bundle.core.BundleStateService;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
 import org.springframework.osgi.context.event.OsgiBundleApplicationContextListener;
 
 public class Activator implements BundleActivator {
 
-    public void start(BundleContext bundleContext) {
-	    registerSpringBundleStateService(bundleContext);
-    }
+    private ServiceRegistration registration;
 
-	private void registerSpringBundleStateService(BundleContext bundleContext) {
-		SpringStateService springStateService = new SpringStateService(bundleContext);
-	    Dictionary<String, ?> properties = new Hashtable<String, String>();
-	    String[] classes2 = new String[] {
+    public void start(BundleContext bundleContext) {
+		SpringStateService services = new SpringStateService();
+	    String[] classes = new String[] {
 				OsgiBundleApplicationContextListener.class.getName(),
 				BundleStateService.class.getName()
 			};
-	    bundleContext.registerService(classes2, springStateService, properties);
+        registration = bundleContext.registerService(classes, services, null);
 	}
 
     public void stop(BundleContext context) {
+        registration.unregister();
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/SpringStateService.java
----------------------------------------------------------------------
diff --git a/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/SpringStateService.java b/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/SpringStateService.java
index d0ca26b..e09e6e1 100644
--- a/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/SpringStateService.java
+++ b/bundle/springstate/src/main/java/org/apache/karaf/bundle/state/spring/internal/SpringStateService.java
@@ -26,7 +26,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.apache.karaf.bundle.core.BundleState;
 import org.apache.karaf.bundle.core.BundleStateService;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.BundleListener;
 import org.slf4j.Logger;
@@ -44,7 +43,7 @@ public class SpringStateService implements OsgiBundleApplicationContextListener,
 
     private final Map<Long, OsgiBundleApplicationContextEvent> states;
 
-    public SpringStateService(BundleContext bundleContext) {
+    public SpringStateService() {
         this.states = new ConcurrentHashMap<Long, OsgiBundleApplicationContextEvent>();
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/766e7dd2/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 60fd604..7e90888 100644
--- a/pom.xml
+++ b/pom.xml
@@ -393,6 +393,11 @@
                 <artifactId>org.apache.karaf.bundle.springstate</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.karaf.bundle</groupId>
+                <artifactId>org.apache.karaf.bundle.blueprintstate</artifactId>
+                <version>${project.version}</version>
+            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.package</groupId>