Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 223379 Details for
Bug 356683
Construct application contexts defined in extender fragments only once and share across extender instances
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
New patch version including license headers
356683-against-master.patch (text/plain), 189.89 KB, created by
Olaf Otto
on 2012-11-09 02:10:04 EST
(
hide
)
Description:
New patch version including license headers
Filename:
MIME Type:
Creator:
Olaf Otto
Created:
2012-11-09 02:10:04 EST
Size:
189.89 KB
patch
obsolete
>From 45f3d4c2120d44185be2eb38df03ed6b095930aa Mon Sep 17 00:00:00 2001 >From: Olaf Otto <olaf.otto@unic.com> >Date: Fri, 9 Nov 2012 08:05:19 +0100 >Subject: [PATCH] 356683 Separate staged configuration and listeners > (https://bugs.eclipse.org/bugs/show_bug.cgi?id=356683) > >--- > .../classloader/ChainedClassLoaderTest.java | 255 +++-- > .../context/support/ConfigLocationsTest.java | 119 ++- > .../BlueprintNamespaceHandlerActivator.java | 28 + > .../internal/activator/ContextLoaderListener.java | 744 +++++--------- > .../activator/JavaBeansCacheActivator.java | 74 ++ > .../internal/activator/LifecycleManager.java | 864 ++++++++-------- > .../internal/activator/ListListenerAdapter.java | 181 ++-- > .../activator/ListenerServiceActivator.java | 93 ++ > .../internal/activator/LoggingActivator.java | 41 + > .../activator/NamespaceHandlerActivator.java | 129 +++ > .../internal/activator/listeners/BaseListener.java | 99 ++ > .../activator/listeners/NamespaceBundleLister.java | 73 ++ > .../activator/BlueprintLoaderListener.java | 195 ++-- > .../support/BlueprintExtenderConfiguration.java | 44 - > .../extender/internal/boot/ChainActivator.java | 171 ++-- > ...efaultOsgiBundleApplicationContextListener.java | 131 ++- > .../internal/support/ExtenderConfiguration.java | 1068 ++++++++++---------- > .../internal/ContextLoaderListenerTest.java | 51 +- > .../ExtenderConfigurationCustomSettingsTest.java | 206 ++-- > .../ExtenderConfigurationDefaultSettingsTest.java | 177 ++-- > 20 files changed, 2498 insertions(+), 2245 deletions(-) > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/BlueprintNamespaceHandlerActivator.java > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/JavaBeansCacheActivator.java > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/ListenerServiceActivator.java > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LoggingActivator.java > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/NamespaceHandlerActivator.java > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/BaseListener.java > create mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/listeners/NamespaceBundleLister.java > delete mode 100644 extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/blueprint/activator/support/BlueprintExtenderConfiguration.java > >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 >-- >1.7.10.4 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
glyn.normington
:
iplog+
Actions:
View
|
Diff
Attachments on
bug 356683
:
202722
|
202769
|
223184
|
223222
|
223234
| 223379