/* * 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 * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.ipojo.extender.internal; import java.util.concurrent.ThreadFactory; import org.apache.felix.ipojo.ConfigurationTracker; import org.apache.felix.ipojo.EventDispatcher; import org.apache.felix.ipojo.extender.internal.declaration.service.DeclarationServiceFactory; import org.apache.felix.ipojo.extender.internal.linker.DeclarationLinker; import org.apache.felix.ipojo.extender.internal.processor.*; import org.apache.felix.ipojo.extender.internal.queue.ExecutorQueueService; import org.apache.felix.ipojo.extender.internal.queue.GroupThreadFactory; import org.apache.felix.ipojo.extender.internal.queue.NamingThreadFactory; import org.apache.felix.ipojo.extender.internal.queue.PrefixedThreadFactory; import org.apache.felix.ipojo.extender.internal.queue.SynchronousQueueService; import org.apache.felix.ipojo.extender.internal.queue.debug.ReplayQueueEventProxy; import org.apache.felix.ipojo.extender.internal.queue.pref.HeaderPreferenceSelection; import org.apache.felix.ipojo.extender.internal.queue.pref.Preference; import org.apache.felix.ipojo.extender.internal.queue.pref.PreferenceQueueService; import org.apache.felix.ipojo.extender.internal.queue.pref.enforce.EnforcedQueueService; import org.apache.felix.ipojo.extender.queue.debug.QueueEventProxy; import org.apache.felix.ipojo.util.Logger; import org.osgi.framework.*; import org.osgi.util.tracker.BundleTracker; import org.osgi.util.tracker.BundleTrackerCustomizer; /** * iPOJO main activator. */ public class Extender implements BundleActivator { public static final String BOOTSTRAP_QUEUE_DEBUG_PROPERTY = "org.apache.felix.ipojo.extender.BootstrapQueueDebug"; /** * Enables the iPOJO internal dispatcher. * This internal dispatcher helps the OSGi framework to support large * 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 {@literal true} or {@literal false}. */ 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 {@literal true} or {@literal false}. */ private static final String SYNCHRONOUS_PROCESSING = "ipojo.processing.synchronous"; /** * The Bundle Context of the iPOJO Core bundle. */ private static BundleContext m_context; /** * The iPOJO Extender logger. */ private Logger m_logger; /** * The iPOJO Bundle. */ private Bundle m_bundle; /** * The chained processor containing all the true bundle processor. */ private ChainedBundleProcessor m_processor; /** * Binds Instances to Factories to Extensions. */ private DeclarationLinker m_linker; private LifecycleQueueService m_queueService; /** * Track ACTIVE bundles. */ private BundleTracker m_tracker; /** * Service provided to build declarations through code. */ private DeclarationServiceFactory m_declarationService; /** * The iPOJO bundle is starting. * This method configures the iPOJO system (internal dispatcher and bundle processing). Then it initiates the * bundle processing. * <p/> * To optimize the processing, we process the iPOJO bundle first. * * @param context the iPOJO's bundle bundle context * @throws Exception something terrible happen during startup */ public void start(BundleContext context) throws Exception { m_context = context; m_bundle = context.getBundle(); m_logger = new Logger(m_context, "IPOJO-Main-Extender"); enablingDispatcher(context, m_logger); enablingSynchronousProcessing(context, m_logger); // Create the dispatcher only if required. if (DISPATCHER_ENABLED) { EventDispatcher.create(context); } // Initialize ConfigurationTracker ConfigurationTracker.initialize(); // Initialize the queue event proxy if wanted ReplayQueueEventProxy proxy = null; if (Boolean.getBoolean(BOOTSTRAP_QUEUE_DEBUG_PROPERTY)) { proxy = new ReplayQueueEventProxy(); context.registerService(QueueEventProxy.class, proxy, null); } BundleProcessor extensionBundleProcessor = new ExtensionBundleProcessor(m_logger); BundleProcessor componentsProcessor = new ComponentsBundleProcessor(m_logger); BundleProcessor configurationProcessor = new ConfigurationProcessor(m_logger); if (SYNCHRONOUS_PROCESSING_ENABLED) { m_queueService = new EnforcedQueueService( new HeaderPreferenceSelection(), new SynchronousQueueService(context), Preference.SYNC, m_logger); // If required, add the event proxy if (proxy != null) { m_queueService.addQueueListener(proxy); } } else { // Build a thread factory that will groups extender's thread together ThreadFactory threadFactory = new GroupThreadFactory(new ThreadGroup("iPOJO Extender")); threadFactory = new NamingThreadFactory(threadFactory); threadFactory = new PrefixedThreadFactory(threadFactory, "[iPOJO] "); // Create the queue services SynchronousQueueService sync = new SynchronousQueueService(context); ExecutorQueueService async = new ExecutorQueueService(context, Integer.getInteger(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY, 1), // default to 1 if no system property is set threadFactory); m_queueService = new PreferenceQueueService(new HeaderPreferenceSelection(), sync, async); extensionBundleProcessor = new QueuingActivationProcessor(extensionBundleProcessor, m_queueService); componentsProcessor = new QueuingActivationProcessor(componentsProcessor, m_queueService); configurationProcessor = new QueuingActivationProcessor(configurationProcessor, m_queueService); // If required, add the event proxy to both real services if (proxy != null) { sync.addQueueListener(proxy); async.addQueueListener(proxy); } } m_queueService.start(); // Start linking m_linker = new DeclarationLinker(context, m_queueService); m_linker.start(); m_processor = ChainedBundleProcessor.create(extensionBundleProcessor, componentsProcessor, configurationProcessor); m_processor.start(); // Begin by initializing core handlers m_processor.activate(m_bundle); m_tracker = new BundleTracker(context, Bundle.ACTIVE, new BundleTrackerCustomizer() { public Object addingBundle(final Bundle bundle, final BundleEvent event) { if (bundle.getBundleId() == m_bundle.getBundleId()) { // Not interested in our own bundle return null; } m_processor.activate(bundle); return bundle; } public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Object object) {} public void removedBundle(final Bundle bundle, final BundleEvent event, final Object object) { m_processor.deactivate(bundle); } }); m_tracker.open(); m_declarationService = new DeclarationServiceFactory(context); m_declarationService.start(); m_logger.log(Logger.INFO, "iPOJO Main Extender started"); } /** * The iPOJO bundle is stopping. * * @param context the bundle context * @throws Exception something terrible happen */ public void stop(BundleContext context) throws Exception { m_declarationService.stop(); m_tracker.close(); m_processor.deactivate(m_bundle); //Shutdown ConfigurationTracker ConfigurationTracker.shutdown(); m_processor.stop(); if (DISPATCHER_ENABLED) { EventDispatcher.dispose(); } m_linker.stop(); m_queueService.stop(); m_logger.log(Logger.INFO, "iPOJO Main Extender stopped"); m_context = null; } /** * Gets iPOJO bundle context. * * @return the iPOJO Bundle Context */ public static BundleContext getIPOJOBundleContext() { return m_context; } /** * Enables or disables the internal dispatcher, so sets the * {@link Extender#DISPATCHER_ENABLED} flag. * This method checks if the {@link Extender#ENABLING_DISPATCHER} * property is set to {@literal true}. Otherwise, the internal * dispatcher is disabled. The property can be set as a system * property ({@literal ipojo.internal.dispatcher}) or inside the * iPOJO bundle manifest ({@literal ipojo-internal-dispatcher}). * * @param context the bundle context. * @param logger the logger to indicates if the internal dispatcher is set. */ 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; logger.log(Logger.INFO, "iPOJO Internal Event Dispatcher enables"); 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 {@literal true}. Otherwise, asynchronous processing * is used (default). The property can be set as a system * property ({@literal ipojo.processing.synchronous}) 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 synchronous processing disabled"); } }