aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlaf Otto2012-11-09 07:30:04 (EST)
committerGlyn Normington2012-11-09 07:31:25 (EST)
commit6976b50e76a17aaf800a60f836c6b7af46fbf483 (patch)
tree860ce05408b77a9148e309f6f10ddd673c80fc36
parent3a61ce14025be80696667d653627f788059f52da (diff)
downloadorg.eclipse.gemini.blueprint-6976b50e76a17aaf800a60f836c6b7af46fbf483.zip
org.eclipse.gemini.blueprint-6976b50e76a17aaf800a60f836c6b7af46fbf483.tar.gz
org.eclipse.gemini.blueprint-6976b50e76a17aaf800a60f836c6b7af46fbf483.tar.bz2
356683: construct extender configuration once and share it
-rw-r--r--core/src/test/java/org/eclipse/gemini/blueprint/context/internal/classloader/ChainedClassLoaderTest.java255
-rw-r--r--core/src/test/java/org/eclipse/gemini/blueprint/context/support/ConfigLocationsTest.java119
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/BlueprintNamespaceHandlerActivator.java28
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ContextLoaderListener.java744
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/JavaBeansCacheActivator.java74
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java864
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListListenerAdapter.java181
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListenerServiceActivator.java93
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LoggingActivator.java41
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/NamespaceHandlerActivator.java129
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/BaseListener.java99
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/NamespaceBundleLister.java73
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/BlueprintLoaderListener.java195
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/support/BlueprintExtenderConfiguration.java44
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/boot/ChainActivator.java171
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/DefaultOsgiBundleApplicationContextListener.java131
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfiguration.java1068
-rw-r--r--extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/ContextLoaderListenerTest.java51
-rw-r--r--extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationCustomSettingsTest.java206
-rw-r--r--extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationDefaultSettingsTest.java177
20 files changed, 2498 insertions, 2245 deletions
diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/context/internal/classloader/ChainedClassLoaderTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/context/internal/classloader/ChainedClassLoaderTest.java
index effc03e..1af35e6 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/context/internal/classloader/ChainedClassLoaderTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/context/internal/classloader/ChainedClassLoaderTest.java
@@ -1,129 +1,128 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.context.internal.classloader;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-import org.eclipse.gemini.blueprint.TestUtils;
-import org.eclipse.gemini.blueprint.context.support.internal.classloader.ChainedClassLoader;
-import org.osgi.framework.Bundle;
-
-/**
- * @author Costin Leau
- */
-public class ChainedClassLoaderTest extends TestCase {
-
- private ChainedClassLoader chainedLoader;
- private ClassLoader emptyCL;
-
-
- protected void setUp() throws Exception {
- emptyCL = new URLClassLoader(new URL[0], null) {
-
- public Class<?> loadClass(String name) throws ClassNotFoundException {
- throw new ClassNotFoundException(name);
- }
-
- public URL getResource(String name) {
- return null;
- }
- };
-
- chainedLoader = new ChainedClassLoader(new ClassLoader[] { emptyCL }, emptyCL);
- }
-
- protected void tearDown() throws Exception {
- chainedLoader = null;
- emptyCL = null;
- }
-
- public void testChainedClassLoaderClassLoaderArray() throws Exception {
- String className = "java.lang.Object";
- try {
- emptyCL.loadClass(className);
- fail("should not be able to load classes");
- }
- catch (ClassNotFoundException cnfe) {
- // expected
- }
-
- chainedLoader = new ChainedClassLoader(new ClassLoader[] { emptyCL });
- chainedLoader.loadClass(className);
- }
-
- public void testParentClassLoader() throws Exception {
- chainedLoader = new ChainedClassLoader(new ClassLoader[] { emptyCL });
- ClassLoader parent = chainedLoader.getParent();
- assertNotNull(parent);
- // fragile check (might fail on non SUN VMs)
- assertTrue("does the test run on a SUN VM or is it embedded?", parent.getClass().getName().indexOf("App") >= 0);
- }
-
- public void testChainedClassLoaderClassLoaderArrayClassLoader() throws Exception {
- String className = "java.lang.Object";
-
- try {
- emptyCL.loadClass(className);
- fail("should not be able to load classes");
- }
- catch (ClassNotFoundException cnfe) {
- // expected
- }
-
- try {
- chainedLoader.loadClass(className);
- fail("should not be able to load classes");
- }
- catch (ClassNotFoundException cnfe) {
- // expected
- }
- }
-
- public void testGetResourceString() throws Exception {
- System.out.println(chainedLoader.getResource("java/lang/Object.class"));
- assertNull(chainedLoader.getResource("java/lang/Object.class"));
- chainedLoader.addClassLoader(Object.class);
- assertNotNull(chainedLoader.getResource("java/lang/Object.class"));
- }
-
- public void testAddClassLoaderClass() throws Exception {
- chainedLoader.addClassLoader(Object.class);
- chainedLoader.loadClass("java.lang.Object");
- }
-
- public void testAddClassLoaderClassLoader() throws Exception {
- chainedLoader.addClassLoader(Bundle.class.getClassLoader());
- chainedLoader.loadClass("org.osgi.framework.Bundle");
- }
-
- public void testNonOSGiClassLoaderInsertOrder() throws Exception {
- ClassLoader appLoader = ClassLoader.getSystemClassLoader();
- ClassLoader extLoader = appLoader.getParent();
-
- chainedLoader.addClassLoader(extLoader);
- chainedLoader.addClassLoader(appLoader);
-
- // read the internal array
- List list = (List) TestUtils.getFieldValue(chainedLoader, "nonOsgiLoaders");
-
- // the loaders should be inserted based on their inheritance
- assertSame(appLoader, list.get(0));
- assertSame(extLoader, list.get(1));
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.context.internal.classloader;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.gemini.blueprint.TestUtils;
+import org.eclipse.gemini.blueprint.context.support.internal.classloader.ChainedClassLoader;
+import org.osgi.framework.Bundle;
+
+/**
+ * @author Costin Leau
+ */
+public class ChainedClassLoaderTest extends TestCase {
+
+ private ChainedClassLoader chainedLoader;
+ private ClassLoader emptyCL;
+
+
+ protected void setUp() throws Exception {
+ emptyCL = new URLClassLoader(new URL[0], null) {
+
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ throw new ClassNotFoundException(name);
+ }
+
+ public URL getResource(String name) {
+ return null;
+ }
+ };
+
+ chainedLoader = new ChainedClassLoader(new ClassLoader[] { emptyCL }, emptyCL);
+ }
+
+ protected void tearDown() throws Exception {
+ chainedLoader = null;
+ emptyCL = null;
+ }
+
+ public void testChainedClassLoaderClassLoaderArray() throws Exception {
+ String className = "java.lang.Object";
+ try {
+ emptyCL.loadClass(className);
+ fail("should not be able to load classes");
+ }
+ catch (ClassNotFoundException cnfe) {
+ // expected
+ }
+
+ chainedLoader = new ChainedClassLoader(new ClassLoader[] { emptyCL });
+ chainedLoader.loadClass(className);
+ }
+
+ public void testParentClassLoader() throws Exception {
+ chainedLoader = new ChainedClassLoader(new ClassLoader[] { emptyCL });
+ ClassLoader parent = chainedLoader.getParent();
+ assertNotNull(parent);
+ // fragile check (might fail on non SUN VMs)
+ assertTrue("does the test run on a SUN VM or is it embedded?", parent.getClass().getName().indexOf("App") >= 0);
+ }
+
+ public void testChainedClassLoaderClassLoaderArrayClassLoader() throws Exception {
+ String className = "java.lang.Object";
+
+ try {
+ emptyCL.loadClass(className);
+ fail("should not be able to load classes");
+ }
+ catch (ClassNotFoundException cnfe) {
+ // expected
+ }
+
+ try {
+ chainedLoader.loadClass(className);
+ fail("should not be able to load classes");
+ }
+ catch (ClassNotFoundException cnfe) {
+ // expected
+ }
+ }
+
+ public void testGetResourceString() throws Exception {
+ assertNull(chainedLoader.getResource("java/lang/Object.class"));
+ chainedLoader.addClassLoader(Object.class);
+ assertNotNull(chainedLoader.getResource("java/lang/Object.class"));
+ }
+
+ public void testAddClassLoaderClass() throws Exception {
+ chainedLoader.addClassLoader(Object.class);
+ chainedLoader.loadClass("java.lang.Object");
+ }
+
+ public void testAddClassLoaderClassLoader() throws Exception {
+ chainedLoader.addClassLoader(Bundle.class.getClassLoader());
+ chainedLoader.loadClass("org.osgi.framework.Bundle");
+ }
+
+ public void testNonOSGiClassLoaderInsertOrder() throws Exception {
+ ClassLoader appLoader = ClassLoader.getSystemClassLoader();
+ ClassLoader extLoader = appLoader.getParent();
+
+ chainedLoader.addClassLoader(extLoader);
+ chainedLoader.addClassLoader(appLoader);
+
+ // read the internal array
+ List list = (List) TestUtils.getFieldValue(chainedLoader, "nonOsgiLoaders");
+
+ // the loaders should be inserted based on their inheritance
+ assertSame(appLoader, list.get(0));
+ assertSame(extLoader, list.get(1));
+ }
} \ No newline at end of file
diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/context/support/ConfigLocationsTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/context/support/ConfigLocationsTest.java
index 548f297..96b24c2 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/context/support/ConfigLocationsTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/context/support/ConfigLocationsTest.java
@@ -1,60 +1,59 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.context.support;
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-
-import junit.framework.TestCase;
-
-import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext;
-
-/**
- *
- * @author Costin Leau
- */
-public class ConfigLocationsTest extends TestCase {
-
- private OsgiBundleXmlApplicationContext context;
-
- @Override
- protected void setUp() throws Exception {
- context = new OsgiBundleXmlApplicationContext();
- }
-
- @Override
- protected void tearDown() throws Exception {
- context = null;
- }
-
- public void testExpandConfigFolders() throws Exception {
- String[] cfgs = new String[] { "cnf/", "/cnf/" };
- context.setConfigLocations(cfgs);
- String[] returned =
- (String[]) invokeMethod("expandLocations", new Class[] { String[].class }, new Object[] { cfgs });
- System.out.println("returned " + Arrays.toString(returned));
- assertTrue(Arrays.equals(new String[] { "cnf/*.xml", "/cnf/*.xml" }, returned));
- }
-
- private Object invokeMethod(String name, Class[] types, Object[] args) {
- try {
- Method mt = context.getClass().getDeclaredMethod(name, types);
- mt.setAccessible(true);
- return mt.invoke(context, args);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-}
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.context.support;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext;
+
+/**
+ *
+ * @author Costin Leau
+ */
+public class ConfigLocationsTest extends TestCase {
+
+ private OsgiBundleXmlApplicationContext context;
+
+ @Override
+ protected void setUp() throws Exception {
+ context = new OsgiBundleXmlApplicationContext();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ context = null;
+ }
+
+ public void testExpandConfigFolders() throws Exception {
+ String[] cfgs = new String[] { "cnf/", "/cnf/" };
+ context.setConfigLocations(cfgs);
+ String[] returned =
+ (String[]) invokeMethod("expandLocations", new Class[] { String[].class }, new Object[] { cfgs });
+ assertTrue(Arrays.equals(new String[] { "cnf/*.xml", "/cnf/*.xml" }, returned));
+ }
+
+ private Object invokeMethod(String name, Class[] types, Object[] args) {
+ try {
+ Method mt = context.getClass().getDeclaredMethod(name, types);
+ mt.setAccessible(true);
+ return mt.invoke(context, args);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/BlueprintNamespaceHandlerActivator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/BlueprintNamespaceHandlerActivator.java
new file mode 100644
index 0000000..6004720
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/BlueprintNamespaceHandlerActivator.java
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintConfigUtils;
+
+/**
+ * @author Olaf Otto
+ */
+public class BlueprintNamespaceHandlerActivator extends NamespaceHandlerActivator {
+
+ @Override
+ protected String getManagedBundleExtenderVersionHeader() {
+ return BlueprintConfigUtils.EXTENDER_VERSION;
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ContextLoaderListener.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ContextLoaderListener.java
index 5c7f419..82a7c37 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ContextLoaderListener.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ContextLoaderListener.java
@@ -1,507 +1,269 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- * Oracle Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.activator;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.SynchronousBundleListener;
-import org.osgi.framework.Version;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.CachedIntrospectionResults;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
-import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
-import org.eclipse.gemini.blueprint.extender.internal.support.NamespaceManager;
-import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
-import org.eclipse.gemini.blueprint.service.exporter.support.OsgiServiceFactoryBean;
-import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceCollectionProxyFactoryBean;
-import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceProxyFactoryBean;
-import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
-import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
-
-/**
- * Osgi Extender that bootstraps 'Spring powered bundles'.
- *
- * <p/> The class listens to bundle events and manages the creation and destruction of application contexts for bundles
- * that have one or both of: <ul> <li>A manifest header entry Spring-Context <li>XML files in META-INF/spring folder
- * </ul>
- *
- * <p/> The extender also discovers any Spring namespace/schema handlers in resolved bundles and makes them available
- * through a dedicated OSGi service.
- *
- * <p/> The extender behaviour can be customized by attaching fragments to the extender bundle. On startup, the extender
- * will look for <code>META-INF/spring/*.xml</code> files and merge them into an application context. From the resulting
- * context, the context will look for beans with predefined names to determine its configuration. The current version
- * recognises the following bean names:
- *
- * <table border="1"> <tr> <th>Bean Name</th> <th>Bean Type</th> <th>Description</th> </tr> <tr>
- * <td><code>taskExecutor</code></td> <td><code>org.springframework.core.task.TaskExecutor</code></td> <td>Task executor
- * used for creating the discovered application contexts.</td> </tr> <tr> <td><code>shutdownTaskExecutor</code></td>
- * <td><code>org.springframework.core.task.TaskExecutor</code></td> <td>Task executor used for shutting down various
- * application contexts.</td> </tr> <tr> <td><code>extenderProperties</code></td>
- * <td><code>java.util.Properties</code></td> <td>Various properties for configuring the extender behaviour (see
- * below)</td> </tr> </table>
- *
- * <p/> <code>extenderProperties</code> recognises the following properties:
- *
- * <table border="1"> <tr> <th>Name</th> <th>Type</th> <th>Description</th> </tr> <tr>
- * <td><code>shutdown.wait.time</code></td> <td>Number</td> <td>The amount of time the extender will wait for each
- * application context to shutdown gracefully. Expressed in milliseconds.</td> </tr> <tr>
- * <td><code>process.annotations</code></td> <td>Boolean</td> <td>Whether or not, the extender will process SpringOSGi
- * annotations.</td> </tr> </table>
- *
- * <p/> Note: The extender configuration context is created during the bundle activation (a synchronous OSGi lifecycle
- * callback) and should contain only simple bean definitions that will not delay context initialisation. </p>
- *
- * @author Bill Gallagher
- * @author Andy Piper
- * @author Hal Hildebrand
- * @author Adrian Colyer
- * @author Costin Leau
- */
-public class ContextLoaderListener implements BundleActivator {
-
- /**
- * Common base class for {@link ContextLoaderListener} listeners.
- *
- * @author Costin Leau
- */
- private abstract class BaseListener implements SynchronousBundleListener {
-
- static final int LAZY_ACTIVATION_EVENT_TYPE = 0x00000200;
-
- protected final Log log = LogFactory.getLog(getClass());
-
- /**
- * common cache used for tracking down bundles started lazily so they don't get processed twice (once when
- * started lazy, once when started fully)
- */
- protected Map<Bundle, Object> lazyBundleCache = new WeakHashMap<Bundle, Object>();
- /** dummy value for the bundle cache */
- private final Object VALUE = new Object();
-
- // caches the bundle
- protected void push(Bundle bundle) {
- synchronized (lazyBundleCache) {
- lazyBundleCache.put(bundle, VALUE);
- }
- }
-
- // checks the presence of the bundle as well as removing it
- protected boolean pop(Bundle bundle) {
- synchronized (lazyBundleCache) {
- return (lazyBundleCache.remove(bundle) != null);
- }
- }
-
- /**
- * A bundle has been started, stopped, resolved, or unresolved. This method is a synchronous callback, do not do
- * any long-running work in this thread.
- *
- * @see org.osgi.framework.SynchronousBundleListener#bundleChanged
- */
- public void bundleChanged(BundleEvent event) {
-
- boolean trace = log.isTraceEnabled();
-
- // check if the listener is still alive
- if (isClosed) {
- if (trace)
- log.trace("Listener is closed; events are being ignored");
- return;
- }
- if (trace) {
- log.trace("Processing bundle event [" + OsgiStringUtils.nullSafeToString(event) + "] for bundle ["
- + OsgiStringUtils.nullSafeSymbolicName(event.getBundle()) + "]");
- }
- try {
- handleEvent(event);
- } catch (Exception ex) {
- /* log exceptions before swallowing */
- log.warn("Got exception while handling event " + event, ex);
- }
- }
-
- protected abstract void handleEvent(BundleEvent event);
- }
-
- /**
- * Bundle listener used for detecting namespace handler/resolvers. Exists as a separate listener so that it can be
- * registered early to avoid race conditions with bundles in INSTALLING state but still to avoid premature context
- * creation before the Spring {@link ContextLoaderListener} is not fully initialized.
- *
- * @author Costin Leau
- */
- private class NamespaceBundleLister extends BaseListener {
-
- private final boolean resolved;
-
- NamespaceBundleLister(boolean resolvedBundles) {
- this.resolved = resolvedBundles;
- }
-
- protected void handleEvent(BundleEvent event) {
- Bundle bundle = event.getBundle();
-
- switch (event.getType()) {
-
- case BundleEvent.RESOLVED:
- if (resolved) {
- maybeAddNamespaceHandlerFor(bundle, false);
- }
- break;
-
- case LAZY_ACTIVATION_EVENT_TYPE: {
- if (!resolved) {
- push(bundle);
- maybeAddNamespaceHandlerFor(bundle, true);
- }
- break;
- }
- case BundleEvent.STARTED: {
- if (!resolved) {
- if (!pop(bundle)) {
- maybeAddNamespaceHandlerFor(bundle, false);
- }
- }
- break;
- }
- case BundleEvent.STOPPED: {
- pop(bundle);
- maybeRemoveNameSpaceHandlerFor(bundle);
- break;
- }
- default:
- break;
- }
- }
- }
-
- /**
- * Bundle listener used for context creation/destruction.
- */
- private class ContextBundleListener extends BaseListener {
-
- protected void handleEvent(BundleEvent event) {
-
- Bundle bundle = event.getBundle();
-
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ * Oracle Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
+import org.eclipse.gemini.blueprint.extender.internal.activator.listeners.BaseListener;
+import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
+import org.eclipse.gemini.blueprint.extender.support.DefaultOsgiApplicationContextCreator;
+import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
+import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
+import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
+import org.osgi.framework.*;
+
+/**
+ * Osgi Extender that bootstraps 'Spring powered bundles'.
+ *
+ * <p/> The class listens to bundle events and manages the creation and destruction of application contexts for bundles
+ * that have one or both of: <ul> <li>A manifest header entry Spring-Context <li>XML files in META-INF/spring folder
+ * </ul>
+ *
+ * <p/> The extender also discovers any Spring namespace/schema handlers in resolved bundles and makes them available
+ * through a dedicated OSGi service.
+ *
+ * <p/> The extender behaviour can be customized by attaching fragments to the extender bundle. On startup, the extender
+ * will look for <code>META-INF/spring/*.xml</code> files and merge them into an application context. From the resulting
+ * context, the context will look for beans with predefined names to determine its configuration. The current version
+ * recognises the following bean names:
+ *
+ * <table border="1"> <tr> <th>Bean Name</th> <th>Bean Type</th> <th>Description</th> </tr> <tr>
+ * <td><code>taskExecutor</code></td> <td><code>org.springframework.core.task.TaskExecutor</code></td> <td>Task executor
+ * used for creating the discovered application contexts.</td> </tr> <tr> <td><code>shutdownTaskExecutor</code></td>
+ * <td><code>org.springframework.core.task.TaskExecutor</code></td> <td>Task executor used for shutting down various
+ * application contexts.</td> </tr> <tr> <td><code>extenderProperties</code></td>
+ * <td><code>java.util.Properties</code></td> <td>Various properties for configuring the extender behaviour (see
+ * below)</td> </tr> </table>
+ *
+ * <p/> <code>extenderProperties</code> recognises the following properties:
+ *
+ * <table border="1"> <tr> <th>Name</th> <th>Type</th> <th>Description</th> </tr> <tr>
+ * <td><code>shutdown.wait.time</code></td> <td>Number</td> <td>The amount of time the extender will wait for each
+ * application context to shutdown gracefully. Expressed in milliseconds.</td> </tr> <tr>
+ * <td><code>process.annotations</code></td> <td>Boolean</td> <td>Whether or not, the extender will process SpringOSGi
+ * annotations.</td> </tr> </table>
+ *
+ * <p/> Note: The extender configuration context is created during the bundle activation (a synchronous OSGi lifecycle
+ * callback) and should contain only simple bean definitions that will not delay context initialisation. </p>
+ *
+ * @author Bill Gallagher
+ * @author Andy Piper
+ * @author Hal Hildebrand
+ * @author Adrian Colyer
+ * @author Costin Leau
+ */
+public class ContextLoaderListener implements BundleActivator {
+
+ /**
+ * Bundle listener used for context creation/destruction.
+ */
+ private class ContextBundleListener extends BaseListener {
+
+ protected void handleEvent(BundleEvent event) {
+
+ Bundle bundle = event.getBundle();
+
// ignore current bundle for context creation
- if (bundle.getBundleId() == bundleId) {
- return;
- }
-
- switch (event.getType()) {
- case LAZY_ACTIVATION_EVENT_TYPE: {
+ if (bundle.getBundleId() == bundleId) {
+ return;
+ }
+
+ switch (event.getType()) {
+ case LAZY_ACTIVATION_EVENT_TYPE: {
// activate bundle
- try {
- bundle.loadClass("org.osgi.service.blueprint.container.BlueprintContainer");
- } catch (Exception ex) {
- }
- break;
- }
- case BundleEvent.STARTED: {
- lifecycleManager.maybeCreateApplicationContextFor(bundle);
- break;
- }
- case BundleEvent.STOPPING: {
- if (OsgiBundleUtils.isSystemBundle(bundle)) {
- if (log.isDebugEnabled()) {
- log.debug("System bundle stopping");
- }
+ try {
+ bundle.loadClass("org.osgi.service.blueprint.container.BlueprintContainer");
+ } catch (Exception ex) {
+ }
+ break;
+ }
+ case BundleEvent.STARTED: {
+ lifecycleManager.maybeCreateApplicationContextFor(bundle);
+ break;
+ }
+ case BundleEvent.STOPPING: {
+ if (OsgiBundleUtils.isSystemBundle(bundle)) {
+ if (log.isDebugEnabled()) {
+ log.debug("System bundle stopping");
+ }
// System bundle is shutting down; Special handling for
// framework shutdown
- shutdown();
- } else {
- lifecycleManager.maybeCloseApplicationContextFor(bundle);
- }
- break;
- }
- default:
- break;
- }
- }
- }
-
- protected final Log log = LogFactory.getLog(getClass());
-
- /** extender bundle id */
- private long bundleId;
-
- /** extender configuration */
- private ExtenderConfiguration extenderConfiguration;
-
- /** Spring namespace/resolver manager */
- private NamespaceManager nsManager;
-
- /** The bundle's context */
- private BundleContext bundleContext;
-
- /** Bundle listener interested in context creation */
- private SynchronousBundleListener contextListener;
-
- /** Bundle listener interested in namespace resolvers/parsers discovery */
- private SynchronousBundleListener nsListener;
-
- /**
- * Monitor used for dealing with the bundle activator and synchronous bundle threads
- */
- private final Object monitor = new Object();
-
- /**
- * flag indicating whether the context is down or not - useful during shutdown
- */
- private volatile boolean isClosed = false;
-
- /** This extender version */
- private Version extenderVersion;
-
- private volatile OsgiBundleApplicationContextEventMulticaster multicaster;
-
- private volatile LifecycleManager lifecycleManager;
- private volatile VersionMatcher versionMatcher;
- private volatile OsgiContextProcessor processor;
- private volatile ListListenerAdapter osgiListeners;
-
- /**
- * <p/> Called by OSGi when this bundle is started. Finds all previously resolved bundles and adds namespace
- * handlers for them if necessary. </p> <p/> Creates application contexts for bundles started before the extender
- * was started. </p> <p/> Registers a namespace/entity resolving service for use by web app contexts. </p>
- *
- * @see org.osgi.framework.BundleActivator#start
- */
- public void start(BundleContext context) throws Exception {
-
- this.bundleContext = context;
- this.bundleId = context.getBundle().getBundleId();
-
- this.extenderVersion = OsgiBundleUtils.getBundleVersion(context.getBundle());
- log.info("Starting [" + bundleContext.getBundle().getSymbolicName() + "] bundle v.[" + extenderVersion + "]");
- versionMatcher = new DefaultVersionMatcher(getManagedBundleExtenderVersionHeader(), extenderVersion);
- processor = createContextProcessor();
-
- // init cache (to prevent ad-hoc Java Bean discovery on lazy bundles)
- initJavaBeansCache();
-
- // Step 1 : discover existing namespaces (in case there are fragments with custom XML definitions)
- nsManager = new NamespaceManager(context);
- initNamespaceHandlers(bundleContext);
-
- // Step 2: initialize the extender configuration
- extenderConfiguration = initExtenderConfiguration(bundleContext);
-
- // init the OSGi event dispatch/listening system
- initListenerService();
-
+ shutdown();
+ } else {
+ lifecycleManager.maybeCloseApplicationContextFor(bundle);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ protected final Log log = LogFactory.getLog(getClass());
+
+ private ExtenderConfiguration extenderConfiguration;
+ private VersionMatcher versionMatcher;
+ private Version extenderVersion;
+
+ /** extender bundle id */
+ private long bundleId;
+
+ /** The bundle's context */
+ private BundleContext bundleContext;
+
+ /** Bundle listener interested in context creation */
+ private BaseListener contextListener;
+
+ /**
+ * Monitor used for dealing with the bundle activator and synchronous bundle threads
+ */
+ private final Object monitor = new Object();
+
+ /**
+ * flag indicating whether the context is down or not - useful during shutdown
+ */
+ private volatile boolean isClosed = false;
+
+ private volatile LifecycleManager lifecycleManager;
+ private volatile OsgiContextProcessor processor;
+
+ public ContextLoaderListener(ExtenderConfiguration extenderConfiguration) {
+ this.extenderConfiguration = extenderConfiguration;
+ }
+
+ /**
+ * <p/> Called by OSGi when this bundle is started. Finds all previously resolved bundles and adds namespace
+ * handlers for them if necessary. </p> <p/> Creates application contexts for bundles started before the extender
+ * was started. </p> <p/> Registers a namespace/entity resolving service for use by web app contexts. </p>
+ *
+ * @see org.osgi.framework.BundleActivator#start
+ */
+ public void start(BundleContext extenderBundleContext) throws Exception {
+
+ this.bundleContext = extenderBundleContext;
+ this.bundleId = extenderBundleContext.getBundle().getBundleId();
+ this.extenderVersion = OsgiBundleUtils.getBundleVersion(extenderBundleContext.getBundle());
+ this.versionMatcher = new DefaultVersionMatcher(getManagedBundleExtenderVersionHeader(), extenderVersion);
+ this.processor = createContextProcessor();
+
// initialize the configuration once namespace handlers have been detected
- lifecycleManager =
- new LifecycleManager(extenderConfiguration, versionMatcher, createContextConfigFactory(),
- this.processor, getTypeCompatibilityChecker(), bundleContext);
-
+ this.lifecycleManager =
+ new LifecycleManager(
+ this.extenderConfiguration,
+ getVersionMatcher(),
+ createContextConfigFactory(),
+ getOsgiApplicationContextCreator(),
+ this.processor,
+ getTypeCompatibilityChecker(),
+ bundleContext);
+
// Step 3: discover the bundles that are started
// and require context creation
- initStartedBundles(bundleContext);
- }
-
- protected ExtenderConfiguration initExtenderConfiguration(BundleContext bundleContext) {
- return new ExtenderConfiguration(bundleContext, log);
- }
-
- protected OsgiContextProcessor createContextProcessor() {
- return new NoOpOsgiContextProcessor();
- }
-
- protected TypeCompatibilityChecker getTypeCompatibilityChecker() {
- return null;
- }
-
- protected String getManagedBundleExtenderVersionHeader() {
- return ConfigUtils.EXTENDER_VERSION;
- }
-
- protected void initNamespaceHandlers(BundleContext context) {
- nsManager = new NamespaceManager(context);
-
- // register listener first to make sure any bundles in INSTALLED state
- // are not lost
-
- // if the property is defined and true, consider bundles in STARTED/LAZY-INIT state, otherwise use RESOLVED
- boolean nsResolved = !Boolean.getBoolean("org.eclipse.gemini.blueprint.ns.bundles.started");
- nsListener = new NamespaceBundleLister(nsResolved);
- context.addBundleListener(nsListener);
-
- Bundle[] previousBundles = context.getBundles();
-
- for (Bundle bundle : previousBundles) {
- // special handling for uber bundle being restarted
- if ((nsResolved && OsgiBundleUtils.isBundleResolved(bundle)) || (!nsResolved && OsgiBundleUtils.isBundleActive(bundle)) || bundleId == bundle.getBundleId()) {
- maybeAddNamespaceHandlerFor(bundle, false);
- } else if (OsgiBundleUtils.isBundleLazyActivated(bundle)) {
- maybeAddNamespaceHandlerFor(bundle, true);
- }
- }
-
- // discovery finished, publish the resolvers/parsers in the OSGi space
- nsManager.afterPropertiesSet();
- }
-
- protected void initStartedBundles(BundleContext bundleContext) {
+ initStartedBundles(bundleContext);
+ }
+
+ protected OsgiContextProcessor createContextProcessor() {
+ return new NoOpOsgiContextProcessor();
+ }
+
+ protected TypeCompatibilityChecker getTypeCompatibilityChecker() {
+ return null;
+ }
+
+ protected void initStartedBundles(BundleContext bundleContext) {
// register the context creation listener
- contextListener = new ContextBundleListener();
+ contextListener = new ContextBundleListener();
// listen to any changes in bundles
- bundleContext.addBundleListener(contextListener);
+ bundleContext.addBundleListener(contextListener);
// get the bundles again to get an updated view
- Bundle[] previousBundles = bundleContext.getBundles();
-
+ Bundle[] previousBundles = bundleContext.getBundles();
+
// Instantiate all previously resolved bundles which are Spring
// powered
- for (int i = 0; i < previousBundles.length; i++) {
- if (OsgiBundleUtils.isBundleActive(previousBundles[i])) {
- try {
- lifecycleManager.maybeCreateApplicationContextFor(previousBundles[i]);
- } catch (Throwable e) {
- log.warn("Cannot start bundle " + OsgiStringUtils.nullSafeSymbolicName(previousBundles[i])
- + " due to", e);
- }
- }
- }
- }
-
- /**
- * Called by OSGi when this bundled is stopped. Unregister the namespace/entity resolving service and clear all
- * state. No further management of application contexts created by this extender prior to stopping the bundle occurs
- * after this point (even if the extender bundle is subsequently restarted).
- *
- * @see org.osgi.framework.BundleActivator#stop
- */
- public void stop(BundleContext context) throws Exception {
- shutdown();
- }
-
- /**
- * Shutdown the extender and all bundled managed by it. Shutdown of contexts is in the topological order of the
- * dependency graph formed by the service references.
- */
- protected void shutdown() {
- synchronized (monitor) {
+ for (int i = 0; i < previousBundles.length; i++) {
+ if (OsgiBundleUtils.isBundleActive(previousBundles[i])) {
+ try {
+ lifecycleManager.maybeCreateApplicationContextFor(previousBundles[i]);
+ } catch (Throwable e) {
+ log.warn("Cannot start bundle " + OsgiStringUtils.nullSafeSymbolicName(previousBundles[i])
+ + " due to", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by OSGi when this bundled is stopped. Unregister the namespace/entity resolving service and clear all
+ * state. No further management of application contexts created by this extender prior to stopping the bundle occurs
+ * after this point (even if the extender bundle is subsequently restarted).
+ *
+ * @see org.osgi.framework.BundleActivator#stop
+ */
+ public void stop(BundleContext context) throws Exception {
+ shutdown();
+ }
+
+ /**
+ * Shutdown the extender and all bundled managed by it. Shutdown of contexts is in the topological order of the
+ * dependency graph formed by the service references.
+ */
+ protected void shutdown() {
+ synchronized (monitor) {
// if already closed, bail out
- if (isClosed)
- return;
- else
- isClosed = true;
- }
- log.info("Stopping [" + bundleContext.getBundle().getSymbolicName() + "] bundle v.[" + extenderVersion + "]");
-
- destroyJavaBeansCache();
-
+ if (isClosed)
+ return;
+ else
+ isClosed = true;
+ }
+
+ this.contextListener.close();
+
// remove the bundle listeners (we are closing down)
- if (contextListener != null) {
- bundleContext.removeBundleListener(contextListener);
- contextListener = null;
- }
-
- if (nsListener != null) {
- bundleContext.removeBundleListener(nsListener);
- nsListener = null;
- }
-
+ if (contextListener != null) {
+ bundleContext.removeBundleListener(contextListener);
+ contextListener = null;
+ }
+
// close managed bundles
- lifecycleManager.destroy();
- // clear the namespace registry
- nsManager.destroy();
-
- // release multicaster
- if (multicaster != null) {
- multicaster.removeAllListeners();
- multicaster = null;
- }
- // release listeners
- osgiListeners.destroy();
- osgiListeners = null;
-
- extenderConfiguration.destroy();
- }
-
- private void initJavaBeansCache() {
- Class<?>[] classes =
- new Class<?>[] { OsgiServiceFactoryBean.class, OsgiServiceProxyFactoryBean.class,
- OsgiServiceCollectionProxyFactoryBean.class };
-
- CachedIntrospectionResults.acceptClassLoader(OsgiStringUtils.class.getClassLoader());
-
- for (Class<?> clazz : classes) {
- BeanUtils.getPropertyDescriptors(clazz);
- }
- }
-
- private void destroyJavaBeansCache() {
- CachedIntrospectionResults.clearClassLoader(OsgiStringUtils.class.getClassLoader());
- }
-
- protected void maybeAddNamespaceHandlerFor(Bundle bundle, boolean isLazy) {
- if (handlerBundleMatchesExtenderVersion(bundle))
- nsManager.maybeAddNamespaceHandlerFor(bundle, isLazy);
- }
-
- protected void maybeRemoveNameSpaceHandlerFor(Bundle bundle) {
- if (handlerBundleMatchesExtenderVersion(bundle))
- nsManager.maybeRemoveNameSpaceHandlerFor(bundle);
- }
-
- /**
- * Utility method that does extender range versioning and approapriate
- *
- * logging.
- *
- * @param bundle
- */
- private boolean handlerBundleMatchesExtenderVersion(Bundle bundle) {
- if (!versionMatcher.matchVersion(bundle)) {
- if (log.isDebugEnabled())
- log.debug("Ignoring handler bundle " + OsgiStringUtils.nullSafeNameAndSymName(bundle)
- + "] due to mismatch in expected extender version");
- return false;
- }
- return true;
- }
-
- protected ApplicationContextConfigurationFactory createContextConfigFactory() {
- return new DefaultApplicationContextConfigurationFactory();
- }
-
- protected void initListenerService() {
- multicaster = extenderConfiguration.getEventMulticaster();
-
- addApplicationListener(multicaster);
- multicaster.addApplicationListener(extenderConfiguration.getContextEventListener());
-
- if (log.isDebugEnabled())
- log.debug("Initialization of OSGi listeners service completed...");
- }
-
- protected void addApplicationListener(OsgiBundleApplicationContextEventMulticaster multicaster) {
- osgiListeners = new ListListenerAdapter(bundleContext);
- osgiListeners.afterPropertiesSet();
- // register the listener that does the dispatching
- multicaster.addApplicationListener(osgiListeners);
- }
+ lifecycleManager.destroy();
+ }
+
+ protected ApplicationContextConfigurationFactory createContextConfigFactory() {
+ return new DefaultApplicationContextConfigurationFactory();
+ }
+
+ public VersionMatcher getVersionMatcher() {
+ return versionMatcher;
+ }
+
+ protected String getManagedBundleExtenderVersionHeader() {
+ return ConfigUtils.EXTENDER_VERSION;
+ }
+
+ protected OsgiApplicationContextCreator getOsgiApplicationContextCreator() {
+ OsgiApplicationContextCreator creator = this.extenderConfiguration.getContextCreator();
+ if (creator == null) {
+ creator = createDefaultOsgiApplicationContextCreator();
+ }
+ return creator;
+ }
+
+ protected OsgiApplicationContextCreator createDefaultOsgiApplicationContextCreator() {
+ return new DefaultOsgiApplicationContextCreator();
+ }
} \ No newline at end of file
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/JavaBeansCacheActivator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/JavaBeansCacheActivator.java
new file mode 100644
index 0000000..24df0a4
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/JavaBeansCacheActivator.java
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.eclipse.gemini.blueprint.service.exporter.support.OsgiServiceFactoryBean;
+import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceCollectionProxyFactoryBean;
+import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceProxyFactoryBean;
+import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.CachedIntrospectionResults;
+
+/**
+ * Used to prevent ad-hoc Java Bean discovery on lazy bundles.
+ *
+ * @author Bill Gallagher
+ * @author Andy Piper
+ * @author Hal Hildebrand
+ * @author Adrian Colyer
+ * @author Costin Leau
+ * @author Olaf Otto
+ */
+public class JavaBeansCacheActivator implements BundleActivator {
+ /**
+ * Monitor used for dealing with the bundle activator and synchronous bundle threads
+ */
+ private final Object monitor = new Object();
+ private boolean stopped = false;
+
+ public void start(BundleContext extenderBundleContext) {
+ initJavaBeansCache();
+ }
+
+ public void stop(BundleContext extenderBundleContext) {
+ synchronized (monitor) {
+ if (stopped) {
+ return;
+ }
+ stopped = true;
+ }
+ destroyJavaBeansCache();
+ }
+
+ private void initJavaBeansCache() {
+ Class<?>[] classes =
+ new Class<?>[] { OsgiServiceFactoryBean.class, OsgiServiceProxyFactoryBean.class,
+ OsgiServiceCollectionProxyFactoryBean.class };
+
+ CachedIntrospectionResults.acceptClassLoader(OsgiStringUtils.class.getClassLoader());
+
+ for (Class<?> clazz : classes) {
+ BeanUtils.getPropertyDescriptors(clazz);
+ }
+ }
+
+ private void destroyJavaBeansCache() {
+ CachedIntrospectionResults.clearClassLoader(OsgiStringUtils.class.getClassLoader());
+ }
+}
+
+
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java
index 5ad01f2..b2d5e43 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java
@@ -1,436 +1,430 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.activator;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Timer;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
-import org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
-import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
-import org.eclipse.gemini.blueprint.extender.OsgiBeanFactoryPostProcessor;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ShutdownSorter;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor;
-import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
-import org.eclipse.gemini.blueprint.extender.internal.support.OsgiBeanFactoryPostProcessorAdapter;
-import org.eclipse.gemini.blueprint.extender.internal.util.concurrent.Counter;
-import org.eclipse.gemini.blueprint.extender.internal.util.concurrent.RunnableTimedExecution;
-import org.eclipse.gemini.blueprint.extender.support.ApplicationContextConfiguration;
-import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
-import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.core.task.SyncTaskExecutor;
-import org.springframework.core.task.TaskExecutor;
-
-/**
- * Manager handling the startup/shutdown threading issues regarding OSGi contexts. Used by {@link ContextLoaderListener}
- * .
- *
- * @author Costin Leau
- */
-class LifecycleManager implements DisposableBean {
-
- /** logger */
- private static final Log log = LogFactory.getLog(LifecycleManager.class);
-
- /**
- * The contexts we are currently managing. Keys are bundle ids, values are ServiceDependentOsgiApplicationContexts
- * for the application context
- */
- private final Map<Long, ConfigurableOsgiBundleApplicationContext> managedContexts =
- new ConcurrentHashMap<Long, ConfigurableOsgiBundleApplicationContext>(16);
-
- /** listener counter - used to properly synchronize shutdown */
- private Counter contextsStarted = new Counter("contextsStarted");
-
- // "Spring Application Context Creation Timer"
- private final Timer timer = new Timer("Spring DM Context Creation Timer", true);
-
- /** Task executor used for bootstraping the Spring contexts in async mode */
- private final TaskExecutor taskExecutor;
-
- /** ApplicationContext Creator */
- private final OsgiApplicationContextCreator contextCreator;
-
- /** BFPP list */
- private final List<OsgiBeanFactoryPostProcessor> postProcessors;
-
- /** shutdown task executor */
- private final TaskExecutor shutdownTaskExecutor;
-
- /**
- * Task executor which uses the same thread for running tasks. Used when doing a synchronous wait-for-dependencies.
- */
- private final TaskExecutor sameThreadTaskExecutor = new SyncTaskExecutor();
-
- private final OsgiBundleApplicationContextEventMulticaster multicaster;
-
- private final ExtenderConfiguration extenderConfiguration;
-
- private final BundleContext bundleContext;
-
- private final OsgiContextProcessor processor;
-
- private final ApplicationContextConfigurationFactory contextConfigurationFactory;
-
- private final VersionMatcher versionMatcher;
- private final TypeCompatibilityChecker typeChecker;
-
- LifecycleManager(ExtenderConfiguration extenderConfiguration, VersionMatcher versionMatcher,
- ApplicationContextConfigurationFactory appCtxCfgFactory, OsgiContextProcessor processor,
- TypeCompatibilityChecker checker, BundleContext context) {
-
- this.versionMatcher = versionMatcher;
- this.extenderConfiguration = extenderConfiguration;
- this.contextConfigurationFactory = appCtxCfgFactory;
-
- this.processor = processor;
-
- this.taskExecutor = extenderConfiguration.getTaskExecutor();
- this.shutdownTaskExecutor = extenderConfiguration.getShutdownTaskExecutor();
-
- this.multicaster = extenderConfiguration.getEventMulticaster();
-
- this.contextCreator = extenderConfiguration.getContextCreator();
- this.postProcessors = extenderConfiguration.getPostProcessors();
- this.typeChecker = checker;
-
- this.bundleContext = context;
- }
-
- /**
- * Context creation is a potentially long-running activity (certainly more than we want to do on the synchronous
- * event callback).
- *
- * <p/> Based on our configuration, the context can be started on the same thread or on a different one.
- *
- * <p/> Kick off a background activity to create an application context for the given bundle if needed.
- *
- * <b>Note:</b> Make sure to do the fastest filtering first to avoid slow-downs on platforms with a big number of
- * plugins and wiring (i.e. Eclipse platform).
- *
- * @param bundle
- */
- protected void maybeCreateApplicationContextFor(Bundle bundle) {
-
- boolean debug = log.isDebugEnabled();
- String bundleString = "[" + OsgiStringUtils.nullSafeNameAndSymName(bundle) + "]";
-
- final Long bundleId = new Long(bundle.getBundleId());
-
- if (managedContexts.containsKey(bundleId)) {
- if (debug) {
- log.debug("Bundle " + bundleString + " is already managed; ignoring...");
- }
- return;
- }
-
- if (!versionMatcher.matchVersion(bundle)) {
- return;
- }
-
- BundleContext localBundleContext = OsgiBundleUtils.getBundleContext(bundle);
-
- // initialize context
- final DelegatedExecutionOsgiBundleApplicationContext localApplicationContext;
-
- if (debug)
- log.debug("Inspecting bundle " + bundleString);
-
- try {
- localApplicationContext = contextCreator.createApplicationContext(localBundleContext);
- } catch (Exception ex) {
- log.error("Cannot create application context for bundle " + bundleString, ex);
- return;
- }
-
- if (localApplicationContext == null) {
- log.debug("No application context created for bundle " + bundleString);
- return;
- }
-
- if (typeChecker != null) {
- if (!typeChecker.isTypeCompatible(localBundleContext)) {
- log.info("Bundle " + OsgiStringUtils.nullSafeName(bundle) + " is not type compatible with extender "
- + OsgiStringUtils.nullSafeName(bundleContext.getBundle()) + "; ignoring bundle...");
- return;
- }
- }
-
- log.debug("Bundle " + OsgiStringUtils.nullSafeName(bundle) + " is type compatible with extender "
- + OsgiStringUtils.nullSafeName(bundleContext.getBundle()) + "; processing bundle...");
-
- // create a dedicated hook for this application context
- BeanFactoryPostProcessor processingHook =
- new OsgiBeanFactoryPostProcessorAdapter(localBundleContext, postProcessors);
-
- // add in the post processors
- localApplicationContext.addBeanFactoryPostProcessor(processingHook);
-
- // add the context to the tracker
- managedContexts.put(bundleId, localApplicationContext);
-
- localApplicationContext.setDelegatedEventMulticaster(multicaster);
-
- ApplicationContextConfiguration config = contextConfigurationFactory.createConfiguration(bundle);
-
- final boolean asynch = config.isCreateAsynchronously();
-
- // create refresh runnable
- Runnable contextRefresh = new Runnable() {
-
- public void run() {
- // post refresh events are caught through events
- if (log.isTraceEnabled()) {
- log.trace("Calling pre-refresh on processor " + processor);
- }
- processor.preProcessRefresh(localApplicationContext);
- localApplicationContext.refresh();
- }
- };
-
- // executor used for creating the appCtx
- // chosen based on the sync/async configuration
- TaskExecutor executor = null;
-
- String creationType;
-
- // synch/asynch context creation
- if (asynch) {
- // for the async stuff use the executor
- executor = taskExecutor;
- creationType = "Asynchronous";
- } else {
- // for the sync stuff, use this thread
- executor = sameThreadTaskExecutor;
- creationType = "Synchronous";
- }
-
- if (debug) {
- log.debug(creationType + " context creation for bundle " + bundleString);
- }
-
- // wait/no wait for dependencies behaviour
- if (config.isWaitForDependencies()) {
- DependencyWaiterApplicationContextExecutor appCtxExecutor =
- new DependencyWaiterApplicationContextExecutor(localApplicationContext, !asynch,
- extenderConfiguration.getDependencyFactories());
-
- long timeout;
- // check whether a timeout has been defined
-
- if (config.isTimeoutDeclared()) {
- timeout = config.getTimeout();
- if (debug)
- log.debug("Setting bundle-defined, wait-for-dependencies/graceperiod timeout value=" + timeout
- + " ms, for bundle " + bundleString);
-
- } else {
- timeout = extenderConfiguration.getDependencyWaitTime();
- if (debug)
- log.debug("Setting globally defined wait-for-dependencies/graceperiod timeout value=" + timeout
- + " ms, for bundle " + bundleString);
- }
-
- appCtxExecutor.setTimeout(timeout);
- appCtxExecutor.setWatchdog(timer);
- appCtxExecutor.setTaskExecutor(executor);
- appCtxExecutor.setMonitoringCounter(contextsStarted);
- // set events publisher
- appCtxExecutor.setDelegatedMulticaster(this.multicaster);
-
- contextsStarted.increment();
- } else {
- // do nothing; by default contexts do not wait for services.
- }
-
- executor.execute(contextRefresh);
- }
-
- /**
- * Closing an application context is a potentially long-running activity, however, we *have* to do it synchronously
- * during the event process as the BundleContext object is not valid once we return from this method.
- *
- * @param bundle
- */
- protected void maybeCloseApplicationContextFor(Bundle bundle) {
- final ConfigurableOsgiBundleApplicationContext context =
- (ConfigurableOsgiBundleApplicationContext) managedContexts.remove(Long.valueOf(bundle.getBundleId()));
- if (context == null) {
- return;
- }
-
- RunnableTimedExecution.execute(new Runnable() {
-
- private final String toString = "Closing runnable for context " + context.getDisplayName();
-
- public void run() {
- closeApplicationContext(context);
- }
-
- public String toString() {
- return toString;
- }
-
- }, extenderConfiguration.getShutdownWaitTime(), shutdownTaskExecutor);
- }
-
- /**
- * Closes an application context. This is a convenience methods that invokes the event notification as well.
- *
- * @param ctx
- */
- private void closeApplicationContext(ConfigurableOsgiBundleApplicationContext ctx) {
- if (log.isDebugEnabled()) {
- log.debug("Closing application context " + ctx.getDisplayName());
- }
-
- if (log.isTraceEnabled()) {
- log.trace("Calling pre-close on processor " + processor);
- }
- processor.preProcessClose(ctx);
- try {
- ctx.close();
- } finally {
- if (log.isTraceEnabled()) {
- log.trace("Calling post close on processor " + processor);
- }
- processor.postProcessClose(ctx);
- }
- }
-
- public void destroy() {
- // first stop the watchdog
- stopTimer();
-
- // get hold of the needed bundles
- List<Bundle> bundles = new ArrayList<Bundle>(managedContexts.size());
-
- for (ConfigurableOsgiBundleApplicationContext context : managedContexts.values()) {
- bundles.add(context.getBundle());
- }
-
- boolean debug = log.isDebugEnabled();
-
- if (debug) {
- log.debug("Starting shutdown procedure for bundles " + bundles);
- }
- while (!bundles.isEmpty()) {
- Collection<Bundle> candidates = ShutdownSorter.getBundles(bundles);
- if (debug)
- log.debug("Staging shutdown for bundles " + candidates);
-
- final List<Runnable> taskList = new ArrayList<Runnable>(candidates.size());
- final List<ConfigurableOsgiBundleApplicationContext> closedContexts =
- Collections.synchronizedList(new ArrayList<ConfigurableOsgiBundleApplicationContext>());
- final Object[] contextClosingDown = new Object[1];
-
- for (Bundle shutdownBundle : candidates) {
- final ConfigurableOsgiBundleApplicationContext context = getManagedContext(shutdownBundle);
- if (context != null) {
- closedContexts.add(context);
- // add a new runnable
- taskList.add(new Runnable() {
-
- private final String toString = "Closing runnable for context " + context.getDisplayName();
-
- public void run() {
- contextClosingDown[0] = context;
- // eliminate context
- closedContexts.remove(context);
- closeApplicationContext(context);
- }
-
- public String toString() {
- return toString;
- }
- });
- }
- }
-
- // tasks
- final Runnable[] tasks = (Runnable[]) taskList.toArray(new Runnable[taskList.size()]);
-
- // start the ripper >:)
- for (int j = 0; j < tasks.length; j++) {
- if (RunnableTimedExecution.execute(tasks[j], extenderConfiguration.getShutdownWaitTime(),
- shutdownTaskExecutor)) {
- if (debug) {
- log.debug(contextClosingDown[0] + " context did not close successfully; forcing shutdown...");
- }
- }
- }
- }
-
- this.managedContexts.clear();
-
- // before bailing out; wait for the threads that might be left by
- // the task executor
- stopTaskExecutor();
- }
-
- public ConfigurableOsgiBundleApplicationContext getManagedContext(Bundle bundle) {
- ConfigurableOsgiBundleApplicationContext context = null;
- try {
- Long id = new Long(bundle.getBundleId());
- context = (ConfigurableOsgiBundleApplicationContext) managedContexts.get(id);
- } catch (IllegalStateException _) {
- // ignore
- }
- return context;
- }
-
- /**
- * Do some additional waiting so the service dependency listeners detect the shutdown.
- */
- private void stopTaskExecutor() {
- boolean debug = log.isDebugEnabled();
-
- if (debug)
- log.debug("Waiting for " + contextsStarted + " service dependency listener(s) to stop...");
-
- contextsStarted.waitForZero(extenderConfiguration.getShutdownWaitTime());
-
- if (!contextsStarted.isZero()) {
- if (debug)
- log.debug(contextsStarted.getValue()
- + " service dependency listener(s) did not responded in time; forcing them to shutdown...");
- extenderConfiguration.setForceThreadShutdown(true);
- }
-
- else
- log.debug("All listeners closed");
- }
-
- /**
- * Cancel any tasks scheduled for the timer.
- */
- private void stopTimer() {
- if (log.isDebugEnabled())
- log.debug("Canceling timer tasks");
- timer.cancel();
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
+import org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
+import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
+import org.eclipse.gemini.blueprint.extender.OsgiBeanFactoryPostProcessor;
+import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ShutdownSorter;
+import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor;
+import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
+import org.eclipse.gemini.blueprint.extender.internal.support.OsgiBeanFactoryPostProcessorAdapter;
+import org.eclipse.gemini.blueprint.extender.internal.util.concurrent.Counter;
+import org.eclipse.gemini.blueprint.extender.internal.util.concurrent.RunnableTimedExecution;
+import org.eclipse.gemini.blueprint.extender.support.ApplicationContextConfiguration;
+import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
+import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.core.task.SyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manager handling the startup/shutdown threading issues regarding OSGi contexts. Used by {@link ContextLoaderListener}
+ * .
+ *
+ * @author Costin Leau
+ */
+class LifecycleManager implements DisposableBean {
+
+ /** logger */
+ private static final Log log = LogFactory.getLog(LifecycleManager.class);
+
+ /**
+ * The contexts we are currently managing. Keys are bundle ids, values are ServiceDependentOsgiApplicationContexts
+ * for the application context
+ */
+ private final Map<Long, ConfigurableOsgiBundleApplicationContext> managedContexts =
+ new ConcurrentHashMap<Long, ConfigurableOsgiBundleApplicationContext>(16);
+
+ /** listener counter - used to properly synchronize shutdown */
+ private Counter contextsStarted = new Counter("contextsStarted");
+
+ // "Spring Application Context Creation Timer"
+ private final Timer timer = new Timer("Spring DM Context Creation Timer", true);
+
+ /** Task executor used for bootstraping the Spring contexts in async mode */
+ private final TaskExecutor taskExecutor;
+
+ /** ApplicationContext Creator */
+ private final OsgiApplicationContextCreator contextCreator;
+
+ /** BFPP list */
+ private final List<OsgiBeanFactoryPostProcessor> postProcessors;
+
+ /** shutdown task executor */
+ private final TaskExecutor shutdownTaskExecutor;
+
+ /**
+ * Task executor which uses the same thread for running tasks. Used when doing a synchronous wait-for-dependencies.
+ */
+ private final TaskExecutor sameThreadTaskExecutor = new SyncTaskExecutor();
+
+ private final OsgiBundleApplicationContextEventMulticaster multicaster;
+
+ private final ExtenderConfiguration extenderConfiguration;
+
+ private final BundleContext bundleContext;
+
+ private final OsgiContextProcessor processor;
+
+ private final ApplicationContextConfigurationFactory contextConfigurationFactory;
+
+ private final VersionMatcher versionMatcher;
+ private final TypeCompatibilityChecker typeChecker;
+
+ LifecycleManager(ExtenderConfiguration extenderConfiguration, VersionMatcher versionMatcher,
+ ApplicationContextConfigurationFactory appCtxCfgFactory, OsgiApplicationContextCreator osgiApplicationContextCreator, OsgiContextProcessor processor,
+ TypeCompatibilityChecker checker, BundleContext context) {
+
+ this.versionMatcher = versionMatcher;
+ this.extenderConfiguration = extenderConfiguration;
+ this.contextConfigurationFactory = appCtxCfgFactory;
+ this.contextCreator = osgiApplicationContextCreator;
+ this.processor = processor;
+
+ this.taskExecutor = extenderConfiguration.getTaskExecutor();
+ this.shutdownTaskExecutor = extenderConfiguration.getShutdownTaskExecutor();
+
+ this.multicaster = extenderConfiguration.getEventMulticaster();
+
+ this.postProcessors = extenderConfiguration.getPostProcessors();
+ this.typeChecker = checker;
+
+ this.bundleContext = context;
+ }
+
+ /**
+ * Context creation is a potentially long-running activity (certainly more than we want to do on the synchronous
+ * event callback).
+ *
+ * <p/> Based on our configuration, the context can be started on the same thread or on a different one.
+ *
+ * <p/> Kick off a background activity to create an application context for the given bundle if needed.
+ *
+ * <b>Note:</b> Make sure to do the fastest filtering first to avoid slow-downs on platforms with a big number of
+ * plugins and wiring (i.e. Eclipse platform).
+ *
+ * @param bundle
+ */
+ protected void maybeCreateApplicationContextFor(Bundle bundle) {
+
+ boolean debug = log.isDebugEnabled();
+ String bundleString = "[" + OsgiStringUtils.nullSafeNameAndSymName(bundle) + "]";
+
+ final Long bundleId = new Long(bundle.getBundleId());
+
+ if (managedContexts.containsKey(bundleId)) {
+ if (debug) {
+ log.debug("Bundle " + bundleString + " is already managed; ignoring...");
+ }
+ return;
+ }
+
+ if (!versionMatcher.matchVersion(bundle)) {
+ return;
+ }
+
+ BundleContext localBundleContext = OsgiBundleUtils.getBundleContext(bundle);
+
+ // initialize context
+ final DelegatedExecutionOsgiBundleApplicationContext localApplicationContext;
+
+ if (debug)
+ log.debug("Inspecting bundle " + bundleString);
+
+ try {
+ localApplicationContext = contextCreator.createApplicationContext(localBundleContext);
+ } catch (Exception ex) {
+ log.error("Cannot create application context for bundle " + bundleString, ex);
+ return;
+ }
+
+ if (localApplicationContext == null) {
+ log.debug("No application context created for bundle " + bundleString);
+ return;
+ }
+
+ if (typeChecker != null) {
+ if (!typeChecker.isTypeCompatible(localBundleContext)) {
+ log.info("Bundle " + OsgiStringUtils.nullSafeName(bundle) + " is not type compatible with extender "
+ + OsgiStringUtils.nullSafeName(bundleContext.getBundle()) + "; ignoring bundle...");
+ return;
+ }
+ }
+
+ log.debug("Bundle " + OsgiStringUtils.nullSafeName(bundle) + " is type compatible with extender "
+ + OsgiStringUtils.nullSafeName(bundleContext.getBundle()) + "; processing bundle...");
+
+ // create a dedicated hook for this application context
+ BeanFactoryPostProcessor processingHook =
+ new OsgiBeanFactoryPostProcessorAdapter(localBundleContext, postProcessors);
+
+ // add in the post processors
+ localApplicationContext.addBeanFactoryPostProcessor(processingHook);
+
+ // add the context to the tracker
+ managedContexts.put(bundleId, localApplicationContext);
+
+ localApplicationContext.setDelegatedEventMulticaster(multicaster);
+
+ ApplicationContextConfiguration config = contextConfigurationFactory.createConfiguration(bundle);
+
+ final boolean asynch = config.isCreateAsynchronously();
+
+ // create refresh runnable
+ Runnable contextRefresh = new Runnable() {
+
+ public void run() {
+ // post refresh events are caught through events
+ if (log.isTraceEnabled()) {
+ log.trace("Calling pre-refresh on processor " + processor);
+ }
+ processor.preProcessRefresh(localApplicationContext);
+ localApplicationContext.refresh();
+ }
+ };
+
+ // executor used for creating the appCtx
+ // chosen based on the sync/async configuration
+ TaskExecutor executor = null;
+
+ String creationType;
+
+ // synch/asynch context creation
+ if (asynch) {
+ // for the async stuff use the executor
+ executor = taskExecutor;
+ creationType = "Asynchronous";
+ } else {
+ // for the sync stuff, use this thread
+ executor = sameThreadTaskExecutor;
+ creationType = "Synchronous";
+ }
+
+ if (debug) {
+ log.debug(creationType + " context creation for bundle " + bundleString);
+ }
+
+ // wait/no wait for dependencies behaviour
+ if (config.isWaitForDependencies()) {
+ DependencyWaiterApplicationContextExecutor appCtxExecutor =
+ new DependencyWaiterApplicationContextExecutor(localApplicationContext, !asynch,
+ extenderConfiguration.getDependencyFactories());
+
+ long timeout;
+ // check whether a timeout has been defined
+
+ if (config.isTimeoutDeclared()) {
+ timeout = config.getTimeout();
+ if (debug)
+ log.debug("Setting bundle-defined, wait-for-dependencies/graceperiod timeout value=" + timeout
+ + " ms, for bundle " + bundleString);
+
+ } else {
+ timeout = extenderConfiguration.getDependencyWaitTime();
+ if (debug)
+ log.debug("Setting globally defined wait-for-dependencies/graceperiod timeout value=" + timeout
+ + " ms, for bundle " + bundleString);
+ }
+
+ appCtxExecutor.setTimeout(timeout);
+ appCtxExecutor.setWatchdog(timer);
+ appCtxExecutor.setTaskExecutor(executor);
+ appCtxExecutor.setMonitoringCounter(contextsStarted);
+ // set events publisher
+ appCtxExecutor.setDelegatedMulticaster(this.multicaster);
+
+ contextsStarted.increment();
+ } else {
+ // do nothing; by default contexts do not wait for services.
+ }
+
+ executor.execute(contextRefresh);
+ }
+
+ /**
+ * Closing an application context is a potentially long-running activity, however, we *have* to do it synchronously
+ * during the event process as the BundleContext object is not valid once we return from this method.
+ *
+ * @param bundle
+ */
+ protected void maybeCloseApplicationContextFor(Bundle bundle) {
+ final ConfigurableOsgiBundleApplicationContext context =
+ (ConfigurableOsgiBundleApplicationContext) managedContexts.remove(Long.valueOf(bundle.getBundleId()));
+ if (context == null) {
+ return;
+ }
+
+ RunnableTimedExecution.execute(new Runnable() {
+
+ private final String toString = "Closing runnable for context " + context.getDisplayName();
+
+ public void run() {
+ closeApplicationContext(context);
+ }
+
+ public String toString() {
+ return toString;
+ }
+
+ }, extenderConfiguration.getShutdownWaitTime(), shutdownTaskExecutor);
+ }
+
+ /**
+ * Closes an application context. This is a convenience methods that invokes the event notification as well.
+ *
+ * @param ctx
+ */
+ private void closeApplicationContext(ConfigurableOsgiBundleApplicationContext ctx) {
+ if (log.isDebugEnabled()) {
+ log.debug("Closing application context " + ctx.getDisplayName());
+ }
+
+ if (log.isTraceEnabled()) {
+ log.trace("Calling pre-close on processor " + processor);
+ }
+ processor.preProcessClose(ctx);
+ try {
+ ctx.close();
+ } finally {
+ if (log.isTraceEnabled()) {
+ log.trace("Calling post close on processor " + processor);
+ }
+ processor.postProcessClose(ctx);
+ }
+ }
+
+ public void destroy() {
+ // first stop the watchdog
+ stopTimer();
+
+ // get hold of the needed bundles
+ List<Bundle> bundles = new ArrayList<Bundle>(managedContexts.size());
+
+ for (ConfigurableOsgiBundleApplicationContext context : managedContexts.values()) {
+ bundles.add(context.getBundle());
+ }
+
+ boolean debug = log.isDebugEnabled();
+
+ if (debug) {
+ log.debug("Starting shutdown procedure for bundles " + bundles);
+ }
+ while (!bundles.isEmpty()) {
+ Collection<Bundle> candidates = ShutdownSorter.getBundles(bundles);
+ if (debug)
+ log.debug("Staging shutdown for bundles " + candidates);
+
+ final List<Runnable> taskList = new ArrayList<Runnable>(candidates.size());
+ final List<ConfigurableOsgiBundleApplicationContext> closedContexts =
+ Collections.synchronizedList(new ArrayList<ConfigurableOsgiBundleApplicationContext>());
+ final Object[] contextClosingDown = new Object[1];
+
+ for (Bundle shutdownBundle : candidates) {
+ final ConfigurableOsgiBundleApplicationContext context = getManagedContext(shutdownBundle);
+ if (context != null) {
+ closedContexts.add(context);
+ // add a new runnable
+ taskList.add(new Runnable() {
+
+ private final String toString = "Closing runnable for context " + context.getDisplayName();
+
+ public void run() {
+ contextClosingDown[0] = context;
+ // eliminate context
+ closedContexts.remove(context);
+ closeApplicationContext(context);
+ }
+
+ public String toString() {
+ return toString;
+ }
+ });
+ }
+ }
+
+ // tasks
+ final Runnable[] tasks = (Runnable[]) taskList.toArray(new Runnable[taskList.size()]);
+
+ // start the ripper >:)
+ for (int j = 0; j < tasks.length; j++) {
+ if (RunnableTimedExecution.execute(tasks[j], extenderConfiguration.getShutdownWaitTime(),
+ shutdownTaskExecutor)) {
+ if (debug) {
+ log.debug(contextClosingDown[0] + " context did not close successfully; forcing shutdown...");
+ }
+ }
+ }
+ }
+
+ this.managedContexts.clear();
+
+ // before bailing out; wait for the threads that might be left by
+ // the task executor
+ stopTaskExecutor();
+ }
+
+ public ConfigurableOsgiBundleApplicationContext getManagedContext(Bundle bundle) {
+ ConfigurableOsgiBundleApplicationContext context = null;
+ try {
+ Long id = new Long(bundle.getBundleId());
+ context = (ConfigurableOsgiBundleApplicationContext) managedContexts.get(id);
+ } catch (IllegalStateException _) {
+ // ignore
+ }
+ return context;
+ }
+
+ /**
+ * Do some additional waiting so the service dependency listeners detect the shutdown.
+ */
+ private void stopTaskExecutor() {
+ boolean debug = log.isDebugEnabled();
+
+ if (debug)
+ log.debug("Waiting for " + contextsStarted + " service dependency listener(s) to stop...");
+
+ contextsStarted.waitForZero(extenderConfiguration.getShutdownWaitTime());
+
+ if (!contextsStarted.isZero()) {
+ if (debug)
+ log.debug(contextsStarted.getValue()
+ + " service dependency listener(s) did not responded in time; forcing them to shutdown...");
+ extenderConfiguration.setForceThreadShutdown(true);
+ }
+
+ else
+ log.debug("All listeners closed");
+ }
+
+ /**
+ * Cancel any tasks scheduled for the timer.
+ */
+ private void stopTimer() {
+ if (log.isDebugEnabled())
+ log.debug("Canceling timer tasks");
+ timer.cancel();
+ }
} \ No newline at end of file
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListListenerAdapter.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListListenerAdapter.java
index bcb9283..1246757 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListListenerAdapter.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListListenerAdapter.java
@@ -1,94 +1,89 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.activator;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.util.tracker.ServiceTracker;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.core.GenericTypeResolver;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEvent;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
-
-/**
- * Listener interface that delegates to a list of listener. This is useful in OSGi environments when dealing with
- * dynamic collections which can be updated during iteration.
- *
- * @author Costin Leau
- *
- */
-@SuppressWarnings("unchecked")
-class ListListenerAdapter implements OsgiBundleApplicationContextListener<OsgiBundleApplicationContextEvent>,
- InitializingBean, DisposableBean {
-
- private final ServiceTracker tracker;
- private final Map<Class<? extends OsgiBundleApplicationContextListener>, Class<? extends OsgiBundleApplicationContextEvent>> eventCache =
- new WeakHashMap<Class<? extends OsgiBundleApplicationContextListener>, Class<? extends OsgiBundleApplicationContextEvent>>();
-
- /**
- * Constructs a new <code>ListListenerAdapter</code> instance.
- *
- * @param listeners
- */
- public ListListenerAdapter(BundleContext bundleContext) {
- this.tracker = new ServiceTracker(bundleContext, OsgiBundleApplicationContextListener.class.getName(), null);
- }
-
- public void afterPropertiesSet() {
- this.tracker.open();
- }
-
- public void destroy() {
- this.tracker.close();
- eventCache.clear();
- }
-
- public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
- Object[] listeners = tracker.getServices();
-
- if (listeners != null) {
- synchronized (eventCache) {
- for (Object listnr : listeners) {
- OsgiBundleApplicationContextListener listener = (OsgiBundleApplicationContextListener) listnr;
- Class<? extends OsgiBundleApplicationContextListener> listenerClass = listener.getClass();
- Class<? extends OsgiBundleApplicationContextEvent> eventType = eventCache.get(listenerClass);
- if (eventType == null) {
- Class<?> evtType =
- GenericTypeResolver.resolveTypeArgument(listenerClass,
- OsgiBundleApplicationContextListener.class);
- if (evtType == null) {
- evtType = OsgiBundleApplicationContextEvent.class;
- }
- if (evtType != null && evtType.isAssignableFrom(OsgiBundleApplicationContextEvent.class)) {
- eventType = (Class<? extends OsgiBundleApplicationContextEvent>) evtType;
- } else {
- eventType = OsgiBundleApplicationContextEvent.class;
- }
- eventCache.put(listenerClass, eventType);
- }
- if (eventType.isInstance(event)) {
- listener.onOsgiApplicationEvent(event);
- }
- }
- }
- }
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEvent;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.GenericTypeResolver;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * Listener interface that delegates to a list of listener. This is useful in OSGi environments when dealing with
+ * dynamic collections which can be updated during iteration.
+ *
+ * @author Costin Leau
+ *
+ */
+@SuppressWarnings("unchecked")
+class ListListenerAdapter implements OsgiBundleApplicationContextListener<OsgiBundleApplicationContextEvent>,
+ InitializingBean, DisposableBean {
+
+ private final ServiceTracker tracker;
+ private final Map<Class<? extends OsgiBundleApplicationContextListener>, Class<? extends OsgiBundleApplicationContextEvent>> eventCache =
+ new WeakHashMap<Class<? extends OsgiBundleApplicationContextListener>, Class<? extends OsgiBundleApplicationContextEvent>>();
+
+ /**
+ * Constructs a new <code>ListListenerAdapter</code> instance.
+ */
+ public ListListenerAdapter(BundleContext bundleContext) {
+ this.tracker = new ServiceTracker(bundleContext, OsgiBundleApplicationContextListener.class.getName(), null);
+ }
+
+ public void afterPropertiesSet() {
+ this.tracker.open();
+ }
+
+ public void destroy() {
+ this.tracker.close();
+ eventCache.clear();
+ }
+
+ public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
+ Object[] listeners = tracker.getServices();
+
+ if (listeners != null) {
+ synchronized (eventCache) {
+ for (Object listnr : listeners) {
+ OsgiBundleApplicationContextListener listener = (OsgiBundleApplicationContextListener) listnr;
+ Class<? extends OsgiBundleApplicationContextListener> listenerClass = listener.getClass();
+ Class<? extends OsgiBundleApplicationContextEvent> eventType = eventCache.get(listenerClass);
+ if (eventType == null) {
+ Class<?> evtType =
+ GenericTypeResolver.resolveTypeArgument(listenerClass,
+ OsgiBundleApplicationContextListener.class);
+ if (evtType == null) {
+ evtType = OsgiBundleApplicationContextEvent.class;
+ }
+ if (evtType != null && evtType.isAssignableFrom(OsgiBundleApplicationContextEvent.class)) {
+ eventType = (Class<? extends OsgiBundleApplicationContextEvent>) evtType;
+ } else {
+ eventType = OsgiBundleApplicationContextEvent.class;
+ }
+ eventCache.put(listenerClass, eventType);
+ }
+ if (eventType.isInstance(event)) {
+ listener.onOsgiApplicationEvent(event);
+ }
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListenerServiceActivator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListenerServiceActivator.java
new file mode 100644
index 0000000..1713da4
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListenerServiceActivator.java
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
+import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Initializes the event multicaster infrastructure.
+ *
+ * @author Bill Gallagher
+ * @author Andy Piper
+ * @author Hal Hildebrand
+ * @author Adrian Colyer
+ * @author Costin Leau
+ * @author Olaf Otto
+ */
+public class ListenerServiceActivator implements BundleActivator {
+ /**
+ * Monitor used for dealing with the bundle activator and synchronous bundle threads
+ */
+ private final Object monitor = new Object();
+ private boolean stopped = false;
+ private OsgiBundleApplicationContextEventMulticaster multicaster;
+ private volatile ListListenerAdapter osgiListeners;
+ private final Log log = LogFactory.getLog(getClass());
+ private final ExtenderConfiguration extenderConfiguration;
+ private BundleContext extenderBundleContext;
+
+ public ListenerServiceActivator(ExtenderConfiguration extenderConfiguration) {
+ this.extenderConfiguration = extenderConfiguration;
+ }
+
+ public void start(BundleContext extenderBundleContext) throws Exception {
+ this.extenderBundleContext = extenderBundleContext;
+ initListenerService();
+ }
+
+ public void stop(BundleContext extenderBundleContext) throws Exception {
+ synchronized (monitor) {
+ if (stopped) {
+ return;
+ }
+ stopped = true;
+ }
+
+ // release multicaster
+ if (multicaster != null) {
+ multicaster.removeAllListeners();
+ multicaster = null;
+ }
+ // release listeners
+ osgiListeners.destroy();
+ osgiListeners = null;
+ }
+
+ protected void initListenerService() {
+ this.multicaster = extenderConfiguration.getEventMulticaster();
+
+ addApplicationListener(multicaster);
+ multicaster.addApplicationListener(extenderConfiguration.getContextEventListener());
+
+ if (log.isDebugEnabled())
+ log.debug("Initialization of OSGi listeners service completed...");
+ }
+
+ protected void addApplicationListener(OsgiBundleApplicationContextEventMulticaster multicaster) {
+ osgiListeners = new ListListenerAdapter(this.extenderBundleContext);
+ osgiListeners.afterPropertiesSet();
+ // register the listener that does the dispatching
+ multicaster.addApplicationListener(osgiListeners);
+ }
+
+ public OsgiBundleApplicationContextEventMulticaster getMulticaster() {
+ return multicaster;
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LoggingActivator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LoggingActivator.java
new file mode 100644
index 0000000..1427b6c
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LoggingActivator.java
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+
+/**
+ * Simply writes status convenient status information to the log.
+ *
+ * @author Olaf Otto
+ */
+public class LoggingActivator implements BundleActivator {
+ private final Log log = LogFactory.getLog(getClass());
+
+ public void start(BundleContext extenderBundleContext) throws Exception {
+ Version extenderVersion = OsgiBundleUtils.getBundleVersion(extenderBundleContext.getBundle());
+ log.info("Starting [" + extenderBundleContext.getBundle().getSymbolicName() + "] bundle v.[" + extenderVersion + "]");
+ }
+
+ public void stop(BundleContext extenderBundleContext) throws Exception {
+ Version extenderVersion = OsgiBundleUtils.getBundleVersion(extenderBundleContext.getBundle());
+ log.info("Stopping [" + extenderBundleContext.getBundle().getSymbolicName() + "] bundle v.[" + extenderVersion + "]");
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/NamespaceHandlerActivator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/NamespaceHandlerActivator.java
new file mode 100644
index 0000000..a53e439
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/NamespaceHandlerActivator.java
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.extender.internal.activator.listeners.BaseListener;
+import org.eclipse.gemini.blueprint.extender.internal.activator.listeners.NamespaceBundleLister;
+import org.eclipse.gemini.blueprint.extender.internal.support.NamespaceManager;
+import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
+import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
+import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+
+/**
+ * @author Bill Gallagher
+ * @author Andy Piper
+ * @author Hal Hildebrand
+ * @author Adrian Colyer
+ * @author Costin Leau
+ * @author Olaf Otto
+ */
+public class NamespaceHandlerActivator implements BundleActivator {
+ /**
+ * Monitor used for dealing with the bundle activator and synchronous bundle threads
+ */
+ private final Object monitor = new Object();
+ private boolean stopped = false;
+ private final Log log = LogFactory.getLog(getClass());
+ private NamespaceManager nsManager;
+ private BaseListener nsListener;
+ private long bundleId;
+ private BundleContext extenderBundleContext;
+ private DefaultVersionMatcher versionMatcher;
+
+ public void start(BundleContext extenderBundleContext) {
+ this.extenderBundleContext = extenderBundleContext;
+ this.nsManager = new NamespaceManager(extenderBundleContext);
+ this.bundleId = extenderBundleContext.getBundle().getBundleId();
+ Version extenderVersion = OsgiBundleUtils.getBundleVersion(extenderBundleContext.getBundle());
+ this.versionMatcher = new DefaultVersionMatcher(getManagedBundleExtenderVersionHeader(), extenderVersion);
+
+ initNamespaceHandlers(extenderBundleContext);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ synchronized (monitor) {
+ if (stopped) {
+ return;
+ }
+ stopped = true;
+ }
+
+ this.nsListener.close();
+ this.extenderBundleContext.removeBundleListener(this.nsListener);
+ this.nsListener = null;
+ this.nsManager.destroy();
+ }
+
+ protected String getManagedBundleExtenderVersionHeader() {
+ return ConfigUtils.EXTENDER_VERSION;
+ }
+
+ protected void initNamespaceHandlers(BundleContext extenderBundleContext) {
+ nsManager = new NamespaceManager(extenderBundleContext);
+
+ // register listener first to make sure any bundles in INSTALLED state
+ // are not lost
+
+ // if the property is defined and true, consider bundles in STARTED/LAZY-INIT state, otherwise use RESOLVED
+ boolean nsResolved = !Boolean.getBoolean("org.eclipse.gemini.blueprint.ns.bundles.started");
+ nsListener = new NamespaceBundleLister(nsResolved, this);
+ extenderBundleContext.addBundleListener(nsListener);
+
+ Bundle[] previousBundles = extenderBundleContext.getBundles();
+
+ for (Bundle bundle : previousBundles) {
+ // special handling for uber bundle being restarted
+ if ((nsResolved && OsgiBundleUtils.isBundleResolved(bundle)) || (!nsResolved && OsgiBundleUtils.isBundleActive(bundle)) || bundleId == bundle.getBundleId()) {
+ maybeAddNamespaceHandlerFor(bundle, false);
+ } else if (OsgiBundleUtils.isBundleLazyActivated(bundle)) {
+ maybeAddNamespaceHandlerFor(bundle, true);
+ }
+ }
+
+ // discovery finished, publish the resolvers/parsers in the OSGi space
+ nsManager.afterPropertiesSet();
+ }
+
+
+ public void maybeAddNamespaceHandlerFor(Bundle bundle, boolean isLazy) {
+ if (handlerBundleMatchesExtenderVersion(bundle)) {
+ nsManager.maybeAddNamespaceHandlerFor(bundle, isLazy);
+ }
+ }
+
+ public void maybeRemoveNameSpaceHandlerFor(Bundle bundle) {
+ if (handlerBundleMatchesExtenderVersion(bundle))
+ nsManager.maybeRemoveNameSpaceHandlerFor(bundle);
+ }
+
+ /**
+ * Utility method that does extender range version check and appropriate logging.
+ */
+ protected boolean handlerBundleMatchesExtenderVersion(Bundle bundle) {
+ if (!versionMatcher.matchVersion(bundle)) {
+ if (log.isDebugEnabled())
+ log.debug("Ignoring handler bundle " + OsgiStringUtils.nullSafeNameAndSymName(bundle)
+ + "] due to mismatch in expected extender version");
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/BaseListener.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/BaseListener.java
new file mode 100644
index 0000000..566c96a
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/BaseListener.java
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator.listeners;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * Common base class for {@link org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener} listeners.
+ *
+ * @author Costin Leau
+ */
+public abstract class BaseListener implements SynchronousBundleListener {
+ public static final int LAZY_ACTIVATION_EVENT_TYPE = 0x00000200;
+
+ protected final Log log = LogFactory.getLog(getClass());
+
+ /**
+ * flag indicating whether the context is down or not - useful during shutdown
+ */
+ private volatile boolean isClosed = false;
+
+ /**
+ * common cache used for tracking down bundles started lazily so they don't get processed twice (once when
+ * started lazy, once when started fully)
+ */
+ protected final Map<Bundle, Object> lazyBundleCache = new WeakHashMap<Bundle, Object>();
+ /**
+ * dummy value for the bundle cache
+ */
+ private final Object VALUE = new Object();
+
+ // caches the bundle
+ protected void push(Bundle bundle) {
+ synchronized (lazyBundleCache) {
+ lazyBundleCache.put(bundle, VALUE);
+ }
+ }
+
+ // checks the presence of the bundle as well as removing it
+ protected boolean pop(Bundle bundle) {
+ synchronized (lazyBundleCache) {
+ return (lazyBundleCache.remove(bundle) != null);
+ }
+ }
+
+ /**
+ * A bundle has been started, stopped, resolved, or unresolved. This method is a synchronous callback, do not do
+ * any long-running work in this thread.
+ *
+ * @see org.osgi.framework.SynchronousBundleListener#bundleChanged
+ */
+ public void bundleChanged(BundleEvent event) {
+
+ boolean trace = log.isTraceEnabled();
+
+ // check if the listener is still alive
+ if (isClosed) {
+ if (trace)
+ log.trace("Listener is closed; events are being ignored");
+ return;
+ }
+ if (trace) {
+ log.trace("Processing bundle event [" + OsgiStringUtils.nullSafeToString(event) + "] for bundle ["
+ + OsgiStringUtils.nullSafeSymbolicName(event.getBundle()) + "]");
+ }
+ try {
+ handleEvent(event);
+ } catch (Exception ex) {
+ /* log exceptions before swallowing */
+ log.warn("Got exception while handling event " + event, ex);
+ }
+ }
+
+ protected abstract void handleEvent(BundleEvent event);
+
+ public void close() {
+ this.isClosed = true;
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/NamespaceBundleLister.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/NamespaceBundleLister.java
new file mode 100644
index 0000000..79998f5
--- /dev/null
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/NamespaceBundleLister.java
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.activator.listeners;
+
+import org.eclipse.gemini.blueprint.extender.internal.activator.NamespaceHandlerActivator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+
+/**
+ * Bundle listener used for detecting namespace handler/resolvers. Exists as a separate listener so that it can be
+ * registered early to avoid race conditions with bundles in INSTALLING state but still to avoid premature context
+ * creation before the Spring {@link org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener} is not fully initialized.
+ *
+ * @author Costin Leau
+ */
+public class NamespaceBundleLister extends BaseListener {
+
+ private final boolean resolved;
+ private final NamespaceHandlerActivator namespaceHandlerActivator;
+
+ public NamespaceBundleLister(boolean resolvedBundles, NamespaceHandlerActivator namespaceHandlerActivator) {
+ this.resolved = resolvedBundles;
+ this.namespaceHandlerActivator = namespaceHandlerActivator;
+ }
+
+ protected void handleEvent(BundleEvent event) {
+ Bundle bundle = event.getBundle();
+
+ switch (event.getType()) {
+
+ case BundleEvent.RESOLVED:
+ if (resolved) {
+ this.namespaceHandlerActivator.maybeAddNamespaceHandlerFor(bundle, false);
+ }
+ break;
+
+ case LAZY_ACTIVATION_EVENT_TYPE: {
+ if (!resolved) {
+ push(bundle);
+ this.namespaceHandlerActivator.maybeAddNamespaceHandlerFor(bundle, true);
+ }
+ break;
+ }
+ case BundleEvent.STARTED: {
+ if (!resolved) {
+ if (!pop(bundle)) {
+ this.namespaceHandlerActivator.maybeAddNamespaceHandlerFor(bundle, false);
+ }
+ }
+ break;
+ }
+ case BundleEvent.STOPPED: {
+ pop(bundle);
+ this.namespaceHandlerActivator.maybeRemoveNameSpaceHandlerFor(bundle);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/BlueprintLoaderListener.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/BlueprintLoaderListener.java
index 27fb197..1e92751 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/BlueprintLoaderListener.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/BlueprintLoaderListener.java
@@ -1,101 +1,96 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.blueprint.activator;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
-import org.eclipse.gemini.blueprint.extender.internal.activator.ApplicationContextConfigurationFactory;
-import org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener;
-import org.eclipse.gemini.blueprint.extender.internal.activator.OsgiContextProcessor;
-import org.eclipse.gemini.blueprint.extender.internal.activator.TypeCompatibilityChecker;
-import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintConfigUtils;
-import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintContainerConfig;
-import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintExtenderConfiguration;
-import org.eclipse.gemini.blueprint.extender.internal.blueprint.event.EventAdminDispatcher;
-import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
-import org.eclipse.gemini.blueprint.extender.support.ApplicationContextConfiguration;
-
-/**
- * RFC124 extension to the Spring DM extender.
- *
- * @author Costin Leau
- */
-public class BlueprintLoaderListener extends ContextLoaderListener {
-
- private volatile EventAdminDispatcher dispatcher;
- private volatile BlueprintListenerManager listenerManager;
- private volatile Bundle bundle;
- private volatile BlueprintContainerProcessor contextProcessor;
- private volatile TypeCompatibilityChecker typeChecker;
-
- @Override
- public void start(BundleContext context) throws Exception {
- this.listenerManager = new BlueprintListenerManager(context);
- this.dispatcher = new EventAdminDispatcher(context);
- this.bundle = context.getBundle();
- this.contextProcessor = new BlueprintContainerProcessor(dispatcher, listenerManager, bundle);
- this.typeChecker = new BlueprintTypeCompatibilityChecker(bundle);
-
- super.start(context);
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- super.stop(context);
- listenerManager.destroy();
- }
-
- @Override
- protected ExtenderConfiguration initExtenderConfiguration(BundleContext bundleContext) {
- return new BlueprintExtenderConfiguration(bundleContext, log);
- }
-
- @Override
- protected ApplicationContextConfigurationFactory createContextConfigFactory() {
- return new ApplicationContextConfigurationFactory() {
-
- public ApplicationContextConfiguration createConfiguration(Bundle bundle) {
- return new BlueprintContainerConfig(bundle);
- }
- };
- }
-
- @Override
- protected OsgiContextProcessor createContextProcessor() {
- return contextProcessor;
- }
-
- @Override
- protected TypeCompatibilityChecker getTypeCompatibilityChecker() {
- return typeChecker;
- }
-
- @Override
- protected String getManagedBundleExtenderVersionHeader() {
- return BlueprintConfigUtils.EXTENDER_VERSION;
- }
-
- @Override
- protected void addApplicationListener(OsgiBundleApplicationContextEventMulticaster multicaster) {
- super.addApplicationListener(multicaster);
- // monitor bootstrapping events
- multicaster.addApplicationListener(contextProcessor);
- }
-
- protected ApplicationContextConfiguration createContextConfig(Bundle bundle) {
- return new BlueprintContainerConfig(bundle);
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.blueprint.activator;
+
+import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
+import org.eclipse.gemini.blueprint.extender.internal.activator.*;
+import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintConfigUtils;
+import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintContainerConfig;
+import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support.BlueprintContainerCreator;
+import org.eclipse.gemini.blueprint.extender.internal.blueprint.event.EventAdminDispatcher;
+import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
+import org.eclipse.gemini.blueprint.extender.support.ApplicationContextConfiguration;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * RFC124 extension to the Spring DM extender.
+ *
+ * @author Costin Leau
+ */
+public class BlueprintLoaderListener extends ContextLoaderListener {
+ private volatile BlueprintListenerManager listenerManager;
+ private volatile BlueprintContainerProcessor contextProcessor;
+ private volatile TypeCompatibilityChecker typeChecker;
+ private ListenerServiceActivator listenerServiceActivator;
+
+ public BlueprintLoaderListener(ExtenderConfiguration extenderConfiguration, ListenerServiceActivator listenerServiceActivator) {
+ super(extenderConfiguration);
+ this.listenerServiceActivator = listenerServiceActivator;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ this.listenerManager = new BlueprintListenerManager(context);
+ EventAdminDispatcher dispatcher = new EventAdminDispatcher(context);
+ Bundle bundle = context.getBundle();
+ this.contextProcessor = new BlueprintContainerProcessor(dispatcher, listenerManager, bundle);
+ this.typeChecker = new BlueprintTypeCompatibilityChecker(bundle);
+ this.listenerServiceActivator.getMulticaster().addApplicationListener(this.contextProcessor);
+ super.start(context);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ listenerManager.destroy();
+ }
+
+ @Override
+ protected ApplicationContextConfigurationFactory createContextConfigFactory() {
+ return new ApplicationContextConfigurationFactory() {
+
+ public ApplicationContextConfiguration createConfiguration(Bundle bundle) {
+ return new BlueprintContainerConfig(bundle);
+ }
+ };
+ }
+
+ /**
+ * Always use the {@link BlueprintContainerCreator}, never the configured creator.
+ * Rationale: Backwards compatibility. Both DM and Blueprint extenders are available simultaneously,
+ * however Blueprint extender support is new and must not be broken by existing configurations. Otherwise, existing
+ * users would have to make their creators aware of the difference between blueprint and dm containers.
+ */
+ @Override
+ protected OsgiApplicationContextCreator getOsgiApplicationContextCreator() {
+ return new BlueprintContainerCreator();
+ }
+
+ @Override
+ protected OsgiContextProcessor createContextProcessor() {
+ return contextProcessor;
+ }
+
+ @Override
+ protected TypeCompatibilityChecker getTypeCompatibilityChecker() {
+ return typeChecker;
+ }
+
+ @Override
+ protected String getManagedBundleExtenderVersionHeader() {
+ return BlueprintConfigUtils.EXTENDER_VERSION;
+ }
} \ No newline at end of file
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/support/BlueprintExtenderConfiguration.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/support/BlueprintExtenderConfiguration.java
deleted file mode 100644
index e95e7ac..0000000
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/support/BlueprintExtenderConfiguration.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.support;
-
-import org.apache.commons.logging.Log;
-import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
-import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
-import org.osgi.framework.BundleContext;
-
-/**
- * Extension of the default extender configuration for handling RFC 124 extender semantics.
- *
- * @author Costin Leau
- *
- */
-public class BlueprintExtenderConfiguration extends ExtenderConfiguration {
-
- private final OsgiApplicationContextCreator contextCreator = new BlueprintContainerCreator();
-
- /**
- * Constructs a new <code>BlueprintExtenderConfiguration</code> instance.
- *
- * @param bundleContext
- */
- public BlueprintExtenderConfiguration(BundleContext bundleContext, Log log) {
- super(bundleContext, log);
- }
-
- public OsgiApplicationContextCreator getContextCreator() {
- return contextCreator;
- }
-}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/boot/ChainActivator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/boot/ChainActivator.java
index a1605a6..a51d46c 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/boot/ChainActivator.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/boot/ChainActivator.java
@@ -1,69 +1,102 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.boot;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener;
-import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.BlueprintLoaderListener;
-import org.eclipse.gemini.blueprint.util.OsgiPlatformDetector;
-import org.springframework.util.ClassUtils;
-
-/**
- * Bundle activator that simply the lifecycle callbacks to other activators.
- *
- * @author Costin Leau
- *
- */
-public class ChainActivator implements BundleActivator {
-
- protected final Log log = LogFactory.getLog(getClass());
-
- private static final boolean BLUEPRINT_AVAILABLE =
- ClassUtils.isPresent("org.osgi.service.blueprint.container.BlueprintContainer", ChainActivator.class
- .getClassLoader());
-
- private final BundleActivator[] CHAIN;
-
- public ChainActivator() {
- if (OsgiPlatformDetector.isR42()) {
- if (BLUEPRINT_AVAILABLE) {
- log.info("Blueprint API detected; enabling Blueprint Container functionality");
- CHAIN = new BundleActivator[] { new ContextLoaderListener(), new BlueprintLoaderListener() };
- }
- else {
- log.warn("Blueprint API not found; disabling Blueprint Container functionality");
- CHAIN = new BundleActivator[] { new ContextLoaderListener() };
- }
- } else {
- log.warn("Pre-4.2 OSGi platform detected; disabling Blueprint Container functionality");
- CHAIN = new BundleActivator[] { new ContextLoaderListener() };
- }
- }
-
- public void start(BundleContext context) throws Exception {
- for (int i = 0; i < CHAIN.length; i++) {
- CHAIN[i].start(context);
- }
- }
-
- public void stop(BundleContext context) throws Exception {
- for (int i = CHAIN.length - 1; i >= 0; i--) {
- CHAIN[i].stop(context);
- }
- }
-}
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.boot;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.extender.internal.activator.*;
+import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.eclipse.gemini.blueprint.extender.internal.blueprint.activator.BlueprintLoaderListener;
+import org.eclipse.gemini.blueprint.util.OsgiPlatformDetector;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Bundle activator that simply the lifecycle callbacks to other activators.
+ *
+ * @author Costin Leau
+ *
+ */
+public class ChainActivator implements BundleActivator {
+
+ protected final Log log = LogFactory.getLog(getClass());
+
+ private static final boolean BLUEPRINT_AVAILABLE =
+ ClassUtils.isPresent("org.osgi.service.blueprint.container.BlueprintContainer", ChainActivator.class
+ .getClassLoader());
+
+ private final BundleActivator[] CHAIN;
+
+ public ChainActivator() {
+ final LoggingActivator logStatus = new LoggingActivator();
+ final JavaBeansCacheActivator activateJavaBeansCache = new JavaBeansCacheActivator();
+ final NamespaceHandlerActivator activateCustomNamespaceHandling = new NamespaceHandlerActivator();
+ final NamespaceHandlerActivator activateBlueprintspecificNamespaceHandling = new BlueprintNamespaceHandlerActivator();
+ final ExtenderConfiguration initializeExtenderConfiguration = new ExtenderConfiguration();
+ final ListenerServiceActivator activateListeners = new ListenerServiceActivator(initializeExtenderConfiguration);
+ final ContextLoaderListener listenForSpringDmBundles = new ContextLoaderListener(initializeExtenderConfiguration);
+ final BlueprintLoaderListener listenForBlueprintBundles = new BlueprintLoaderListener(initializeExtenderConfiguration, activateListeners);
+
+ if (OsgiPlatformDetector.isR42()) {
+ if (BLUEPRINT_AVAILABLE) {
+ log.info("Blueprint API detected; enabling Blueprint Container functionality");
+ CHAIN = new BundleActivator[] {
+ logStatus,
+ activateJavaBeansCache,
+ activateCustomNamespaceHandling,
+ activateBlueprintspecificNamespaceHandling,
+ initializeExtenderConfiguration,
+ activateListeners,
+ listenForSpringDmBundles,
+ listenForBlueprintBundles
+ };
+ }
+ else {
+ log.warn("Blueprint API not found; disabling Blueprint Container functionality");
+ CHAIN = new BundleActivator[] {
+ logStatus,
+ activateJavaBeansCache,
+ activateCustomNamespaceHandling,
+ initializeExtenderConfiguration,
+ activateListeners,
+ listenForSpringDmBundles
+ };
+ }
+ } else {
+ log.warn("Pre-4.2 OSGi platform detected; disabling Blueprint Container functionality");
+ CHAIN = new BundleActivator[] {
+ logStatus,
+ activateJavaBeansCache,
+ activateCustomNamespaceHandling,
+ initializeExtenderConfiguration,
+ activateListeners,
+ listenForSpringDmBundles
+ };
+ }
+ }
+
+ public void start(BundleContext context) throws Exception {
+ for (int i = 0; i < CHAIN.length; i++) {
+ CHAIN[i].start(context);
+ }
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ for (int i = CHAIN.length - 1; i >= 0; i--) {
+ CHAIN[i].stop(context);
+ }
+ }
+}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/DefaultOsgiBundleApplicationContextListener.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/DefaultOsgiBundleApplicationContextListener.java
index 073e4e6..0024427 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/DefaultOsgiBundleApplicationContextListener.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/DefaultOsgiBundleApplicationContextListener.java
@@ -1,67 +1,66 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- * Oracle Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.support;
-
-import org.apache.commons.logging.Log;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEvent;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextClosedEvent;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextFailedEvent;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextRefreshedEvent;
-import org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener;
-
-/**
- * Default application context event logger. Logs (using the {@link ContextLoaderListener} logger, the events received.
- *
- * @author Costin Leau
- * @author Andy Piper
- */
-public class DefaultOsgiBundleApplicationContextListener implements
- OsgiBundleApplicationContextListener<OsgiBundleApplicationContextEvent> {
-
- /** logger */
- private final Log log;
-
- public DefaultOsgiBundleApplicationContextListener(Log log) {
- this.log = log;
- }
-
- public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
- String applicationContextString = event.getApplicationContext().getDisplayName();
-
- if (event instanceof OsgiBundleContextRefreshedEvent) {
- log.info("Application context successfully refreshed (" + applicationContextString + ")");
- }
-
- if (event instanceof OsgiBundleContextFailedEvent) {
- OsgiBundleContextFailedEvent failureEvent = (OsgiBundleContextFailedEvent) event;
- log.error("Application context refresh failed (" + applicationContextString + ")", failureEvent
- .getFailureCause());
-
- }
-
- if (event instanceof OsgiBundleContextClosedEvent) {
- OsgiBundleContextClosedEvent closedEvent = (OsgiBundleContextClosedEvent) event;
- Throwable error = closedEvent.getFailureCause();
-
- if (error == null) {
- log.info("Application context succesfully closed (" + applicationContextString + ")");
- } else {
- log.error("Application context close failed (" + applicationContextString + ")", error);
- }
- }
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ * Oracle Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.support;
+
+import org.apache.commons.logging.Log;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEvent;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextClosedEvent;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextFailedEvent;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextRefreshedEvent;
+
+/**
+ * Default application context event logger. Logs (using the {@link org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener} logger, the events received.
+ *
+ * @author Costin Leau
+ * @author Andy Piper
+ */
+public class DefaultOsgiBundleApplicationContextListener implements
+ OsgiBundleApplicationContextListener<OsgiBundleApplicationContextEvent> {
+
+ /** logger */
+ private final Log log;
+
+ public DefaultOsgiBundleApplicationContextListener(Log log) {
+ this.log = log;
+ }
+
+ public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
+ String applicationContextString = event.getApplicationContext().getDisplayName();
+
+ if (event instanceof OsgiBundleContextRefreshedEvent) {
+ log.info("Application context successfully refreshed (" + applicationContextString + ")");
+ }
+
+ if (event instanceof OsgiBundleContextFailedEvent) {
+ OsgiBundleContextFailedEvent failureEvent = (OsgiBundleContextFailedEvent) event;
+ log.error("Application context refresh failed (" + applicationContextString + ")", failureEvent
+ .getFailureCause());
+
+ }
+
+ if (event instanceof OsgiBundleContextClosedEvent) {
+ OsgiBundleContextClosedEvent closedEvent = (OsgiBundleContextClosedEvent) event;
+ Throwable error = closedEvent.getFailureCause();
+
+ if (error == null) {
+ log.info("Application context succesfully closed (" + applicationContextString + ")");
+ } else {
+ log.error("Application context close failed (" + applicationContextString + ")", error);
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfiguration.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfiguration.java
index d6dd63e..78560ce 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfiguration.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfiguration.java
@@ -1,541 +1,529 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.support;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Properties;
-import java.util.Timer;
-
-import org.apache.commons.logging.Log;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.context.event.SimpleApplicationEventMulticaster;
-import org.springframework.core.task.SimpleAsyncTaskExecutor;
-import org.springframework.core.task.TaskExecutor;
-import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
-import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext;
-import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
-import org.eclipse.gemini.blueprint.extender.OsgiBeanFactoryPostProcessor;
-import org.eclipse.gemini.blueprint.extender.OsgiServiceDependencyFactory;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory;
-import org.eclipse.gemini.blueprint.extender.support.DefaultOsgiApplicationContextCreator;
-import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
-import org.eclipse.gemini.blueprint.util.BundleDelegatingClassLoader;
-import org.springframework.scheduling.timer.TimerTaskExecutor;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-
-/**
- * Configuration class for the extender. Takes care of locating the extender specific configurations and merging the
- * results with the defaults.
- *
- * @author Costin Leau
- */
-public class ExtenderConfiguration implements DisposableBean {
-
- /** logger */
- private final Log log;
-
- private static final String TASK_EXECUTOR_NAME = "taskExecutor";
-
- private static final String SHUTDOWN_TASK_EXECUTOR_NAME = "shutdownTaskExecutor";
-
- private static final String CONTEXT_CREATOR_NAME = "applicationContextCreator";
-
- private static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "osgiApplicationEventMulticaster";
-
- private static final String CONTEXT_LISTENER_NAME = "osgiApplicationContextListener";
-
- private static final String PROPERTIES_NAME = "extenderProperties";
-
- private static final String SHUTDOWN_WAIT_KEY = "shutdown.wait.time";
-
- private static final String PROCESS_ANNOTATIONS_KEY = "process.annotations";
-
- private static final String WAIT_FOR_DEPS_TIMEOUT_KEY = "dependencies.wait.time";
-
- private static final String EXTENDER_CFG_LOCATION = "META-INF/spring/extender";
-
- private static final String XML_PATTERN = "*.xml";
-
- private static final String ANNOTATION_DEPENDENCY_FACTORY =
- "org.eclipse.gemini.blueprint.extensions.annotation.ServiceReferenceDependencyBeanFactoryPostProcessor";
-
- /** annotation processing system property (kept for backwards compatibility) */
- private static final String AUTO_ANNOTATION_PROCESSING =
- "org.eclipse.gemini.blueprint.extender.annotation.auto.processing";
-
- //
- // defaults
- //
-
- // default dependency wait time (in milliseconds)
- private static final long DEFAULT_DEP_WAIT = ConfigUtils.DIRECTIVE_TIMEOUT_DEFAULT * 1000;
- private static final boolean DEFAULT_NS_BUNDLE_STATE = true;
- private static final long DEFAULT_SHUTDOWN_WAIT = 10 * 1000;
- private static final boolean DEFAULT_PROCESS_ANNOTATION = false;
-
- private ConfigurableOsgiBundleApplicationContext extenderConfiguration;
-
- private TaskExecutor taskExecutor, shutdownTaskExecutor;
-
- private boolean isTaskExecutorManagedInternally;
-
- private boolean isShutdownTaskExecutorManagedInternally;
-
- private boolean isMulticasterManagedInternally;
-
- private long shutdownWaitTime, dependencyWaitTime;
-
- private boolean processAnnotation, nsBundledResolved;
-
- private OsgiBundleApplicationContextEventMulticaster eventMulticaster;
-
- private OsgiBundleApplicationContextListener contextEventListener;
-
- private boolean forceThreadShutdown;
-
- private OsgiApplicationContextCreator contextCreator;
-
- /** bundle wrapped class loader */
- private final ClassLoader classLoader;
- /** List of context post processors */
- private final List<OsgiBeanFactoryPostProcessor> postProcessors =
- Collections.synchronizedList(new ArrayList<OsgiBeanFactoryPostProcessor>(0));
- /** List of service dependency factories */
- private final List<OsgiServiceDependencyFactory> dependencyFactories =
- Collections.synchronizedList(new ArrayList<OsgiServiceDependencyFactory>(0));
-
- // fields reading/writing lock
- private final Object lock = new Object();
-
- /**
- * Constructs a new <code>ExtenderConfiguration</code> instance. Locates the extender configuration, creates an
- * application context which will returned the extender items.
- *
- * @param bundleContext extender OSGi bundle context
- */
- public ExtenderConfiguration(BundleContext bundleContext, Log log) {
- this.log = log;
- Bundle bundle = bundleContext.getBundle();
- Properties properties = new Properties(createDefaultProperties());
-
- Enumeration<?> enm = bundle.findEntries(EXTENDER_CFG_LOCATION, XML_PATTERN, false);
-
- if (enm == null) {
- log.info("No custom extender configuration detected; using defaults...");
-
- synchronized (lock) {
- taskExecutor = createDefaultTaskExecutor();
- shutdownTaskExecutor = createDefaultShutdownTaskExecutor();
- eventMulticaster = createDefaultEventMulticaster();
- contextCreator = createDefaultApplicationContextCreator();
- contextEventListener = createDefaultApplicationContextListener();
-
- }
- classLoader = BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle);
- } else {
- String[] configs = copyEnumerationToList(enm);
-
- log.info("Detected extender custom configurations at " + ObjectUtils.nullSafeToString(configs));
- // create OSGi specific XML context
- ConfigurableOsgiBundleApplicationContext extenderAppCtx = new OsgiBundleXmlApplicationContext(configs);
- extenderAppCtx.setBundleContext(bundleContext);
- extenderAppCtx.refresh();
-
- synchronized (lock) {
- extenderConfiguration = extenderAppCtx;
- // initialize beans
- taskExecutor =
- extenderConfiguration.containsBean(TASK_EXECUTOR_NAME) ? (TaskExecutor) extenderConfiguration
- .getBean(TASK_EXECUTOR_NAME, TaskExecutor.class) : createDefaultTaskExecutor();
-
- shutdownTaskExecutor =
- extenderConfiguration.containsBean(SHUTDOWN_TASK_EXECUTOR_NAME) ? (TaskExecutor) extenderConfiguration
- .getBean(SHUTDOWN_TASK_EXECUTOR_NAME, TaskExecutor.class)
- : createDefaultShutdownTaskExecutor();
-
- eventMulticaster =
- extenderConfiguration.containsBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME) ? (OsgiBundleApplicationContextEventMulticaster) extenderConfiguration
- .getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
- OsgiBundleApplicationContextEventMulticaster.class)
- : createDefaultEventMulticaster();
-
- contextCreator =
- extenderConfiguration.containsBean(CONTEXT_CREATOR_NAME) ? (OsgiApplicationContextCreator) extenderConfiguration
- .getBean(CONTEXT_CREATOR_NAME, OsgiApplicationContextCreator.class)
- : createDefaultApplicationContextCreator();
-
- contextEventListener =
- extenderConfiguration.containsBean(CONTEXT_LISTENER_NAME) ? (OsgiBundleApplicationContextListener) extenderConfiguration
- .getBean(CONTEXT_LISTENER_NAME, OsgiBundleApplicationContextListener.class)
- : createDefaultApplicationContextListener();
- }
-
- // get post processors
- postProcessors.addAll(extenderConfiguration.getBeansOfType(OsgiBeanFactoryPostProcessor.class).values());
-
- // get dependency factories
- dependencyFactories.addAll(extenderConfiguration.getBeansOfType(OsgiServiceDependencyFactory.class)
- .values());
-
- classLoader = extenderConfiguration.getClassLoader();
- // extender properties using the defaults as backup
- if (extenderConfiguration.containsBean(PROPERTIES_NAME)) {
- Properties customProperties =
- (Properties) extenderConfiguration.getBean(PROPERTIES_NAME, Properties.class);
- Enumeration<?> propertyKey = customProperties.propertyNames();
- while (propertyKey.hasMoreElements()) {
- String property = (String) propertyKey.nextElement();
- properties.setProperty(property, customProperties.getProperty(property));
- }
- }
- }
-
- synchronized (lock) {
- shutdownWaitTime = getShutdownWaitTime(properties);
- dependencyWaitTime = getDependencyWaitTime(properties);
- processAnnotation = getProcessAnnotations(properties);
- }
-
- // load default dependency factories
- addDefaultDependencyFactories();
-
- // allow post processing
- contextCreator = postProcess(contextCreator);
- }
-
- /**
- * Allows post processing of the context creator.
- *
- * @param contextCreator
- * @return
- */
- protected OsgiApplicationContextCreator postProcess(OsgiApplicationContextCreator contextCreator) {
- return contextCreator;
- }
-
- /**
- * {@inheritDoc}
- *
- * Cleanup the configuration items.
- */
- public void destroy() {
-
- synchronized (lock) {
- if (isMulticasterManagedInternally) {
- eventMulticaster.removeAllListeners();
- eventMulticaster = null;
- }
-
- if (extenderConfiguration != null) {
- extenderConfiguration.close();
- extenderConfiguration = null;
- }
-
- // postpone the task executor shutdown
- if (forceThreadShutdown) {
-
- if (isTaskExecutorManagedInternally) {
- log.warn("Forcing the (internally created) taskExecutor to stop...");
- ThreadGroup th = ((SimpleAsyncTaskExecutor) taskExecutor).getThreadGroup();
- if (!th.isDestroyed()) {
- // ask the threads nicely to stop
- th.interrupt();
- }
- }
- taskExecutor = null;
- }
-
- if (isShutdownTaskExecutorManagedInternally) {
- try {
- ((DisposableBean) shutdownTaskExecutor).destroy();
- } catch (Exception ex) {
- log.debug("Received exception while shutting down shutdown task executor", ex);
- }
- shutdownTaskExecutor = null;
- }
- }
- }
-
- /**
- * Copies the URLs returned by the given enumeration and returns them as an array of Strings for consumption by the
- * application context.
- *
- * @param enm
- * @return
- */
- @SuppressWarnings("deprecation")
- private String[] copyEnumerationToList(Enumeration<?> enm) {
- List<String> urls = new ArrayList<String>(4);
- while (enm != null && enm.hasMoreElements()) {
- URL configURL = (URL) enm.nextElement();
- if (configURL != null) {
- String configURLAsString = configURL.toExternalForm();
- try {
- urls.add(URLDecoder.decode(configURLAsString, "UTF8"));
- } catch (UnsupportedEncodingException uee) {
- log.warn("UTF8 encoding not supported, using the platform default");
- urls.add(URLDecoder.decode(configURLAsString));
- }
- }
- }
-
- return (String[]) urls.toArray(new String[urls.size()]);
- }
-
- private Properties createDefaultProperties() {
- Properties properties = new Properties();
- properties.setProperty(SHUTDOWN_WAIT_KEY, "" + DEFAULT_SHUTDOWN_WAIT);
- properties.setProperty(PROCESS_ANNOTATIONS_KEY, "" + DEFAULT_PROCESS_ANNOTATION);
- properties.setProperty(WAIT_FOR_DEPS_TIMEOUT_KEY, "" + DEFAULT_DEP_WAIT);
-
- return properties;
- }
-
- protected void addDefaultDependencyFactories() {
- boolean debug = log.isDebugEnabled();
-
- // default JDK 1.4 processor
- dependencyFactories.add(0, new MandatoryImporterDependencyFactory());
-
- // load through reflection the dependency and injection processors if running on JDK 1.5 and annotation
- // processing is enabled
- if (processAnnotation) {
- // dependency processor
- Class<?> annotationProcessor = null;
- try {
- annotationProcessor =
- Class.forName(ANNOTATION_DEPENDENCY_FACTORY, false, ExtenderConfiguration.class
- .getClassLoader());
- } catch (ClassNotFoundException cnfe) {
- log.warn("Spring DM annotation package not found, annotation processing disabled.");
- log.debug("Spring DM annotation package not found, annotation processing disabled.", cnfe);
- return;
- }
- Object processor = BeanUtils.instantiateClass(annotationProcessor);
- Assert.isInstanceOf(OsgiServiceDependencyFactory.class, processor);
- dependencyFactories.add(1, (OsgiServiceDependencyFactory) processor);
-
- if (debug)
- log.debug("Succesfully loaded annotation dependency processor [" + ANNOTATION_DEPENDENCY_FACTORY + "]");
-
- // add injection processor (first in line)
- postProcessors.add(0, new OsgiAnnotationPostProcessor());
- log.info("Spring-DM annotation processing enabled");
- } else {
- if (debug) {
- log.debug("Spring-DM annotation processing disabled; [" + ANNOTATION_DEPENDENCY_FACTORY
- + "] not loaded");
- }
- }
-
- }
-
- private TaskExecutor createDefaultTaskExecutor() {
- // create thread-pool for starting contexts
- ThreadGroup threadGroup =
- new ThreadGroup("eclipse-gemini-blueprint-extender[" + ObjectUtils.getIdentityHexString(this) + "]-threads");
- threadGroup.setDaemon(false);
-
- SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
- taskExecutor.setThreadGroup(threadGroup);
- taskExecutor.setThreadNamePrefix("EclipseGeminiBlueprintExtenderThread-");
-
- isTaskExecutorManagedInternally = true;
-
- return taskExecutor;
- }
-
- private TaskExecutor createDefaultShutdownTaskExecutor() {
- TimerTaskExecutor taskExecutor = new TimerTaskExecutor() {
- @Override
- protected Timer createTimer() {
- return new Timer("Gemini Blueprint context shutdown thread", true);
- }
- };
-
- taskExecutor.afterPropertiesSet();
- isShutdownTaskExecutorManagedInternally = true;
- return taskExecutor;
- }
-
- private OsgiBundleApplicationContextEventMulticaster createDefaultEventMulticaster() {
- isMulticasterManagedInternally = true;
- return new OsgiBundleApplicationContextEventMulticasterAdapter(new SimpleApplicationEventMulticaster());
- }
-
- private OsgiApplicationContextCreator createDefaultApplicationContextCreator() {
- return new DefaultOsgiApplicationContextCreator();
- }
-
- private OsgiBundleApplicationContextListener createDefaultApplicationContextListener() {
- return new DefaultOsgiBundleApplicationContextListener(log);
- }
-
- private long getShutdownWaitTime(Properties properties) {
- return Long.parseLong(properties.getProperty(SHUTDOWN_WAIT_KEY));
- }
-
- private long getDependencyWaitTime(Properties properties) {
- return Long.parseLong(properties.getProperty(WAIT_FOR_DEPS_TIMEOUT_KEY));
- }
-
- private boolean getProcessAnnotations(Properties properties) {
- return Boolean.valueOf(properties.getProperty(PROCESS_ANNOTATIONS_KEY)).booleanValue()
- || Boolean.getBoolean(AUTO_ANNOTATION_PROCESSING);
- }
-
- /**
- * Returns the taskExecutor.
- *
- * @return Returns the taskExecutor
- */
- public TaskExecutor getTaskExecutor() {
- synchronized (lock) {
- return taskExecutor;
- }
- }
-
- /**
- * Returns the shutdown task executor.
- *
- * @return Returns the shutdown task executor
- */
- public TaskExecutor getShutdownTaskExecutor() {
- synchronized (lock) {
- return shutdownTaskExecutor;
- }
- }
-
- /**
- * Returns the contextEventListener.
- *
- * @return Returns the contextEventListener
- */
- public OsgiBundleApplicationContextListener getContextEventListener() {
- synchronized (lock) {
- return contextEventListener;
- }
- }
-
- /**
- * Returns the shutdownWaitTime.
- *
- * @return Returns the shutdownWaitTime
- */
- public long getShutdownWaitTime() {
- synchronized (lock) {
- return shutdownWaitTime;
- }
- }
-
- /**
- * Indicates if the process annotation is enabled or not.
- *
- * @return Returns true if the annotation should be processed or not otherwise.
- */
- public boolean shouldProcessAnnotation() {
- synchronized (lock) {
- return processAnnotation;
- }
- }
-
- /**
- * Returns the dependencyWaitTime.
- *
- * @return Returns the dependencyWaitTime
- */
- public long getDependencyWaitTime() {
- synchronized (lock) {
- return dependencyWaitTime;
- }
- }
-
- /**
- * Returns the eventMulticaster.
- *
- * @return Returns the eventMulticaster
- */
- public OsgiBundleApplicationContextEventMulticaster getEventMulticaster() {
- synchronized (lock) {
- return eventMulticaster;
- }
- }
-
- /**
- * Sets the flag to force the taskExtender to close up in case of runaway threads - this applies *only* if the
- * taskExecutor has been created internally.
- *
- * <p/> The flag will cause a best attempt to shutdown the threads.
- *
- * @param forceThreadShutdown The forceThreadShutdown to set.
- */
- public void setForceThreadShutdown(boolean forceThreadShutdown) {
- synchronized (lock) {
- this.forceThreadShutdown = forceThreadShutdown;
- }
- }
-
- /**
- * Returns the contextCreator.
- *
- * @return Returns the contextCreator
- */
- public OsgiApplicationContextCreator getContextCreator() {
- synchronized (lock) {
- return contextCreator;
- }
- }
-
- /**
- * Returns the postProcessors.
- *
- * @return Returns the postProcessors
- */
- public List<OsgiBeanFactoryPostProcessor> getPostProcessors() {
- return postProcessors;
- }
-
- /**
- * Returns the class loader wrapped around the extender bundle.
- *
- * @return extender bundle class loader
- */
- public ClassLoader getClassLoader() {
- return classLoader;
- }
-
- /**
- * Returns the dependencies factories declared by the extender configuration. The list automatically contains the
- * default listeners (such as the annotation one).
- *
- * @return list of dependency factories
- */
- public List<OsgiServiceDependencyFactory> getDependencyFactories() {
- return dependencyFactories;
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
+import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext;
+import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
+import org.eclipse.gemini.blueprint.extender.OsgiBeanFactoryPostProcessor;
+import org.eclipse.gemini.blueprint.extender.OsgiServiceDependencyFactory;
+import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory;
+import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
+import org.eclipse.gemini.blueprint.util.BundleDelegatingClassLoader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.event.SimpleApplicationEventMulticaster;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.timer.TimerTaskExecutor;
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.*;
+
+/**
+ * Configuration class for the extender. Takes care of locating the extender specific configurations and merging the
+ * results with the defaults.
+ *
+ * @author Costin Leau
+ */
+public class ExtenderConfiguration implements BundleActivator {
+
+ /** logger */
+ protected final Log log = LogFactory.getLog(getClass());
+
+ private static final String TASK_EXECUTOR_NAME = "taskExecutor";
+
+ private static final String SHUTDOWN_TASK_EXECUTOR_NAME = "shutdownTaskExecutor";
+
+ private static final String CONTEXT_CREATOR_NAME = "applicationContextCreator";
+
+ private static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "osgiApplicationEventMulticaster";
+
+ private static final String CONTEXT_LISTENER_NAME = "osgiApplicationContextListener";
+
+ private static final String PROPERTIES_NAME = "extenderProperties";
+
+ private static final String SHUTDOWN_WAIT_KEY = "shutdown.wait.time";
+
+ private static final String PROCESS_ANNOTATIONS_KEY = "process.annotations";
+
+ private static final String WAIT_FOR_DEPS_TIMEOUT_KEY = "dependencies.wait.time";
+
+ private static final String EXTENDER_CFG_LOCATION = "META-INF/spring/extender";
+
+ private static final String XML_PATTERN = "*.xml";
+
+ private static final String ANNOTATION_DEPENDENCY_FACTORY =
+ "org.eclipse.gemini.blueprint.extensions.annotation.ServiceReferenceDependencyBeanFactoryPostProcessor";
+
+ /** annotation processing system property (kept for backwards compatibility) */
+ private static final String AUTO_ANNOTATION_PROCESSING =
+ "org.eclipse.gemini.blueprint.extender.annotation.auto.processing";
+
+ //
+ // defaults
+ //
+
+ // default dependency wait time (in milliseconds)
+ private static final long DEFAULT_DEP_WAIT = ConfigUtils.DIRECTIVE_TIMEOUT_DEFAULT * 1000;
+ private static final boolean DEFAULT_NS_BUNDLE_STATE = true;
+ private static final long DEFAULT_SHUTDOWN_WAIT = 10 * 1000;
+ private static final boolean DEFAULT_PROCESS_ANNOTATION = false;
+
+ private ConfigurableOsgiBundleApplicationContext extenderConfiguration;
+
+ private TaskExecutor taskExecutor, shutdownTaskExecutor;
+
+ private boolean isTaskExecutorManagedInternally;
+
+ private boolean isShutdownTaskExecutorManagedInternally;
+
+ private boolean isMulticasterManagedInternally;
+
+ private long shutdownWaitTime, dependencyWaitTime;
+
+ private boolean processAnnotation, nsBundledResolved;
+
+ private OsgiBundleApplicationContextEventMulticaster eventMulticaster;
+
+ private OsgiBundleApplicationContextListener contextEventListener;
+
+ private boolean forceThreadShutdown;
+
+ private OsgiApplicationContextCreator contextCreator = null;
+
+ /** bundle wrapped class loader */
+ private ClassLoader classLoader;
+ /** List of context post processors */
+ private final List<OsgiBeanFactoryPostProcessor> postProcessors =
+ Collections.synchronizedList(new ArrayList<OsgiBeanFactoryPostProcessor>(0));
+ /** List of service dependency factories */
+ private final List<OsgiServiceDependencyFactory> dependencyFactories =
+ Collections.synchronizedList(new ArrayList<OsgiServiceDependencyFactory>(0));
+
+ // fields reading/writing lock
+ private final Object lock = new Object();
+
+ /**
+ * Constructs a new <code>ExtenderConfiguration</code> instance. Locates the extender configuration, creates an
+ * application context which will returned the extender items.
+ *
+ * @param extenderBundleContext extender OSGi bundle context
+ */
+ public void start(BundleContext extenderBundleContext) {
+ Bundle bundle = extenderBundleContext.getBundle();
+ Properties properties = new Properties(createDefaultProperties());
+
+ Enumeration<?> enm = bundle.findEntries(EXTENDER_CFG_LOCATION, XML_PATTERN, false);
+
+ if (enm == null) {
+ log.info("No custom extender configuration detected; using defaults...");
+ synchronized (lock) {
+ taskExecutor = createDefaultTaskExecutor();
+ shutdownTaskExecutor = createDefaultShutdownTaskExecutor();
+ eventMulticaster = createDefaultEventMulticaster();
+ contextEventListener = createDefaultApplicationContextListener();
+ }
+ classLoader = BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle);
+ } else {
+ String[] configs = copyEnumerationToList(enm);
+
+ log.info("Detected extender custom configurations at " + ObjectUtils.nullSafeToString(configs));
+ // create OSGi specific XML context
+ ConfigurableOsgiBundleApplicationContext extenderAppCtx = new OsgiBundleXmlApplicationContext(configs);
+ extenderAppCtx.setBundleContext(extenderBundleContext);
+ extenderAppCtx.refresh();
+
+ synchronized (lock) {
+ extenderConfiguration = extenderAppCtx;
+ // initialize beans
+ taskExecutor =
+ extenderConfiguration.containsBean(TASK_EXECUTOR_NAME) ? (TaskExecutor) extenderConfiguration
+ .getBean(TASK_EXECUTOR_NAME, TaskExecutor.class) : createDefaultTaskExecutor();
+
+ shutdownTaskExecutor =
+ extenderConfiguration.containsBean(SHUTDOWN_TASK_EXECUTOR_NAME) ? (TaskExecutor) extenderConfiguration
+ .getBean(SHUTDOWN_TASK_EXECUTOR_NAME, TaskExecutor.class)
+ : createDefaultShutdownTaskExecutor();
+
+ eventMulticaster =
+ extenderConfiguration.containsBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME) ? (OsgiBundleApplicationContextEventMulticaster) extenderConfiguration
+ .getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
+ OsgiBundleApplicationContextEventMulticaster.class)
+ : createDefaultEventMulticaster();
+
+ contextCreator =
+ extenderConfiguration.containsBean(CONTEXT_CREATOR_NAME) ? (OsgiApplicationContextCreator) extenderConfiguration
+ .getBean(CONTEXT_CREATOR_NAME, OsgiApplicationContextCreator.class)
+ : null;
+
+ contextEventListener =
+ extenderConfiguration.containsBean(CONTEXT_LISTENER_NAME) ? (OsgiBundleApplicationContextListener) extenderConfiguration
+ .getBean(CONTEXT_LISTENER_NAME, OsgiBundleApplicationContextListener.class)
+ : createDefaultApplicationContextListener();
+ }
+
+ // get post processors
+ postProcessors.addAll(extenderConfiguration.getBeansOfType(OsgiBeanFactoryPostProcessor.class).values());
+
+ // get dependency factories
+ dependencyFactories.addAll(extenderConfiguration.getBeansOfType(OsgiServiceDependencyFactory.class)
+ .values());
+
+ classLoader = extenderConfiguration.getClassLoader();
+ // extender properties using the defaults as backup
+ if (extenderConfiguration.containsBean(PROPERTIES_NAME)) {
+ Properties customProperties =
+ (Properties) extenderConfiguration.getBean(PROPERTIES_NAME, Properties.class);
+ Enumeration<?> propertyKey = customProperties.propertyNames();
+ while (propertyKey.hasMoreElements()) {
+ String property = (String) propertyKey.nextElement();
+ properties.setProperty(property, customProperties.getProperty(property));
+ }
+ }
+ }
+
+ synchronized (lock) {
+ shutdownWaitTime = getShutdownWaitTime(properties);
+ dependencyWaitTime = getDependencyWaitTime(properties);
+ processAnnotation = getProcessAnnotations(properties);
+ }
+
+ // load default dependency factories
+ addDefaultDependencyFactories();
+
+ // allow post processing
+ contextCreator = postProcess(contextCreator);
+ }
+
+ /**
+ * Allows post processing of the context creator.
+ *
+ * @param contextCreator
+ * @return
+ */
+ protected OsgiApplicationContextCreator postProcess(OsgiApplicationContextCreator contextCreator) {
+ return contextCreator;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Cleanup the configuration items.
+ */
+ public void stop(BundleContext extenderBundleContext) {
+
+ synchronized (lock) {
+ if (isMulticasterManagedInternally) {
+ eventMulticaster.removeAllListeners();
+ eventMulticaster = null;
+ }
+
+ if (extenderConfiguration != null) {
+ extenderConfiguration.close();
+ extenderConfiguration = null;
+ }
+
+ // postpone the task executor shutdown
+ if (forceThreadShutdown) {
+
+ if (isTaskExecutorManagedInternally) {
+ log.warn("Forcing the (internally created) taskExecutor to stop...");
+ ThreadGroup th = ((SimpleAsyncTaskExecutor) taskExecutor).getThreadGroup();
+ if (!th.isDestroyed()) {
+ // ask the threads nicely to stop
+ th.interrupt();
+ }
+ }
+ taskExecutor = null;
+ }
+
+ if (isShutdownTaskExecutorManagedInternally) {
+ try {
+ ((DisposableBean) shutdownTaskExecutor).destroy();
+ } catch (Exception ex) {
+ log.debug("Received exception while shutting down shutdown task executor", ex);
+ }
+ shutdownTaskExecutor = null;
+ }
+ }
+ }
+
+ /**
+ * Copies the URLs returned by the given enumeration and returns them as an array of Strings for consumption by the
+ * application context.
+ *
+ * @param enm
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ private String[] copyEnumerationToList(Enumeration<?> enm) {
+ List<String> urls = new ArrayList<String>(4);
+ while (enm != null && enm.hasMoreElements()) {
+ URL configURL = (URL) enm.nextElement();
+ if (configURL != null) {
+ String configURLAsString = configURL.toExternalForm();
+ try {
+ urls.add(URLDecoder.decode(configURLAsString, "UTF8"));
+ } catch (UnsupportedEncodingException uee) {
+ log.warn("UTF8 encoding not supported, using the platform default");
+ urls.add(URLDecoder.decode(configURLAsString));
+ }
+ }
+ }
+
+ return (String[]) urls.toArray(new String[urls.size()]);
+ }
+
+ private Properties createDefaultProperties() {
+ Properties properties = new Properties();
+ properties.setProperty(SHUTDOWN_WAIT_KEY, "" + DEFAULT_SHUTDOWN_WAIT);
+ properties.setProperty(PROCESS_ANNOTATIONS_KEY, "" + DEFAULT_PROCESS_ANNOTATION);
+ properties.setProperty(WAIT_FOR_DEPS_TIMEOUT_KEY, "" + DEFAULT_DEP_WAIT);
+
+ return properties;
+ }
+
+ protected void addDefaultDependencyFactories() {
+ boolean debug = log.isDebugEnabled();
+
+ // default JDK 1.4 processor
+ dependencyFactories.add(0, new MandatoryImporterDependencyFactory());
+
+ // load through reflection the dependency and injection processors if running on JDK 1.5 and annotation
+ // processing is enabled
+ if (processAnnotation) {
+ // dependency processor
+ Class<?> annotationProcessor = null;
+ try {
+ annotationProcessor =
+ Class.forName(ANNOTATION_DEPENDENCY_FACTORY, false, ExtenderConfiguration.class
+ .getClassLoader());
+ } catch (ClassNotFoundException cnfe) {
+ log.warn("Spring DM annotation package not found, annotation processing disabled.");
+ log.debug("Spring DM annotation package not found, annotation processing disabled.", cnfe);
+ return;
+ }
+ Object processor = BeanUtils.instantiateClass(annotationProcessor);
+ Assert.isInstanceOf(OsgiServiceDependencyFactory.class, processor);
+ dependencyFactories.add(1, (OsgiServiceDependencyFactory) processor);
+
+ if (debug)
+ log.debug("Succesfully loaded annotation dependency processor [" + ANNOTATION_DEPENDENCY_FACTORY + "]");
+
+ // add injection processor (first in line)
+ postProcessors.add(0, new OsgiAnnotationPostProcessor());
+ log.info("Spring-DM annotation processing enabled");
+ } else {
+ if (debug) {
+ log.debug("Spring-DM annotation processing disabled; [" + ANNOTATION_DEPENDENCY_FACTORY
+ + "] not loaded");
+ }
+ }
+
+ }
+
+ private TaskExecutor createDefaultTaskExecutor() {
+ // create thread-pool for starting contexts
+ ThreadGroup threadGroup =
+ new ThreadGroup("eclipse-gemini-blueprint-extender[" + ObjectUtils.getIdentityHexString(this) + "]-threads");
+ threadGroup.setDaemon(false);
+
+ SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
+ taskExecutor.setThreadGroup(threadGroup);
+ taskExecutor.setThreadNamePrefix("EclipseGeminiBlueprintExtenderThread-");
+
+ isTaskExecutorManagedInternally = true;
+
+ return taskExecutor;
+ }
+
+ private TaskExecutor createDefaultShutdownTaskExecutor() {
+ TimerTaskExecutor taskExecutor = new TimerTaskExecutor() {
+ @Override
+ protected Timer createTimer() {
+ return new Timer("Gemini Blueprint context shutdown thread", true);
+ }
+ };
+
+ taskExecutor.afterPropertiesSet();
+ isShutdownTaskExecutorManagedInternally = true;
+ return taskExecutor;
+ }
+
+ private OsgiBundleApplicationContextEventMulticaster createDefaultEventMulticaster() {
+ isMulticasterManagedInternally = true;
+ return new OsgiBundleApplicationContextEventMulticasterAdapter(new SimpleApplicationEventMulticaster());
+ }
+
+ private OsgiBundleApplicationContextListener createDefaultApplicationContextListener() {
+ return new DefaultOsgiBundleApplicationContextListener(log);
+ }
+
+ private long getShutdownWaitTime(Properties properties) {
+ return Long.parseLong(properties.getProperty(SHUTDOWN_WAIT_KEY));
+ }
+
+ private long getDependencyWaitTime(Properties properties) {
+ return Long.parseLong(properties.getProperty(WAIT_FOR_DEPS_TIMEOUT_KEY));
+ }
+
+ private boolean getProcessAnnotations(Properties properties) {
+ return Boolean.valueOf(properties.getProperty(PROCESS_ANNOTATIONS_KEY)).booleanValue()
+ || Boolean.getBoolean(AUTO_ANNOTATION_PROCESSING);
+ }
+
+ /**
+ * Returns the taskExecutor.
+ *
+ * @return Returns the taskExecutor
+ */
+ public TaskExecutor getTaskExecutor() {
+ synchronized (lock) {
+ return taskExecutor;
+ }
+ }
+
+ /**
+ * Returns the shutdown task executor.
+ *
+ * @return Returns the shutdown task executor
+ */
+ public TaskExecutor getShutdownTaskExecutor() {
+ synchronized (lock) {
+ return shutdownTaskExecutor;
+ }
+ }
+
+ /**
+ * Returns the contextEventListener.
+ *
+ * @return Returns the contextEventListener
+ */
+ public OsgiBundleApplicationContextListener getContextEventListener() {
+ synchronized (lock) {
+ return contextEventListener;
+ }
+ }
+
+ /**
+ * Returns the shutdownWaitTime.
+ *
+ * @return Returns the shutdownWaitTime
+ */
+ public long getShutdownWaitTime() {
+ synchronized (lock) {
+ return shutdownWaitTime;
+ }
+ }
+
+ /**
+ * Indicates if the process annotation is enabled or not.
+ *
+ * @return Returns true if the annotation should be processed or not otherwise.
+ */
+ public boolean shouldProcessAnnotation() {
+ synchronized (lock) {
+ return processAnnotation;
+ }
+ }
+
+ /**
+ * Returns the dependencyWaitTime.
+ *
+ * @return Returns the dependencyWaitTime
+ */
+ public long getDependencyWaitTime() {
+ synchronized (lock) {
+ return dependencyWaitTime;
+ }
+ }
+
+ /**
+ * Returns the eventMulticaster.
+ *
+ * @return Returns the eventMulticaster
+ */
+ public OsgiBundleApplicationContextEventMulticaster getEventMulticaster() {
+ synchronized (lock) {
+ return eventMulticaster;
+ }
+ }
+
+ /**
+ * Sets the flag to force the taskExtender to close up in case of runaway threads - this applies *only* if the
+ * taskExecutor has been created internally.
+ *
+ * <p/> The flag will cause a best attempt to shutdown the threads.
+ *
+ * @param forceThreadShutdown The forceThreadShutdown to set.
+ */
+ public void setForceThreadShutdown(boolean forceThreadShutdown) {
+ synchronized (lock) {
+ this.forceThreadShutdown = forceThreadShutdown;
+ }
+ }
+
+ /**
+ * Returns the contextCreator.
+ *
+ * @return Returns the contextCreator
+ */
+ public OsgiApplicationContextCreator getContextCreator() {
+ synchronized (lock) {
+ return contextCreator;
+ }
+ }
+
+ /**
+ * Returns the postProcessors.
+ *
+ * @return Returns the postProcessors
+ */
+ public List<OsgiBeanFactoryPostProcessor> getPostProcessors() {
+ return postProcessors;
+ }
+
+ /**
+ * Returns the class loader wrapped around the extender bundle.
+ *
+ * @return extender bundle class loader
+ */
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ /**
+ * Returns the dependencies factories declared by the extender configuration. The list automatically contains the
+ * default listeners (such as the annotation one).
+ *
+ * @return list of dependency factories
+ */
+ public List<OsgiServiceDependencyFactory> getDependencyFactories() {
+ return dependencyFactories;
+ }
} \ No newline at end of file
diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/ContextLoaderListenerTest.java b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/ContextLoaderListenerTest.java
index 6c496ac..cc3acbf 100644
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/ContextLoaderListenerTest.java
+++ b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/ContextLoaderListenerTest.java
@@ -1,17 +1,17 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
package org.eclipse.gemini.blueprint.extender.internal;
import java.util.Dictionary;
@@ -21,13 +21,14 @@ import java.util.Properties;
import junit.framework.TestCase;
import org.easymock.MockControl;
-import org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener;
-import org.eclipse.gemini.blueprint.extender.internal.support.TestTaskExecutor;
-import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
-import org.eclipse.gemini.blueprint.mock.EntryLookupControllingMockBundle;
-import org.eclipse.gemini.blueprint.mock.MockBundle;
-import org.eclipse.gemini.blueprint.mock.MockBundleContext;
-import org.eclipse.gemini.blueprint.mock.MockServiceRegistration;
+import org.eclipse.gemini.blueprint.extender.internal.activator.ContextLoaderListener;
+import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
+import org.eclipse.gemini.blueprint.extender.internal.support.TestTaskExecutor;
+import org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils;
+import org.eclipse.gemini.blueprint.mock.EntryLookupControllingMockBundle;
+import org.eclipse.gemini.blueprint.mock.MockBundle;
+import org.eclipse.gemini.blueprint.mock.MockBundleContext;
+import org.eclipse.gemini.blueprint.mock.MockServiceRegistration;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
@@ -40,13 +41,13 @@ import org.springframework.core.io.ClassPathResource;
*
*/
public abstract class ContextLoaderListenerTest extends TestCase {
-
private ContextLoaderListener listener;
+ // TODO: mock & train once there are any applications of this base class.
+ private ExtenderConfiguration configuration;
-
- protected void setUp() throws Exception {
+ protected void setUp() throws Exception {
super.setUp();
- this.listener = new ContextLoaderListener();
+ this.listener = new ContextLoaderListener(this.configuration);
}
public void testStart() throws Exception {
diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationCustomSettingsTest.java b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationCustomSettingsTest.java
index 66a0ae2..8a58d2a 100644
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationCustomSettingsTest.java
+++ b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationCustomSettingsTest.java
@@ -1,105 +1,103 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.support;
-
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.springframework.core.task.SimpleAsyncTaskExecutor;
-import org.springframework.core.task.TaskExecutor;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory;
-import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
-import org.eclipse.gemini.blueprint.mock.ArrayEnumerator;
-import org.eclipse.gemini.blueprint.mock.MockBundle;
-import org.eclipse.gemini.blueprint.mock.MockBundleContext;
-
-/**
- * @author Costin Leau
- */
-public class ExtenderConfigurationCustomSettingsTest extends TestCase {
-
- private ExtenderConfiguration config;
- private BundleContext bundleContext;
- private Bundle bundle;
-
- protected void setUp() throws Exception {
- bundle = new MockBundle() {
-
- public Enumeration findEntries(String path, String filePattern, boolean recurse) {
- return new ArrayEnumerator(new URL[] { getClass().getResource(
- "/org/eclipse/gemini/blueprint/extender/internal/support/extender-custom-config.xml") });
- }
- };
-
- bundleContext = new MockBundleContext(bundle);
- config = new ExtenderConfiguration(bundleContext, LogFactory.getLog(ExtenderConfiguration.class));
- }
-
- protected void tearDown() throws Exception {
- config.destroy();
- config = null;
- }
-
- public void testTaskExecutor() throws Exception {
- assertTrue(config.getTaskExecutor() instanceof SimpleAsyncTaskExecutor);
- assertEquals("conf-extender-thread", ((SimpleAsyncTaskExecutor) config.getTaskExecutor()).getThreadNamePrefix());
- }
-
- public void testShutdownTaskExecutor() throws Exception {
- TaskExecutor executor = config.getShutdownTaskExecutor();
- assertTrue(executor instanceof SimpleAsyncTaskExecutor);
- }
-
- public void testEventMulticaster() throws Exception {
- assertTrue(config.getEventMulticaster() instanceof OsgiBundleApplicationContextEventMulticasterAdapter);
- }
-
- public void testApplicationContextCreator() throws Exception {
- assertTrue(config.getContextCreator() instanceof DummyContextCreator);
- }
-
- public void testShutdownWaitTime() throws Exception {
- // 300 ms
- assertEquals(300, config.getShutdownWaitTime());
- }
-
- public void testShouldProcessAnnotation() throws Exception {
- assertTrue(config.shouldProcessAnnotation());
- }
-
- public void testDependencyWaitTime() throws Exception {
- // 200 ms
- assertEquals(200, config.getDependencyWaitTime());
- }
-
- public void testPostProcessors() throws Exception {
- List postProcessors = config.getPostProcessors();
- assertEquals(1, postProcessors.size());
- assertTrue(postProcessors.get(0) instanceof DummyProcessor);
- }
-
- public void testDependencyFactories() throws Exception {
- List factories = config.getDependencyFactories();
- assertEquals("wrong number of dependencies factories registered by default", 1, factories.size());
- assertTrue(factories.get(0) instanceof MandatoryImporterDependencyFactory);
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.support;
+
+import junit.framework.TestCase;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
+import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory;
+import org.eclipse.gemini.blueprint.mock.ArrayEnumerator;
+import org.eclipse.gemini.blueprint.mock.MockBundle;
+import org.eclipse.gemini.blueprint.mock.MockBundleContext;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * @author Costin Leau
+ */
+public class ExtenderConfigurationCustomSettingsTest extends TestCase {
+
+ private ExtenderConfiguration config;
+ private BundleContext bundleContext;
+ private Bundle bundle;
+
+ protected void setUp() throws Exception {
+ bundle = new MockBundle() {
+
+ public Enumeration findEntries(String path, String filePattern, boolean recurse) {
+ return new ArrayEnumerator(new URL[] { getClass().getResource(
+ "/org/eclipse/gemini/blueprint/extender/internal/support/extender-custom-config.xml") });
+ }
+ };
+
+ bundleContext = new MockBundleContext(bundle);
+ config = new ExtenderConfiguration();
+ config.start(this.bundleContext);
+ }
+
+ protected void tearDown() throws Exception {
+ config.stop(this.bundleContext);
+ config = null;
+ }
+
+ public void testTaskExecutor() throws Exception {
+ assertTrue(config.getTaskExecutor() instanceof SimpleAsyncTaskExecutor);
+ assertEquals("conf-extender-thread", ((SimpleAsyncTaskExecutor) config.getTaskExecutor()).getThreadNamePrefix());
+ }
+
+ public void testShutdownTaskExecutor() throws Exception {
+ TaskExecutor executor = config.getShutdownTaskExecutor();
+ assertTrue(executor instanceof SimpleAsyncTaskExecutor);
+ }
+
+ public void testEventMulticaster() throws Exception {
+ assertTrue(config.getEventMulticaster() instanceof OsgiBundleApplicationContextEventMulticasterAdapter);
+ }
+
+ public void testApplicationContextCreator() throws Exception {
+ assertTrue(config.getContextCreator() instanceof DummyContextCreator);
+ }
+
+ public void testShutdownWaitTime() throws Exception {
+ // 300 ms
+ assertEquals(300, config.getShutdownWaitTime());
+ }
+
+ public void testShouldProcessAnnotation() throws Exception {
+ assertTrue(config.shouldProcessAnnotation());
+ }
+
+ public void testDependencyWaitTime() throws Exception {
+ // 200 ms
+ assertEquals(200, config.getDependencyWaitTime());
+ }
+
+ public void testPostProcessors() throws Exception {
+ List postProcessors = config.getPostProcessors();
+ assertEquals(1, postProcessors.size());
+ assertTrue(postProcessors.get(0) instanceof DummyProcessor);
+ }
+
+ public void testDependencyFactories() throws Exception {
+ List factories = config.getDependencyFactories();
+ assertEquals("wrong number of dependencies factories registered by default", 1, factories.size());
+ assertTrue(factories.get(0) instanceof MandatoryImporterDependencyFactory);
+ }
} \ No newline at end of file
diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationDefaultSettingsTest.java b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationDefaultSettingsTest.java
index 421a413..7f02cb5 100644
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationDefaultSettingsTest.java
+++ b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/support/ExtenderConfigurationDefaultSettingsTest.java
@@ -1,91 +1,88 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.support;
-
-import java.util.List;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.BundleContext;
-import org.springframework.core.task.SimpleAsyncTaskExecutor;
-import org.springframework.core.task.TaskExecutor;
-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory;
-import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
-import org.eclipse.gemini.blueprint.extender.support.DefaultOsgiApplicationContextCreator;
-import org.eclipse.gemini.blueprint.mock.MockBundleContext;
-import org.springframework.scheduling.timer.TimerTaskExecutor;
-
-/**
- * @author Costin Leau
- */
-public class ExtenderConfigurationDefaultSettingsTest extends TestCase {
-
- private ExtenderConfiguration config;
- private BundleContext bundleContext;
-
- protected void setUp() throws Exception {
- bundleContext = new MockBundleContext();
- config = new ExtenderConfiguration(bundleContext, LogFactory.getLog(ExtenderConfiguration.class));
- }
-
- protected void tearDown() throws Exception {
- config.destroy();
- config = null;
- }
-
- public void testTaskExecutor() throws Exception {
- assertTrue(config.getTaskExecutor() instanceof SimpleAsyncTaskExecutor);
- }
-
- public void testShutdownTaskExecutor() throws Exception {
- TaskExecutor executor = config.getShutdownTaskExecutor();
- assertTrue(executor instanceof TimerTaskExecutor);
- }
-
- public void testEventMulticaster() throws Exception {
- assertTrue(config.getEventMulticaster() instanceof OsgiBundleApplicationContextEventMulticasterAdapter);
- }
-
- public void testApplicationContextCreator() throws Exception {
- assertTrue(config.getContextCreator() instanceof DefaultOsgiApplicationContextCreator);
- }
-
- public void testShutdownWaitTime() throws Exception {
- // 10 seconds in ms
- assertEquals(10 * 1000, config.getShutdownWaitTime());
- }
-
- public void testShouldProcessAnnotation() throws Exception {
- assertFalse(config.shouldProcessAnnotation());
- }
-
- public void testDependencyWaitTime() throws Exception {
- // 5 minutes in ms
- assertEquals(5 * 60 * 1000, config.getDependencyWaitTime());
- }
-
- public void testPostProcessors() throws Exception {
- List postProcessors = config.getPostProcessors();
- assertTrue(postProcessors.isEmpty());
- }
-
- public void testDependencyFactories() throws Exception {
- List factories = config.getDependencyFactories();
- assertEquals("wrong number of dependencies factories registered by default", 1, factories.size());
- assertTrue(factories.get(0) instanceof MandatoryImporterDependencyFactory);
- }
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.extender.internal.support;
+
+import junit.framework.TestCase;
+import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
+import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory;
+import org.eclipse.gemini.blueprint.mock.MockBundleContext;
+import org.osgi.framework.BundleContext;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.timer.TimerTaskExecutor;
+
+import java.util.List;
+
+/**
+ * @author Costin Leau
+ */
+public class ExtenderConfigurationDefaultSettingsTest extends TestCase {
+
+ private ExtenderConfiguration config;
+ private BundleContext bundleContext;
+
+ protected void setUp() throws Exception {
+ bundleContext = new MockBundleContext();
+ config = new ExtenderConfiguration();
+ this.config.start(this.bundleContext);
+ }
+
+ protected void tearDown() throws Exception {
+ config.start(this.bundleContext);
+ config = null;
+ }
+
+ public void testTaskExecutor() throws Exception {
+ assertTrue(config.getTaskExecutor() instanceof SimpleAsyncTaskExecutor);
+ }
+
+ public void testShutdownTaskExecutor() throws Exception {
+ TaskExecutor executor = config.getShutdownTaskExecutor();
+ assertTrue(executor instanceof TimerTaskExecutor);
+ }
+
+ public void testEventMulticaster() throws Exception {
+ assertTrue(config.getEventMulticaster() instanceof OsgiBundleApplicationContextEventMulticasterAdapter);
+ }
+
+ public void testApplicationContextCreator() throws Exception {
+ assertNull(config.getContextCreator());
+ }
+
+ public void testShutdownWaitTime() throws Exception {
+ // 10 seconds in ms
+ assertEquals(10 * 1000, config.getShutdownWaitTime());
+ }
+
+ public void testShouldProcessAnnotation() throws Exception {
+ assertFalse(config.shouldProcessAnnotation());
+ }
+
+ public void testDependencyWaitTime() throws Exception {
+ // 5 minutes in ms
+ assertEquals(5 * 60 * 1000, config.getDependencyWaitTime());
+ }
+
+ public void testPostProcessors() throws Exception {
+ List postProcessors = config.getPostProcessors();
+ assertTrue(postProcessors.isEmpty());
+ }
+
+ public void testDependencyFactories() throws Exception {
+ List factories = config.getDependencyFactories();
+ assertEquals("wrong number of dependencies factories registered by default", 1, factories.size());
+ assertTrue(factories.get(0) instanceof MandatoryImporterDependencyFactory);
+ }
} \ No newline at end of file