blob: 2100b4509f7fce39078510760596cdf4d277feed [file] [log] [blame]
/******************************************************************************
* 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(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(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);
}
}
}
}