diff options
author | Olaf Otto | 2012-11-09 12:30:04 +0000 |
---|---|---|
committer | Glyn Normington | 2012-11-09 12:31:25 +0000 |
commit | 6976b50e76a17aaf800a60f836c6b7af46fbf483 (patch) | |
tree | 860ce05408b77a9148e309f6f10ddd673c80fc36 | |
parent | 3a61ce14025be80696667d653627f788059f52da (diff) | |
download | org.eclipse.gemini.blueprint-6976b50e76a17aaf800a60f836c6b7af46fbf483.tar.gz org.eclipse.gemini.blueprint-6976b50e76a17aaf800a60f836c6b7af46fbf483.tar.xz org.eclipse.gemini.blueprint-6976b50e76a17aaf800a60f836c6b7af46fbf483.zip |
356683: construct extender configuration once and share it
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 |