[jboss-osgi-commits] JBoss-OSGI SVN: r100935 - in projects/jboss-osgi/projects/bundles/blueprint/trunk: src/main/java/org/jboss/osgi/blueprint/internal and 1 other directory.

jboss-osgi-commits at lists.jboss.org jboss-osgi-commits at lists.jboss.org
Sat Feb 13 10:24:02 EST 2010


Author: thomas.diesler at 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 at 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



More information about the jboss-osgi-commits mailing list