/****************************************************************************** * 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.test.platform; import java.io.File; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.felix.framework.Felix; import org.apache.felix.framework.util.StringMap; import org.apache.felix.main.AutoProcessor; import org.apache.felix.main.Main; import org.eclipse.gemini.blueprint.test.internal.util.IOUtils; import org.osgi.framework.BundleContext; import org.springframework.beans.BeanUtils; import org.springframework.util.ClassUtils; /** * Apache Felix (1.0.3+/1.4.x+/2.0.x) OSGi platform. Automatically detects the available version on the classpath and * uses the appropriate means to configure and instantiate it. * * @author Costin Leau */ public class FelixPlatform extends AbstractOsgiPlatform { private static abstract class Felix1XPlatform implements Platform { private static final Constructor<?> CTOR; static { Class<?> autoActivator = ClassUtils.resolveClassName("org.apache.felix.main.AutoActivator", Felix1XPlatform.class .getClassLoader()); try { CTOR = autoActivator.getConstructor(Map.class); } catch (Exception ex) { throw new IllegalStateException("Cannot instantiate class " + autoActivator, ex); } } private Felix felix; public final BundleContext start() throws Exception { // load properties Map<Object, Object> configMap = getConfiguration(); // pass the auto activator as a list List<Object> list = new ArrayList<Object>(1); list.add(BeanUtils.instantiateClass(CTOR, configMap)); felix = createFelix(configMap, list); felix.start(); return felix.getBundleContext(); } public final void stop() throws Exception { felix.stop(); } abstract Felix createFelix(Map<Object, Object> configMap, List<?> activators) throws Exception; } private static class Felix10XPlatform extends Felix1XPlatform { private static final Constructor<Felix> CTOR; static { try { CTOR = Felix.class.getConstructor(new Class<?>[] { Map.class, List.class }); } catch (NoSuchMethodException ex) { throw new IllegalStateException("Cannot find Felix constructor", ex); } } @Override Felix createFelix(Map<Object, Object> configMap, List<?> activators) throws Exception { return CTOR.newInstance(new Object[] { configMap, activators }); } } private static class Felix14XPlatform extends Felix1XPlatform { @Override Felix createFelix(Map<Object, Object> configMap, List<?> activators) throws Exception { configMap.put("felix.systembundle.activators", activators); return new Felix(configMap); } } private static class Felix20XPlatform implements Platform { private FrameworkTemplate fwkTemplate; private final Log log; Felix20XPlatform(Log log) { this.log = log; } public BundleContext start() throws Exception { Map<Object, Object> configMap = getConfiguration(); Felix fx = new Felix(configMap); fwkTemplate = new DefaultFrameworkTemplate(fx, log); fwkTemplate.init(); BundleContext context = fx.getBundleContext(); AutoProcessor.process(configMap, context); fwkTemplate.start(); return context; } public void stop() throws Exception { fwkTemplate.stopAndWait(1000); } } private static enum FelixVersion { V_10X, V_14X, V_20X } private static FelixVersion FELIX_VERSION; private static final Log log = LogFactory.getLog(FelixPlatform.class); private static final String FELIX_PROFILE_DIR_PROPERTY = "felix.cache.profiledir"; /** new property in 1.4.0 replacing cache.profiledir */ private static final String OSGI_STORAGE_PROPERTY = "org.osgi.framework.storage"; static { ClassLoader loader = Felix.class.getClassLoader(); // detect available Felix version if (ClassUtils.isPresent("org.apache.felix.main.AutoProcessor", loader)) { FELIX_VERSION = FelixVersion.V_20X; } else { if (ClassUtils.isPresent("org.apache.felix.main.RegularBundleInfo", loader)) { FELIX_VERSION = FelixVersion.V_14X; } FELIX_VERSION = FelixVersion.V_10X; } } private BundleContext context; private File felixStorageDir; private Platform platform; public FelixPlatform() { toString = "Felix OSGi Platform"; } Properties getPlatformProperties() { // load Felix configuration Properties props = new Properties(); createStorageDir(props); // disable logging props.put("felix.log.level", "0"); // use embedded mode props.put("felix.embedded.execution", "true"); return props; } public BundleContext getBundleContext() { return context; } /** * Configuration settings for the OSGi test run. * * @return */ private void createStorageDir(Properties configProperties) { // create a temporary file if none is set if (felixStorageDir == null) { felixStorageDir = createTempDir("felix"); felixStorageDir.deleteOnExit(); if (log.isTraceEnabled()) log.trace("Felix storage dir is " + felixStorageDir.getAbsolutePath()); } configProperties.setProperty(FELIX_PROFILE_DIR_PROPERTY, this.felixStorageDir.getAbsolutePath()); configProperties.setProperty(OSGI_STORAGE_PROPERTY, this.felixStorageDir.getAbsolutePath()); configProperties.setProperty("org.osgi.framework.storage.clean", "onFirstInit"); } public void start() throws Exception { if (platform == null) { // initialize properties and set them as system wide so Felix can pick them up Map<Object, Object> configProperties = getConfigurationProperties(); System.getProperties().putAll(configProperties); switch (FELIX_VERSION) { case V_20X: platform = new Felix20XPlatform(null); break; case V_14X: platform = new Felix14XPlatform(); break; // fallback to 10-12 version default: platform = new Felix10XPlatform(); break; } context = platform.start(); } } /** * Returns the platform configuration for creating a Felix instance. Uses Felix classes to load and process the * system properties. * * @return Felix configuration */ private static Map<Object, Object> getConfiguration() { // Load system properties. Main.loadSystemProperties(); // Read configuration properties. Properties configProps = Main.loadConfigProperties(); if (configProps == null) { configProps = new Properties(); } // Copy framework properties from the system properties. Main.copySystemProperties(configProps); // Create a (Felix specific) case-insensitive property map return new StringMap(configProps, false); } public void stop() throws Exception { if (platform != null) { try { platform.stop(); } finally { context = null; platform = null; // remove cache folder IOUtils.delete(felixStorageDir); } } } }