FELIX-1555: The osgi:list command should print spring-dm bundle state if spring-dm has been deployed
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@812501 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/gshell/gshell-osgi/pom.xml b/karaf/gshell/gshell-osgi/pom.xml
index a455c56..2ef8131 100644
--- a/karaf/gshell/gshell-osgi/pom.xml
+++ b/karaf/gshell/gshell-osgi/pom.xml
@@ -48,6 +48,17 @@
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-core</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-extender</artifactId>
+ <optional>true</optional>
+ </dependency>
</dependencies>
<build>
@@ -63,8 +74,12 @@
org.osgi.service.command,
org.apache.felix.gogo.commands,
org.apache.felix.karaf.gshell.console,
+ org.springframework*;resolution:=optional,
*
</Import-Package>
+ <DynamicImport-Package>
+ org.springframework.*
+ </DynamicImport-Package>
<Private-Package>!*</Private-Package>
<_versionpolicy>${bnd.version.policy}</_versionpolicy>
</instructions>
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BlueprintListener.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BlueprintListener.java
index b80c3d3..7da1a74 100644
--- a/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BlueprintListener.java
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BlueprintListener.java
@@ -32,7 +32,9 @@
* TODO: use event admin to receive WAIT topics notifications from blueprint extender
*
*/
-public class BlueprintListener implements org.osgi.service.blueprint.container.BlueprintListener, BundleListener {
+public class BlueprintListener implements org.osgi.service.blueprint.container.BlueprintListener, BundleListener,
+ BundleStateListener, BundleStateListener.Factory
+{
public static enum BlueprintState {
Unknown,
@@ -54,6 +56,22 @@
this.states = new ConcurrentHashMap<Long, BlueprintState>();
}
+ public String getName() {
+ return "Blueprint ";
+ }
+
+ public String getState(Bundle bundle) {
+ BlueprintState state = states.get(bundle.getBundleId());
+ if (state == null || bundle.getState() != Bundle.ACTIVE || state == BlueprintState.Unknown) {
+ return null;
+ }
+ return state.toString();
+ }
+
+ public BundleStateListener getListener() {
+ return this;
+ }
+
public BlueprintState getBlueprintState(Bundle bundle) {
BlueprintState state = states.get(bundle.getBundleId());
if (state == null || bundle.getState() != Bundle.ACTIVE) {
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BundleStateListener.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BundleStateListener.java
new file mode 100644
index 0000000..3f5116c
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/BundleStateListener.java
@@ -0,0 +1,33 @@
+/*
+ * 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.felix.karaf.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+
+public interface BundleStateListener {
+
+ public interface Factory {
+
+ BundleStateListener getListener();
+
+ }
+
+ String getName();
+
+ String getState(Bundle bundle);
+
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/ListBundles.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/ListBundles.java
index 426403c..564c234 100644
--- a/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/ListBundles.java
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/ListBundles.java
@@ -16,6 +16,8 @@
*/
package org.apache.felix.karaf.gshell.osgi;
+import java.util.List;
+
import org.apache.felix.karaf.gshell.console.OsgiCommandSupport;
import org.apache.felix.gogo.commands.Option;
import org.apache.felix.gogo.commands.Command;
@@ -37,14 +39,10 @@
@Option(name = "-u", description = "Show update")
boolean showUpdate;
- private BlueprintListener blueprintListener;
+ private List<BundleStateListener.Factory> bundleStateListenerFactories;
- public BlueprintListener getBlueprintListener() {
- return blueprintListener;
- }
-
- public void setBlueprintListener(BlueprintListener blueprintListener) {
- this.blueprintListener = blueprintListener;
+ public void setBundleStateListenerFactories(List<BundleStateListener.Factory> bundleStateListenerFactories) {
+ this.bundleStateListenerFactories = bundleStateListenerFactories;
}
protected Object doExecute() throws Exception {
@@ -85,7 +83,15 @@
msg = " Update location";
}
String level = (sl == null) ? "" : " Level ";
- System.out.println(" ID State Blueprint " + level + msg);
+ String headers = " ID State ";
+ for (BundleStateListener.Factory factory : bundleStateListenerFactories) {
+ BundleStateListener listener = factory.getListener();
+ if (listener != null) {
+ headers += " " + listener.getName() + " ";
+ }
+ }
+ headers += level + msg;
+ System.out.println(headers);
for (int i = 0; i < bundles.length; i++) {
// Get the bundle name or location.
String name = (String) bundles[i].getHeaders().get(Constants.BUNDLE_NAME);
@@ -124,10 +130,16 @@
while (id.length() < 4) {
id = " " + id;
}
- System.out.println("[" + id + "] ["
- + getStateString(bundles[i])
- + "] [" + getBlueprintStateString(bundles[i])
- + "] [" + level + "] " + name);
+ String line = "[" + id + "] [" + getStateString(bundles[i]) + "]";
+ for (BundleStateListener.Factory factory : bundleStateListenerFactories) {
+ BundleStateListener listener = factory.getListener();
+ if (listener != null) {
+ String state = listener.getState(bundles[i]);
+ line += " [" + getStateString(state, listener.getName().length()) + "]";
+ }
+ }
+ line += " [" + level + "] " + name;
+ System.out.println(line);
if (admin != null) {
Bundle[] fragments = admin.getFragments(bundles[i]);
@@ -190,25 +202,13 @@
}
}
- public String getBlueprintStateString(Bundle bundle) {
- BlueprintListener.BlueprintState state = blueprintListener.getBlueprintState(bundle);
- switch (state) {
- case Creating:
- return "Creating ";
- case Created:
- return "Created ";
- case Destroying:
- return "Destroying ";
- case Destroyed:
- return "Destroyed ";
- case Failure:
- return "Failure ";
- case GracePeriod:
- return "GracePeriod";
- case Waiting:
- return "Waiting ";
- default:
- return " ";
+ public String getStateString(String state, int length) {
+ if (state == null) {
+ state = "";
}
+ while (state.length() < length) {
+ state += " ";
+ }
+ return state;
}
}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/SpringStateListenerFactory.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/SpringStateListenerFactory.java
new file mode 100644
index 0000000..d394658
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/felix/karaf/gshell/osgi/SpringStateListenerFactory.java
@@ -0,0 +1,149 @@
+/*
+ * 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.felix.karaf.gshell.osgi;
+
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.springframework.osgi.context.event.OsgiBundleApplicationContextListener;
+import org.springframework.osgi.context.event.OsgiBundleApplicationContextEvent;
+import org.springframework.osgi.context.event.OsgiBundleContextFailedEvent;
+import org.springframework.osgi.context.event.OsgiBundleContextRefreshedEvent;
+import org.springframework.osgi.extender.event.BootstrappingDependencyEvent;
+import org.springframework.osgi.service.importer.event.OsgiServiceDependencyEvent;
+import org.springframework.osgi.service.importer.event.OsgiServiceDependencyWaitStartingEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class SpringStateListenerFactory implements BundleStateListener.Factory {
+
+ private BundleContext bundleContext;
+ private BundleStateListener listener;
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public void destroy() throws Exception {
+ if (listener instanceof Destroyable) {
+ ((Destroyable) listener).destroy();
+ }
+ }
+
+ public BundleStateListener getListener() {
+ if (listener == null) {
+ listener = createListener();
+ }
+ return listener;
+ }
+
+ private BundleStateListener createListener() {
+ try {
+ return new SpringApplicationListener(bundleContext);
+ } catch (Throwable t) {
+ return null;
+ }
+ }
+
+ public static interface Destroyable {
+
+ public void destroy() throws Exception;
+
+ }
+
+ public static class SpringApplicationListener implements OsgiBundleApplicationContextListener,
+ BundleListener, Destroyable, BundleStateListener {
+
+ public static enum SpringState {
+ Unknown,
+ Waiting,
+ Started,
+ Failed,
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(BlueprintListener.class);
+
+ private final Map<Long, SpringState> states;
+ private BundleContext bundleContext;
+ private ServiceRegistration registration;
+
+ public SpringApplicationListener(BundleContext bundleContext) {
+ this.states = new ConcurrentHashMap<Long, SpringState>();
+ this.bundleContext = bundleContext;
+ this.bundleContext.addBundleListener(this);
+ this.registration = this.bundleContext.registerService(OsgiBundleApplicationContextListener.class.getName(), this, new Hashtable());
+ }
+
+ public void destroy() throws Exception {
+ bundleContext.removeBundleListener(this);
+ registration.unregister();
+ }
+
+ public String getName() {
+ return "Spring ";
+ }
+
+ public String getState(Bundle bundle) {
+ SpringState state = states.get(bundle.getBundleId());
+ if (state == null || bundle.getState() != Bundle.ACTIVE || state == SpringState.Unknown) {
+ return null;
+ }
+ return state.toString();
+ }
+
+ public SpringState getSpringState(Bundle bundle) {
+ SpringState state = states.get(bundle.getBundleId());
+ if (state == null || bundle.getState() != Bundle.ACTIVE) {
+ state = SpringState.Unknown;
+ }
+ return state;
+ }
+
+ public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
+ SpringState state = null;
+ if (event instanceof BootstrappingDependencyEvent) {
+ OsgiServiceDependencyEvent de = ((BootstrappingDependencyEvent) event).getDependencyEvent();
+ if (de instanceof OsgiServiceDependencyWaitStartingEvent) {
+ state = SpringState.Waiting;
+ }
+ } else if (event instanceof OsgiBundleContextFailedEvent) {
+ state = SpringState.Failed;
+ } else if (event instanceof OsgiBundleContextRefreshedEvent) {
+ state = SpringState.Started;
+ }
+ if (state != null) {
+ LOG.debug("Spring app state changed to " + state + " for bundle " + event.getBundle().getBundleId());
+ states.put(event.getBundle().getBundleId(), state);
+ }
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ if (event.getType() == BundleEvent.UNINSTALLED) {
+ states.remove(event.getBundle().getBundleId());
+ }
+ }
+
+ }
+
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/OSGI-INF/blueprint/gshell-osgi.xml b/karaf/gshell/gshell-osgi/src/main/resources/OSGI-INF/blueprint/gshell-osgi.xml
index 8dcc553..9cb7c40 100644
--- a/karaf/gshell/gshell-osgi/src/main/resources/OSGI-INF/blueprint/gshell-osgi.xml
+++ b/karaf/gshell/gshell-osgi/src/main/resources/OSGI-INF/blueprint/gshell-osgi.xml
@@ -31,7 +31,12 @@
</command>
<command name="osgi/list">
<action class="org.apache.felix.karaf.gshell.osgi.ListBundles">
- <property name="blueprintListener" ref="blueprintListener"/>
+ <property name="bundleStateListenerFactories">
+ <list xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <ref component-id="blueprintListener" />
+ <ref component-id="springListener" />
+ </list>
+ </property>
</action>
</command>
<command name="osgi/ls">
@@ -67,7 +72,10 @@
</command-bundle>
<bean id="blueprintListener" class="org.apache.felix.karaf.gshell.osgi.BlueprintListener" />
-
<service ref="blueprintListener" interface="org.osgi.service.blueprint.container.BlueprintListener" />
+ <bean id="springListener" class="org.apache.felix.karaf.gshell.osgi.SpringStateListenerFactory" destroy-method="destroy">
+ <property name="bundleContext" ref="blueprintBundleContext" />
+ </bean>
+
</blueprint>
\ No newline at end of file