Fixed FELIX-2932
The ipojo.processing.synchronous=true system property disables the thread used by iPOJO to process bundles.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1096436 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/Extender.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/Extender.java
index e0d56fc..1b1bcf2 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/Extender.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/Extender.java
@@ -1,4 +1,4 @@
-/*
+/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -57,20 +57,35 @@
* scale applications. The internal dispatcher is disabled by default.
*/
static boolean DISPATCHER_ENABLED = true;
-
+
+ /**
+ * Disables the iPOJO asynchronous processing.
+ * When set to false, the bundles are processed in the listener thread
+ * making iPOJO usable on Google App Engine. By default, the processing
+ * is asynchronous.
+ */
+ static boolean SYNCHRONOUS_PROCESSING_ENABLED = false;
+
/**
* Property allowing to set if the internal dispatcher is enabled or disabled.
* Possible value are either <code>true</code> or <code>false</code>.
*/
private static final String ENABLING_DISPATCHER = "ipojo.internal.dispatcher";
-
+
+ /**
+ * Property allowing to disable the asynchronous process (and so enables the
+ * synchronous processing).
+ * Possible value are either <code>true</code> or <code>false</code>.
+ */
+ private static final String SYNCHRONOUS_PROCESSING = "ipojo.processing.synchronous";
+
/**
* iPOJO Component Type and Instance declaration header.
*/
private static final String IPOJO_HEADER = "iPOJO-Components";
/**
- * iPOJO Extension declaration header.
+ * iPOJO Extension declaration header.
*/
private static final String IPOJO_EXTENSION = "IPOJO-Extension";
@@ -78,7 +93,7 @@
* The Bundle Context of the iPOJO Core bundle.
*/
private static BundleContext m_context;
-
+
/**
* The iPOJO Extender logger.
*/
@@ -105,11 +120,11 @@
* A type is unbound if the matching extension is not deployed.
*/
private final List m_unboundTypes = new ArrayList();
-
+
/**
- * The thread analyzing arriving bundles and creating iPOJO contributions.
+ * The processor analyzing arriving bundles and creating iPOJO contributions.
*/
- private final CreatorThread m_thread = new CreatorThread();
+ private final CreatorThread m_processor = new CreatorThread();
/**
* Bundle Listener Notification.
@@ -122,11 +137,12 @@
switch (event.getType()) {
case BundleEvent.STARTED:
// Put the bundle in the queue
- m_thread.addBundle(event.getBundle());
+ m_processor.addBundle(event.getBundle());
break;
case BundleEvent.STOPPING:
- m_thread.removeBundle(event.getBundle());
- closeManagementFor(event.getBundle()); //TODO Should be done in another thread
+ m_processor.removeBundle(event.getBundle());
+ //TODO Should be done in another thread in the asynchronous case.
+ closeManagementFor(event.getBundle());
break;
default:
break;
@@ -135,9 +151,9 @@
}
/**
- * Ends the iPOJO Management for the given bundle.
+ * Ends the iPOJO Management for the given bundle.
* Generally the bundle is leaving. This method
- * stops every factories declared is the bundle and
+ * stops every factories declared is the bundle and
* disposed every declared instances.
* @param bundle the bundle.
*/
@@ -189,7 +205,7 @@
}
/**
- * Checks if the given bundle is an iPOJO bundle, and begin
+ * Checks if the given bundle is an iPOJO bundle, and begin
* the iPOJO management is true.
* @param bundle the bundle to check.
*/
@@ -247,7 +263,7 @@
}
/**
- * Parses the internal metadata (from the manifest
+ * Parses the internal metadata (from the manifest
* (in the iPOJO-Components property)). This methods
* creates factories and add instances to the instance creator.
* @param bundle the owner bundle.
@@ -281,18 +297,21 @@
m_creator = new InstanceCreator(context);
m_logger = new Logger(m_context, "IPOJO-Extender");
-
+
enablingDispatcher(context, m_logger);
-
+ enablingSynchronousProcessing(context, m_logger);
+
// Create the dispatcher only if required.
if (DISPATCHER_ENABLED) {
EventDispatcher.create(context);
}
-
+
// Begin by initializing core handlers
startManagementFor(m_bundle);
-
- new Thread(m_thread).start();
+
+ if (! SYNCHRONOUS_PROCESSING_ENABLED) {
+ new Thread(m_processor).start();
+ }
synchronized (this) {
// listen to any changes in bundles.
@@ -300,11 +319,11 @@
// compute already started bundles.
for (int i = 0; i < context.getBundles().length; i++) {
if (context.getBundles()[i].getState() == Bundle.ACTIVE) {
- m_thread.addBundle(context.getBundles()[i]); // Bundles are processed in another thread.
+ m_processor.addBundle(context.getBundles()[i]); // Bundles are processed in another thread.
}
}
}
-
+
m_logger.log(Logger.INFO, "iPOJO Runtime started");
}
@@ -314,9 +333,9 @@
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) {
- m_thread.stop(); // Stop the thread processing bundles.
+ m_processor.stop(); // Stop the thread processing bundles.
m_context.removeBundleListener(this);
-
+
if (DISPATCHER_ENABLED) {
EventDispatcher.dispose();
}
@@ -340,11 +359,11 @@
m_factoryTypes = null;
m_creator = null;
-
+
m_logger.log(Logger.INFO, "iPOJO Runtime stopped");
m_context = null;
}
-
+
/**
* Gets iPOJO bundle context.
* @return the iPOJO Bundle Context
@@ -352,7 +371,7 @@
public static BundleContext getIPOJOBundleContext() {
return m_context;
}
-
+
/**
* Enables or disables the internal dispatcher, so sets the
* {@link Extender#DISPATCHER_ENABLED} flag.
@@ -367,13 +386,13 @@
private static void enablingDispatcher(BundleContext context, Logger logger) {
// First check in the framework and in the system properties
String flag = context.getProperty(ENABLING_DISPATCHER);
-
+
// If null, look in bundle manifest
if (flag == null) {
String key = ENABLING_DISPATCHER.replace('.', '-');
flag = (String) context.getBundle().getHeaders().get(key);
}
-
+
if (flag != null) {
if (flag.equalsIgnoreCase("true")) {
Extender.DISPATCHER_ENABLED = true;
@@ -381,11 +400,48 @@
return;
}
}
-
+
// Either l is null, or the specified value was false
Extender.DISPATCHER_ENABLED = false;
logger.log(Logger.INFO, "iPOJO Internal Event Dispatcher disables");
-
+
+ }
+
+ /**
+ * Enables or disables the asynchronous processing, so sets the
+ * {@link Extender#SYNCHRONOUS_PROCESSING_ENABLED} flag.
+ * Disabling asynchronous processing avoids iPOJO to create a new
+ * thread to process bundles. So, iPOJO can be used on the
+ * Google App Engine.
+ * This method checks if the {@link Extender#SYNCHRONOUS_PROCESSING}
+ * property is set to <code>true</code>. Otherwise, asynchronous processing
+ * is used (default). The property can be set as a system
+ * property (<code>ipojo.processing.synchronous</code>) or inside the
+ * iPOJO bundle manifest.
+ * @param context the bundle context.
+ * @param logger the logger to indicates if the internal dispatcher is set.
+ */
+ private static void enablingSynchronousProcessing(BundleContext context, Logger logger) {
+ String flag = context.getProperty(SYNCHRONOUS_PROCESSING);
+
+ // If null, look in bundle manifest
+ if (flag == null) {
+ String key = SYNCHRONOUS_PROCESSING.replace('.', '-');
+ flag = (String) context.getBundle().getHeaders().get(key);
+ }
+
+ if (flag != null) {
+ if (flag.equalsIgnoreCase("true")) {
+ Extender.SYNCHRONOUS_PROCESSING_ENABLED = true;
+ logger.log(Logger.INFO, "iPOJO Asynchronous processing disabled");
+ return;
+ }
+ }
+
+ // Either l is null, or the specified value was false
+ Extender.SYNCHRONOUS_PROCESSING_ENABLED = false;
+ logger.log(Logger.INFO, "iPOJO synchrnous processing disables");
+
}
/**
@@ -411,7 +467,7 @@
return;
}
- // Once found, we invoke the AbstractFactory constructor to create the component factory.
+ // Once found, we invoke the AbstractFactory constructor to create the component factory.
Class clazz = factoryType.m_clazz;
try {
// Look for the constructor, and invoke it.
@@ -475,7 +531,7 @@
Bundle m_bundle;
/**
- * The factories created by this extension.
+ * The factories created by this extension.
*/
private Map m_created;
@@ -555,7 +611,7 @@
}
if (meth != null) {
- if (! meth.isAccessible()) {
+ if (! meth.isAccessible()) {
// If not accessible, try to set the accessibility.
meth.setAccessible(true);
}
@@ -573,7 +629,7 @@
}
}
- // Else : Field inspection (KF and Prosyst)
+ // Else : Field inspection (KF and Prosyst)
Field[] fields = bundle.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (BundleContext.class.isAssignableFrom(fields[i].getType())) {
@@ -594,7 +650,7 @@
m_logger.log(Logger.ERROR, "Cannot find the BundleContext for " + bundle.getSymbolicName(), null);
return null;
}
-
+
/**
* The creator thread analyzes arriving bundles to create iPOJO contribution.
@@ -605,23 +661,29 @@
* Is the creator thread started?
*/
private boolean m_started = true;
-
+
/**
* The list of bundle that are going to be analyzed.
*/
private List m_bundles = new ArrayList();
-
+
/**
* A bundle is arriving.
* This method is synchronized to avoid concurrent modification of the waiting list.
* @param bundle the new bundle
*/
public synchronized void addBundle(Bundle bundle) {
- m_bundles.add(bundle);
- notifyAll(); // Notify the thread to force the process.
- m_logger.log(Logger.DEBUG, "Creator thread is going to analyze the bundle " + bundle.getBundleId() + " List : " + m_bundles);
+ if (SYNCHRONOUS_PROCESSING_ENABLED) {
+ m_logger.log(Logger.DEBUG, "Analyzing " + bundle.getBundleId());
+ startManagementFor(bundle);
+ } else {
+ // Asynchronous case, we add the bundle to the queue
+ m_bundles.add(bundle);
+ notifyAll(); // Notify the thread to force the process.
+ m_logger.log(Logger.DEBUG, "Creator thread is going to analyze the bundle " + bundle.getBundleId() + " List : " + m_bundles);
+ }
}
-
+
/**
* A bundle is leaving.
* If the bundle was not already processed, the bundle is remove from the waiting list.
@@ -631,7 +693,7 @@
public synchronized void removeBundle(Bundle bundle) {
m_bundles.remove(bundle);
}
-
+
/**
* Stops the creator thread.
*/
@@ -644,7 +706,7 @@
/**
* Creator thread's run method.
* While the list is not empty, the thread launches the bundle analyzing on the next bundle.
- * When the list is empty, the thread sleeps until the arrival of a new bundle
+ * When the list is empty, the thread sleeps until the arrival of a new bundle
* or until iPOJO stops.
* @see java.lang.Runnable#run()
*/