Author: thomas.diesler(a)jboss.com
Date: 2010-02-13 10:24:01 -0500 (Sat, 13 Feb 2010)
New Revision: 100935
Added:
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintEventDispatcher.java
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintInterceptor.java
Modified:
projects/jboss-osgi/projects/bundles/blueprint/trunk/pom.xml
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintActivator.java
Log:
[JBOSGI-290] Use LifecycleInterceptor with Aries Blueprint
Modified: projects/jboss-osgi/projects/bundles/blueprint/trunk/pom.xml
===================================================================
--- projects/jboss-osgi/projects/bundles/blueprint/trunk/pom.xml 2010-02-13 14:30:36 UTC
(rev 100934)
+++ projects/jboss-osgi/projects/bundles/blueprint/trunk/pom.xml 2010-02-13 15:24:01 UTC
(rev 100935)
@@ -166,6 +166,7 @@
org.jboss.logging;version="[2.1,3.0)",
+ org.jboss.osgi.deployment.interceptor;version="[1.0,2.0)",
org.jboss.osgi.spi*;version="[1.0,2.0)",
org.osgi.framework,
Modified:
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintActivator.java
===================================================================
---
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintActivator.java 2010-02-13
14:30:36 UTC (rev 100934)
+++
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintActivator.java 2010-02-13
15:24:01 UTC (rev 100935)
@@ -26,8 +26,10 @@
import org.apache.aries.blueprint.container.BlueprintExtender;
import org.jboss.logging.Logger;
import org.jboss.osgi.blueprint.BlueprintService;
+import org.jboss.osgi.deployment.interceptor.LifecycleInterceptorService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
/**
* The Blueprint activator registeres the {@link BlueprintService}
@@ -40,7 +42,8 @@
// Provide logging
private static final Logger log = Logger.getLogger(BlueprintActivator.class);
- BundleActivator ariesActivator;
+ private BundleActivator ariesActivator;
+ private BlueprintInterceptor jbossInterceptor;
public void start(BundleContext context) throws Exception
{
@@ -48,10 +51,19 @@
BlueprintService service = new BlueprintService(){};
context.registerService(BlueprintService.class.getName(), service, null);
- log.debug("Start: " + BlueprintExtender.class.getName());
-
- ariesActivator = new BlueprintExtender();
- ariesActivator.start(context);
+ ServiceReference sref =
context.getServiceReference(LifecycleInterceptorService.class.getName());
+ if (sref != null)
+ {
+ log.debug("Start: " + BlueprintInterceptor.class.getName());
+ jbossInterceptor = new BlueprintInterceptor();
+ jbossInterceptor.start(context);
+ }
+ else
+ {
+ log.debug("Start: " + BlueprintExtender.class.getName());
+ ariesActivator = new BlueprintExtender();
+ ariesActivator.start(context);
+ }
}
public void stop(BundleContext context) throws Exception
@@ -61,5 +73,10 @@
log.debug("Stop: " + ariesActivator.getClass().getName());
ariesActivator.stop(context);
}
+ else if (jbossInterceptor != null)
+ {
+ log.debug("Stop: " + jbossInterceptor.getClass().getName());
+ jbossInterceptor.stop(context);
+ }
}
}
\ No newline at end of file
Added:
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintEventDispatcher.java
===================================================================
---
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintEventDispatcher.java
(rev 0)
+++
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintEventDispatcher.java 2010-02-13
15:24:01 UTC (rev 100935)
@@ -0,0 +1,307 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.osgi.blueprint.internal;
+
+//$Id$
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.osgi.service.blueprint.container.BlueprintListener;
+import org.osgi.service.blueprint.container.EventConstants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.aries.blueprint.utils.JavaUtils;
+
+/**
+ * The delivery of {@link BlueprintEvent}s is complicated. The blueprint extender and
its containers use this class to
+ * deliver {@link BlueprintEvent}s.
+ *
+ * This is a copy of the Aries BlueprintEventDispatcher which is package protexted
+ *
+ * @version $Rev$Date: 2010-01-06 07:05:04 +0100 (Wed, 06 Jan 2010)
+ */
+class BlueprintEventDispatcher implements BlueprintListener, SynchronousBundleListener {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(BlueprintEventDispatcher.class);
+
+ private final Set<BlueprintListener> listeners = new
CopyOnWriteArraySet<BlueprintListener>();
+ private final Map<Bundle, BlueprintEvent> states = new
ConcurrentHashMap<Bundle, BlueprintEvent>();
+ private final ExecutorService executor = Executors.newSingleThreadExecutor();
+ private final ExecutorService sharedExecutor;
+ private final EventAdminListener eventAdminListener;
+ private final ServiceTracker containerListenerTracker;
+
+ BlueprintEventDispatcher(final BundleContext bundleContext, ExecutorService
sharedExecutor) {
+
+ assert bundleContext != null;
+ assert sharedExecutor != null;
+
+ this.sharedExecutor = sharedExecutor;
+
+ bundleContext.addBundleListener(this);
+
+ EventAdminListener listener = null;
+ try {
+
getClass().getClassLoader().loadClass("org.osgi.service.event.EventAdmin");
+ listener = new EventAdminListener(bundleContext);
+ } catch (Throwable t) {
+ // Ignore, if the EventAdmin package is not available, just don't use it
+ LOGGER.debug("EventAdmin package is not available, just don't use
it");
+ }
+ this.eventAdminListener = listener;
+
+ this.containerListenerTracker = new ServiceTracker(bundleContext,
BlueprintListener.class.getName(), new ServiceTrackerCustomizer() {
+ public Object addingService(ServiceReference reference) {
+ BlueprintListener listener = (BlueprintListener)
bundleContext.getService(reference);
+
+ synchronized (listeners) {
+ sendInitialEvents(listener);
+ listeners.add(listener);
+ }
+
+ return listener;
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ listeners.remove(service);
+ bundleContext.ungetService(reference);
+ }
+ });
+ this.containerListenerTracker.open();
+ }
+
+ private void sendInitialEvents(BlueprintListener listener) {
+ for (Map.Entry<Bundle, BlueprintEvent> entry : states.entrySet()) {
+ try {
+ callListener(listener, new BlueprintEvent(entry.getValue(), true));
+ } catch (RejectedExecutionException ree) {
+ LOGGER.warn("Executor shut down", ree);
+ break;
+ }
+ }
+ }
+
+ public void blueprintEvent(final BlueprintEvent event) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Sending blueprint container event {} for bundle {}",
toString(event), event.getBundle().getSymbolicName());
+ }
+
+ synchronized (listeners) {
+ callListeners(event);
+ states.put(event.getBundle(), event);
+ }
+
+ if (eventAdminListener != null) {
+ try {
+ sharedExecutor.submit(new Runnable() {
+ public void run() {
+ eventAdminListener.blueprintEvent(event);
+ }
+ });
+ } catch (RejectedExecutionException ree) {
+ LOGGER.warn("Executor shut down", ree);
+ }
+ }
+ }
+
+ @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
+ private static String toString(BlueprintEvent event) {
+ return "BlueprintEvent[type=" + getEventType(event.getType())
+ + (event.getDependencies() != null ? ", dependencies=" +
Arrays.asList(event.getDependencies()) : "")
+ + (event.getCause() != null ? ", exception=" +
event.getCause().getMessage() : "")
+ + "]";
+ }
+
+ private static String getEventType(int type) {
+ switch (type) {
+ case BlueprintEvent.CREATING:
+ return "CREATING";
+ case BlueprintEvent.CREATED:
+ return "CREATED";
+ case BlueprintEvent.DESTROYING:
+ return "DESTROYING";
+ case BlueprintEvent.DESTROYED:
+ return "DESTROYED";
+ case BlueprintEvent.FAILURE:
+ return "FAILURE";
+ case BlueprintEvent.GRACE_PERIOD:
+ return "GRACE_PERIOD";
+ case BlueprintEvent.WAITING:
+ return "WAITING";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private void callListeners(BlueprintEvent event) {
+ for (final BlueprintListener listener : listeners) {
+ try {
+ callListener(listener, event);
+ } catch (RejectedExecutionException ree) {
+ LOGGER.warn("Executor shut down", ree);
+ break;
+ }
+ }
+ }
+
+ private void callListener(final BlueprintListener listener, final BlueprintEvent
event) throws RejectedExecutionException {
+ try {
+ executor.invokeAny(Collections.<Callable<Void>>singleton(new
Callable<Void>() {
+ public Void call() throws Exception {
+ listener.blueprintEvent(event);
+ return null;
+ }
+ }), 60L, TimeUnit.SECONDS);
+ } catch (InterruptedException ie) {
+ LOGGER.warn("Thread interrupted", ie);
+ Thread.currentThread().interrupt();
+ } catch (TimeoutException te) {
+ LOGGER.warn("Listener timed out, will be ignored", te);
+ listeners.remove(listener);
+ } catch (ExecutionException ee) {
+ LOGGER.warn("Listener caused an exception, will be ignored", ee);
+ listeners.remove(listener);
+ }
+ }
+
+ void destroy() {
+ executor.shutdown();
+ // wait for the queued tasks to execute
+ try {
+ executor.awaitTermination(60, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ containerListenerTracker.close();
+ // clean up the EventAdmin tracker if we're using that
+ if (eventAdminListener != null) {
+ eventAdminListener.destroy();
+ }
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ if (BundleEvent.STOPPING == event.getType()) {
+ states.remove(event.getBundle());
+ }
+ }
+
+ private static class EventAdminListener implements BlueprintListener {
+
+ private final ServiceTracker tracker;
+
+ EventAdminListener(BundleContext context) {
+ tracker = new ServiceTracker(context, EventAdmin.class.getName(), null);
+ tracker.open();
+ }
+
+ @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
+ public void blueprintEvent(BlueprintEvent event) {
+ EventAdmin eventAdmin = (EventAdmin) tracker.getService();
+ if (eventAdmin == null) {
+ return;
+ }
+
+ Dictionary<String, Object> props = new Hashtable<String,
Object>();
+ props.put(EventConstants.TYPE, event.getType());
+ props.put(EventConstants.EVENT, event);
+ props.put(EventConstants.TIMESTAMP, event.getTimestamp());
+ props.put(EventConstants.BUNDLE, event.getBundle());
+ props.put(EventConstants.BUNDLE_SYMBOLICNAME,
event.getBundle().getSymbolicName());
+ props.put(EventConstants.BUNDLE_ID, event.getBundle().getBundleId());
+ props.put(EventConstants.BUNDLE_VERSION,
JavaUtils.getBundleVersion(event.getBundle()));
+ props.put(EventConstants.EXTENDER_BUNDLE, event.getExtenderBundle());
+ props.put(EventConstants.EXTENDER_BUNDLE_ID,
event.getExtenderBundle().getBundleId());
+ props.put(EventConstants.EXTENDER_BUNDLE_SYMBOLICNAME,
event.getExtenderBundle().getSymbolicName());
+ props.put(EventConstants.EXTENDER_BUNDLE_VERSION,
JavaUtils.getBundleVersion(event.getExtenderBundle()));
+
+ if (event.getCause() != null) {
+ props.put(EventConstants.CAUSE, event.getCause());
+ }
+ if (event.getDependencies() != null) {
+ props.put(EventConstants.DEPENDENCIES, event.getDependencies());
+ }
+ String topic;
+ switch (event.getType()) {
+ case BlueprintEvent.CREATING:
+ topic = EventConstants.TOPIC_CREATING;
+ break;
+ case BlueprintEvent.CREATED:
+ topic = EventConstants.TOPIC_CREATED;
+ break;
+ case BlueprintEvent.DESTROYING:
+ topic = EventConstants.TOPIC_DESTROYING;
+ break;
+ case BlueprintEvent.DESTROYED:
+ topic = EventConstants.TOPIC_DESTROYED;
+ break;
+ case BlueprintEvent.FAILURE:
+ topic = EventConstants.TOPIC_FAILURE;
+ break;
+ case BlueprintEvent.GRACE_PERIOD:
+ topic = EventConstants.TOPIC_GRACE_PERIOD;
+ break;
+ case BlueprintEvent.WAITING:
+ topic = EventConstants.TOPIC_WAITING;
+ break;
+ default:
+ throw new IllegalStateException("Unknown blueprint event type:
" + event.getType());
+ }
+ eventAdmin.postEvent(new Event(topic, props));
+ }
+
+ /**
+ * Perform cleanup at Blueprint extender shutdown.
+ */
+ public void destroy() {
+ tracker.close();
+ }
+
+ }
+}
Property changes on:
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintEventDispatcher.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added:
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintInterceptor.java
===================================================================
---
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintInterceptor.java
(rev 0)
+++
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintInterceptor.java 2010-02-13
15:24:01 UTC (rev 100935)
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.osgi.blueprint.internal;
+
+//$Id$
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.apache.aries.blueprint.BlueprintConstants;
+import org.apache.aries.blueprint.container.BlueprintContainerImpl;
+import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
+import org.apache.aries.blueprint.namespace.NamespaceHandlerRegistryImpl;
+import org.jboss.osgi.deployment.interceptor.AbstractLifecycleInterceptor;
+import org.jboss.osgi.deployment.interceptor.InvocationContext;
+import org.jboss.osgi.deployment.interceptor.LifecycleInterceptor;
+import org.jboss.osgi.deployment.interceptor.LifecycleInterceptorException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Blueprint interceptor
+ *
+ * @author thomas.diesler(a)jboss.com
+ * @since 20-Oct-2009
+ */
+public class BlueprintInterceptor extends AbstractLifecycleInterceptor implements
LifecycleInterceptor
+{
+ // Provide logging
+ private Logger log = LoggerFactory.getLogger(BlueprintInterceptor.class);
+
+ private Map<Bundle, BlueprintContainerImpl> containers;
+ private BlueprintEventDispatcher eventDispatcher;
+ private NamespaceHandlerRegistry handlers;
+ private ScheduledExecutorService executors;
+
+ public void start(BundleContext context)
+ {
+ containers = new HashMap<Bundle, BlueprintContainerImpl>();
+ handlers = new NamespaceHandlerRegistryImpl(context);
+ executors = Executors.newScheduledThreadPool(3);
+ eventDispatcher = new BlueprintEventDispatcher(context, executors);
+
+ context.registerService(LifecycleInterceptor.class.getName(), this, null);
+ }
+
+ public void stop(BundleContext context)
+ {
+ for (Bundle bundle : containers.keySet())
+ {
+ BlueprintContainerImpl blueprintContainer = containers.remove(bundle);
+ blueprintContainer.destroy();
+ }
+ }
+
+ public void invoke(int state, InvocationContext context) throws
LifecycleInterceptorException
+ {
+ Bundle bundle = context.getBundle();
+ if (state == Bundle.STARTING)
+ {
+ // If a Bundle-Blueprint manifest header is defined, then this header contains a
list of paths.
+ // If this header is not defined, then resources ending in .xml in the bundle’s
+ // OSGI-INF/blueprint directory must be used. These are the resources that
+ // would be found by calling the Bundle
findEntries("OSGI-INF/blueprint", "*.xml", false) method.
+
+ List<Object> pathList = new ArrayList<Object>();
+
+ String descriptorPaths =
(String)bundle.getHeaders().get(BlueprintConstants.BUNDLE_BLUEPRINT_HEADER);
+ if (descriptorPaths != null)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(descriptorPaths,
",");
+ while (tokenizer.hasMoreTokens())
+ {
+ String path = tokenizer.nextToken();
+ pathList.add(path.trim());
+ }
+ }
+ else
+ {
+ Enumeration<?> foundEntries =
bundle.findEntries("OSGI-INF/blueprint", "*.xml", false);
+ if (foundEntries != null)
+ {
+ while (foundEntries.hasMoreElements())
+ {
+ String path = foundEntries.nextElement().toString();
+ int index = path.indexOf("OSGI-INF/blueprint");
+ pathList.add(path.substring(index));
+ }
+ }
+ }
+
+ if (pathList.isEmpty() == false)
+ {
+ log.debug("Create blueprint container");
+ BlueprintContainerImpl blueprintContainer = new
BlueprintContainerImpl(bundle.getBundleContext(), context.getBundle(), eventDispatcher,
handlers, executors, pathList);
+ containers.put(bundle, blueprintContainer);
+ blueprintContainer.schedule();
+ }
+ }
+ else if (state == Bundle.STOPPING)
+ {
+ BlueprintContainerImpl blueprintContainer = containers.remove(bundle);
+ if (blueprintContainer != null)
+ {
+ log.debug("Stop blueprint container");
+ blueprintContainer.destroy();
+ }
+ }
+ }
+}
\ No newline at end of file
Property changes on:
projects/jboss-osgi/projects/bundles/blueprint/trunk/src/main/java/org/jboss/osgi/blueprint/internal/BlueprintInterceptor.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF