summaryrefslogtreecommitdiffstats
path: root/branches/sca-equinox/modules/osgi-runtime/src
diff options
context:
space:
mode:
Diffstat (limited to 'branches/sca-equinox/modules/osgi-runtime/src')
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/EquinoxRuntime.java117
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/FelixRuntime.java253
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/KnopflerfishRuntime.java168
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiBundleActivator.java252
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntime.java275
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeModuleActivator.java47
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator18
-rw-r--r--branches/sca-equinox/modules/osgi-runtime/src/test/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeTestCase.java78
8 files changed, 1208 insertions, 0 deletions
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/EquinoxRuntime.java b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/EquinoxRuntime.java
new file mode 100644
index 0000000000..43101b14c9
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/EquinoxRuntime.java
@@ -0,0 +1,117 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Implementation of an OSGi Runtime using Equinox.
+ *
+ * @version $Rev$ $Date$
+ */
+public class EquinoxRuntime extends OSGiRuntime {
+
+
+ private static BundleContext bundleContext;
+
+ private static EquinoxRuntime instance;
+
+ private static Class<?> eclipseStarterClass;
+
+ public static OSGiRuntime getInstance() throws Exception {
+ if (instance == null) {
+ eclipseStarterClass = EquinoxRuntime.class.getClassLoader().loadClass("org.eclipse.core.runtime.adaptor.EclipseStarter");
+ EquinoxRuntime runtime = new EquinoxRuntime();
+ instance = runtime;
+ }
+ return instance;
+ }
+
+ @Override
+ protected BundleContext startRuntime(boolean tuscanyRunningInOSGiContainer) throws Exception {
+
+ if (bundleContext != null)
+ return bundleContext;
+
+ Method startupMethod = eclipseStarterClass.getMethod("startup", String [].class, Runnable.class);
+
+ // Equinox version 3.2 upwards have a startup method which returns BundleContext
+ if (startupMethod.getReturnType() == BundleContext.class) {
+ bundleContext = (BundleContext) startupMethod.invoke(null, new String[] {"-clean", "-console"}, null );
+ }
+ else {
+
+ // Older versions of Equinox don't have a public method to obtain system bundlecontext
+ // Extract bundleContext from the private field 'context'. We are assuming that
+ // there is no access restriction
+ Method mainMethod = eclipseStarterClass.getMethod("main", String [].class);
+ mainMethod.invoke(null, (Object)new String[] {"-clean", "-console"});
+
+ Field contextField = eclipseStarterClass.getDeclaredField("context");
+ contextField.setAccessible(true);
+ bundleContext = (BundleContext) contextField.get(null);
+
+ }
+
+
+ return bundleContext;
+
+ }
+
+ @Override
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ @Override
+ protected void setBundleContext(BundleContext bundleContext) {
+ super.setBundleContext(bundleContext);
+ EquinoxRuntime.bundleContext = bundleContext;
+ }
+
+ @Override
+ public void shutdown() throws Exception {
+
+ if (bundleContext == null)
+ return;
+ bundleContext = null;
+ instance = null;
+ if (eclipseStarterClass != null) {
+ Method shutdownMethod = eclipseStarterClass.getMethod("shutdown");
+ try {
+ shutdownMethod.invoke(eclipseStarterClass);
+ } catch (Exception e) {
+ // Ignore errors.
+ }
+ }
+ super.shutdown();
+ }
+
+
+ @Override
+ public boolean supportsBundleFragments() {
+ return false;
+ }
+
+
+
+}
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/FelixRuntime.java b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/FelixRuntime.java
new file mode 100644
index 0000000000..f8b56c88d6
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/FelixRuntime.java
@@ -0,0 +1,253 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Implementation of an OSGi Runtime using Felix.
+ *
+ * @version $Rev$ $Date$
+ */
+public class FelixRuntime extends OSGiRuntime implements BundleActivator {
+
+ private static BundleContext bundleContext;
+
+ private static FelixRuntime instance;
+
+ private static Class<?> felixMainClass;
+ private static Class<?> felixClass;
+ private static Object felix;
+
+ public static OSGiRuntime getInstance() throws Exception {
+ if (instance == null) {
+ felixMainClass = FelixRuntime.class.getClassLoader().loadClass("org.apache.felix.main.Main");
+ FelixRuntime runtime = new FelixRuntime();
+ instance = runtime;
+ }
+ return instance;
+ }
+
+
+ private static void deleteDirectory(File dir) {
+
+ File[] files = dir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory())
+ deleteDirectory(files[i]);
+ else
+ files[i].delete();
+ }
+ dir.delete();
+
+ }
+
+ @Override
+ protected BundleContext startRuntime(boolean tuscanyRunningInOSGiContainer) throws Exception {
+
+ if (bundleContext != null)
+ return bundleContext;
+
+
+ ClassLoader cl = FelixRuntime.class.getClassLoader();
+
+ felixClass = cl.loadClass("org.apache.felix.framework.Felix");
+ Method propsMethod = felixMainClass.getMethod("loadConfigProperties");
+ Properties props = (Properties)propsMethod.invoke(null);
+
+ String profileDirName = ".felix";
+ File targetDir = new File("target");
+ if (targetDir.exists() && targetDir.isDirectory())
+ profileDirName = "target/" + profileDirName;
+ File profileDir = new File(profileDirName);
+ if (profileDir.isDirectory())
+ deleteDirectory(profileDir);
+ else
+ profileDir.delete();
+ profileDir.mkdir();
+ profileDir.deleteOnExit();
+
+ props.put("felix.cache.profiledir", profileDir.getAbsolutePath());
+ props.put("felix.embedded.execution", "true");
+
+ String systemPackages =
+ "org.osgi.framework; version=1.3.0," +
+ "org.osgi.service.packageadmin; version=1.2.0, " +
+ "org.osgi.service.startlevel; version=1.0.0, " +
+ "org.osgi.service.url; version=1.0.0, " +
+ "org.osgi.util.tracker; version=1.3.2, " +
+ "javax.xml, " +
+ "javax.xml.datatype, " +
+ "javax.xml.namespace, " +
+ "javax.xml.parsers, " +
+ "javax.xml.transform, " +
+ "javax.xml.transform.dom, " +
+ "javax.xml.transform.sax, " +
+ "javax.xml.transform.stream, " +
+ "javax.xml.validation, " +
+ "javax.xml.xpath, " +
+ "org.apache.xerces.jaxp.datatype, " +
+ "org.w3c.dom, " +
+ "org.xml.sax, " +
+ "org.xml.sax.ext, " +
+ "org.xml.sax.helpers, " +
+ "javax.security.auth, " +
+ "javax.naming, " +
+ "javax.naming.spi, " +
+ "javax.naming.directory, " +
+ "javax.management, " +
+ "sun.misc";
+
+
+ if (!tuscanyRunningInOSGiContainer) {
+ systemPackages = systemPackages + ", org.osoa.sca.annotations, org.osoa.sca";
+ systemPackages = systemPackages + ", commonj.sdo, commonj.sdo.helper, org.apache.tuscany.sdo.helper, org.apache.tuscany.sdo.impl, org.apache.tuscany.sdo.model, org.apache.tuscany.sdo.model.impl";
+ systemPackages = systemPackages + ", org.eclipse.emf.ecore, org.eclipse.emf.ecore.util, org.eclipse.emf.ecore.impl";
+ }
+ props.put("org.osgi.framework.system.packages", systemPackages);
+
+ try {
+ Constructor felixConstructor = felixClass.getConstructor(Map.class, List.class);
+ List<BundleActivator> activators = new ArrayList<BundleActivator>();
+
+ Class<?> autoActivatorClass = cl.loadClass("org.apache.felix.main.AutoActivator");
+ Constructor autoActivatorConstructor = autoActivatorClass.getConstructor(Map.class);
+ BundleActivator autoActivator = (BundleActivator)autoActivatorConstructor.newInstance(props);
+ activators.add(autoActivator);
+
+ felix = felixConstructor.newInstance(props, activators);
+ ((Bundle)felix).start();
+ bundleContext = ((Bundle)felix).getBundleContext();
+
+
+ } catch (Exception e) {
+
+ // This is the older Felix API which has been retained temporarily to avoid build break
+ // TODO: Remove these once Felix 1.0.0 is released.
+
+ Class<?> propertyResolverClass = cl.loadClass("org.apache.felix.framework.util.MutablePropertyResolver");
+ Class<?> propertyResolverImplClass = cl.loadClass("org.apache.felix.framework.util.MutablePropertyResolverImpl");
+
+ Constructor implConstructor = propertyResolverImplClass.getConstructor(Map.class);
+ Object mutableProps = implConstructor.newInstance(props);
+
+
+ try {
+ Constructor felixConstructor = felixClass.getConstructor(propertyResolverClass, List.class);
+ List<BundleActivator> activators = new ArrayList<BundleActivator>();
+ felix = felixConstructor.newInstance(mutableProps, activators);
+ ((Bundle)felix).start();
+ bundleContext = ((Bundle)felix).getBundleContext();
+ } catch (Exception e1) {
+
+
+ felix = felixClass.newInstance();
+ Method startMethod = felixClass.getMethod("start", propertyResolverClass, List.class);
+ List<BundleActivator> activators = new ArrayList<BundleActivator>();
+ BundleActivator activator = new FelixRuntime();
+ activators.add(activator);
+ startMethod.invoke(felix, mutableProps, activators);
+
+ synchronized (activator) {
+ int retries = 0;
+ while (bundleContext == null && retries++ < 10) {
+ activator.wait(1000);
+ }
+ }
+ }
+ }
+
+ return bundleContext;
+
+ }
+
+ public void start(BundleContext context) throws Exception {
+
+ bundleContext = context;
+ synchronized (this) {
+ this.notify();
+ }
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ bundleContext = null;
+ }
+
+
+
+ @Override
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ @Override
+ protected void setBundleContext(BundleContext bundleContext) {
+ super.setBundleContext(bundleContext);
+ FelixRuntime.bundleContext = bundleContext;
+ }
+
+
+ @Override
+ public void shutdown() throws Exception {
+
+ if (bundleContext == null)
+ return;
+ bundleContext = null;
+ instance = null;
+
+ // We could potentially use Felix.stopAndWait, but use timed wait for now because
+ // stopAndWait hangs with Felix 1.0.0
+ if (felix instanceof Bundle) {
+ Bundle felixBundle = (Bundle)felix;
+ felixBundle.stop();
+ int retries = 50;
+ synchronized (felix) {
+ while (retries-- > 0 && felixBundle.getState() != Bundle.UNINSTALLED) {
+ felix.wait(100);
+ }
+ }
+ }
+ else if (felix != null) {
+ Method shutdownMethod = felixClass.getMethod("shutdown");
+ try {
+ shutdownMethod.invoke(felix);
+ } catch (Exception e) {
+ // Ignore errors
+ }
+ felix = null;
+ }
+ super.shutdown();
+ }
+
+ @Override
+ public boolean supportsBundleFragments() {
+ return false;
+ }
+
+}
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/KnopflerfishRuntime.java b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/KnopflerfishRuntime.java
new file mode 100644
index 0000000000..19041daf50
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/KnopflerfishRuntime.java
@@ -0,0 +1,168 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+/**
+ * Implementation of an OSGi Runtime using Knopflerfish.
+ *
+ * @version $Rev$ $Date$
+ */
+public class KnopflerfishRuntime extends OSGiRuntime {
+
+ private static BundleContext bundleContext;
+
+ private static KnopflerfishRuntime instance;
+
+
+ private static Class<?> frameworkClass;
+
+ private static Object framework;
+
+ public static OSGiRuntime getInstance() throws Exception {
+ if (instance == null) {
+ frameworkClass = KnopflerfishRuntime.class.getClassLoader().loadClass("org.knopflerfish.framework.Framework");
+ KnopflerfishRuntime runtime = new KnopflerfishRuntime();
+ instance = runtime;
+ }
+ return instance;
+ }
+
+
+
+ // FIXME: Knopflerfish does not expose the methods used for configuration as public methods
+ // It may be worth using the private methods in org.knopflerfish.framework.Main for
+ // configuring using reflection if security policies allow it.
+ // For now, a simple configuration routine reads sca.xargs from the directory in
+ // the classpath which contains framework.jar. The entries in init.xargs starting with
+ // -install are assumed to be single-line entries with full bundle location.
+ //
+ @Override
+ protected BundleContext startRuntime(boolean tuscanyRunningInOSGiContainer) throws Exception {
+
+ if (bundleContext != null)
+ return bundleContext;
+
+
+
+ System.setProperty("org.knopflerfish.framework.bundlestorage", "memory");
+
+ Constructor frameworkConstructor = frameworkClass.getConstructor(Object.class);
+ framework = frameworkConstructor.newInstance(new KnopflerfishRuntime());
+ Method launchMethod = frameworkClass.getMethod("launch", long.class);
+ launchMethod.invoke(framework, 0);
+ Method getContextMethod = frameworkClass.getMethod("getSystemBundleContext");
+ bundleContext = (BundleContext)getContextMethod.invoke(framework);
+
+ System.setProperty("com.gatespace.bundle.cm.store", "knopflerfish.store");
+ File xargsFile = null;
+ String classpath = System.getProperty("java.class.path");
+ String[] classpathEntries = classpath.split(System.getProperty("path.separator"));
+ for (int i = 0; i < classpathEntries.length; i++) {
+ if (classpathEntries[i].endsWith("framework.jar")) {
+ String path = classpathEntries[i].substring(0, classpathEntries[i].length() - "framework.jar".length());
+ path = path + "sca.xargs";
+ xargsFile = new File(path);
+ if (!xargsFile.exists())
+ xargsFile = null;
+ break;
+ }
+ }
+ if (xargsFile != null) {
+ BufferedReader reader = new BufferedReader(new FileReader(xargsFile));
+ String line;
+ Hashtable<String, Bundle> bundles = new Hashtable<String, Bundle>();
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("-install")) {
+ try {
+
+ String bundleLocation = line.substring("-install".length()).trim();
+ Bundle bundle = bundleContext.installBundle(bundleLocation);
+ bundles.put(bundleLocation, bundle);
+
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+
+ }
+ if (line.startsWith("-start")) {
+
+ try {
+ String bundleLocation = line.substring("-start".length()).trim();
+ Bundle bundle = bundles.get(bundleLocation);
+ bundle.start();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ return bundleContext;
+
+ }
+
+ @Override
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ @Override
+ protected void setBundleContext(BundleContext bundleContext) {
+ super.setBundleContext(bundleContext);
+ KnopflerfishRuntime.bundleContext = bundleContext;
+ }
+
+ @Override
+ public void shutdown() throws Exception {
+
+ if (bundleContext == null)
+ return;
+ bundleContext = null;
+ instance = null;
+ if (framework != null) {
+ Method shutdownMethod = frameworkClass.getMethod("shutdown");
+ try {
+ shutdownMethod.invoke(framework);
+ } catch (Exception e) {
+ // Ignore errors
+ }
+ framework = null;
+ }
+ super.shutdown();
+
+ }
+
+ @Override
+ public boolean supportsBundleFragments() {
+ return true;
+ }
+}
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiBundleActivator.java b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiBundleActivator.java
new file mode 100644
index 0000000000..b87f70deef
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiBundleActivator.java
@@ -0,0 +1,252 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import org.apache.tuscany.sca.extensibility.ServiceDiscovery;
+import org.apache.tuscany.sca.extensibility.osgi.OSGiServiceDiscoverer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+/**
+ * OSGi bundle activator, which is run when Tuscany is run inside an OSGi runtime.
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiBundleActivator implements BundleActivator, BundleListener {
+
+ private static final String TUSCANY_SCA_BUNDLE_PREFIX = "org.apache.tuscany.sca";
+ private static final String TUSCANY_3RD_PARTY_BUNDLE_PREFIX = "org.apache.tuscany.sca.3rdparty";
+ private OSGiRuntime runtime;
+ /*
+ private ConcurrentHashMap<Bundle, ClassLoader> serviceDiscoveryClassLoaders =
+ new ConcurrentHashMap<Bundle, ClassLoader>();
+ */
+ private BundleClassLoader threadContextClassLoader;
+ private ClassLoader origTCCL;
+ private Bundle thisBundle;
+
+ public void start(BundleContext bundleContext) throws Exception {
+
+ initializeTuscanyClassLoaders(bundleContext);
+
+ runtime = OSGiRuntime.findRuntime();
+ runtime.setBundleContext(bundleContext);
+ runtime.setContextClassLoader(threadContextClassLoader);
+ runtime.initialize();
+
+ }
+
+ public void stop(BundleContext bundleContext) throws Exception {
+
+ // runtime.shutdown();
+
+ if (Thread.currentThread().getContextClassLoader() == threadContextClassLoader)
+ Thread.currentThread().setContextClassLoader(origTCCL);
+ }
+
+ /**
+ * Create a bundle ClassLoader which has visibility of all Tuscany related
+ * bundles. Use this ClassLoader as TCCL, and the Tuscany service discovery
+ * ClassLoader.
+ *
+ * @param bundleContext
+ */
+ private void initializeTuscanyClassLoaders(BundleContext bundleContext) {
+
+ OSGiServiceDiscoverer discoverer = new OSGiServiceDiscoverer(bundleContext);
+ ServiceDiscovery.getInstance().setServiceDiscoverer(discoverer);
+ thisBundle = bundleContext.getBundle();
+
+ origTCCL = Thread.currentThread().getContextClassLoader();
+
+ threadContextClassLoader = new BundleClassLoader(thisBundle, origTCCL);
+
+ Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+
+ ClassLoader cl = new BundleClassLoader(thisBundle, null);
+ // ServiceDiscovery.getInstance().registerClassLoader(cl);
+ // serviceDiscoveryClassLoaders.put(thisBundle, cl);
+
+ Bundle[] bundles = bundleContext.getBundles();
+ for (Bundle bundle : bundles) {
+ updateBundleClassLoader(bundle);
+ }
+ bundleContext.addBundleListener(this);
+
+ }
+
+ /**
+ * Add an installed bundle to the list of bundles in the service discovery classpath
+ * if the installed bundle is a Tuscany bundle using the same Core-SPI bundle.
+ * Since the bundle containing this activator is in Tuscany Runtime, this bundle
+ * will provide access to Runtime and its dependencies (SPI, SCA-API). Third party
+ * bundles don't need to be in the service discovery classpath, since they will be automatically
+ * imported by bundles which require them. That leaves Tuscany extension bundles,
+ * which are added to the service discovery classpath here.
+ *
+ * 3rd party bundle should be explicitly added to TCCL since classes from these
+ * bundles use TCCL to load other classes from the bundle.
+ *
+ * Load one class from the bundle to check if the new bundle matches this runtime bundle.
+ *
+ * @param bundle
+ */
+ private void updateBundleClassLoader(Bundle bundle) {
+
+ if (bundle.getSymbolicName().startsWith(TUSCANY_SCA_BUNDLE_PREFIX)) {
+
+ // This may be the third party bundle.
+ if (bundle.getSymbolicName().startsWith(TUSCANY_3RD_PARTY_BUNDLE_PREFIX)) {
+
+ threadContextClassLoader.addBundle(bundle);
+ } else {
+
+ String thisBundleVersion = (String)thisBundle.getHeaders().get("Bundle-Version");
+ String bundleVersion = (String)bundle.getHeaders().get("Bundle-Version");
+
+ if (thisBundleVersion == null || bundleVersion == null || thisBundleVersion.equals(bundleVersion)) {
+
+ if (!threadContextClassLoader.bundles.contains(bundle)) {
+ ClassLoader cl = new BundleClassLoader(bundle, null);
+ // ServiceDiscovery.getInstance().registerClassLoader(cl);
+ // serviceDiscoveryClassLoaders.put(bundle, cl);
+ threadContextClassLoader.addBundle(bundle);
+ }
+ }
+ }
+ } else {
+ threadContextClassLoader.addBundle(bundle);
+ }
+ }
+
+ /**
+ * Handle bundle install/uninstall events
+ */
+ public void bundleChanged(BundleEvent event) {
+
+ Bundle bundle = event.getBundle();
+ if (event.getType() == BundleEvent.UNINSTALLED) {
+// ClassLoader cl = serviceDiscoveryClassLoaders.get(bundle);
+// if (cl != null) {
+// ServiceDiscovery.getInstance().unregisterClassLoader(cl);
+// }
+ threadContextClassLoader.removeBundle(bundle);
+ } else if (event.getType() == BundleEvent.INSTALLED) {
+ updateBundleClassLoader(bundle);
+ }
+ }
+
+ /**
+ * Bundle ClassLoader that searches a bundle classpath consisting of
+ * a list of bundles. The parent ClassLoader is searched only if a class
+ * cannot be loaded from the bundle classpath. Tuscany bundles are
+ * dynamically added and removed from the bundle classpath when the bundles
+ * are installed and uninstalled.
+ *
+ * No ordering of bundles is maintained at the moment.
+ *
+ */
+ private static class BundleClassLoader extends ClassLoader {
+
+ private HashSet<Bundle> bundles;
+
+ BundleClassLoader(Bundle bundle, ClassLoader parent) {
+ super(parent);
+ this.bundles = new HashSet<Bundle>();
+ bundles.add(bundle);
+ }
+
+ private synchronized void addBundle(Bundle bundle) {
+ bundles.add(bundle);
+ }
+
+ private synchronized void removeBundle(Bundle bundle) {
+ if (bundles.contains(bundle))
+ bundles.remove(bundle);
+ }
+
+ @Override
+ protected Class<?> findClass(String className) throws ClassNotFoundException {
+ Class<?> clazz = null;
+ synchronized (this) {
+ for (Bundle bundle : bundles) {
+ try {
+ clazz = bundle.loadClass(className);
+ break;
+ } catch (ClassNotFoundException e) {
+ } catch (NoClassDefFoundError e) {
+ }
+
+ }
+ }
+ if (clazz != null) {
+ return clazz;
+ }
+ return super.findClass(className);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Enumeration<URL> getResources(String resName) throws IOException {
+ HashSet<URL> urlSet = new HashSet<URL>();
+ Enumeration<URL> urls = null;
+ synchronized (this) {
+ for (Bundle bundle : bundles) {
+ urls = bundle.getResources(resName);
+ if (urls != null) {
+ while (urls.hasMoreElements()) {
+ urlSet.add(urls.nextElement());
+ }
+ }
+ }
+ }
+ if (urlSet.size() > 0)
+ return Collections.enumeration(urlSet);
+ return super.getResources(resName);
+ }
+
+ @Override
+ public URL getResource(String resName) {
+ URL url = null;
+ synchronized (this) {
+ for (Bundle bundle : bundles) {
+ url = bundle.getResource(resName);
+ if (url != null)
+ return url;
+ }
+ }
+ return super.getResource(resName);
+ }
+
+ @Override
+ public String toString() {
+ return "Tuscany BundleClassLoader " + bundles.iterator().next();
+ }
+
+ }
+}
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntime.java b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntime.java
new file mode 100644
index 0000000000..79b1c0a5f4
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntime.java
@@ -0,0 +1,275 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Base OSGiRuntime implementation.
+ *
+ * @version $Rev$ $Date$
+ */
+public abstract class OSGiRuntime {
+ private static final Logger logger = Logger.getLogger(OSGiRuntime.class.getName());
+
+ public abstract BundleContext getBundleContext();
+
+ public abstract boolean supportsBundleFragments();
+
+ protected abstract BundleContext startRuntime(boolean tuscanyRunningInOSGiContainer) throws Exception;
+
+ private static OSGiRuntime instance;
+
+ private BundleContext bundleContext;
+
+ private PackageAdmin packageAdmin;
+
+ private boolean tuscanyRunningInOSGiContainer;
+
+ private ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+
+ /**
+ * System property org.apache.tuscany.implementation.osgi.runtime.OSGiRuntime can be set to the
+ * name of the OSGiRuntime class (eg. EquinoxRuntime). If set, start this runtime and return the
+ * system bundlecontext. If not set, start Equinox/Felix/Knopflerfish (in that order) from the
+ * classpath.
+ *
+ * @throws BundleException
+ */
+ public static synchronized OSGiRuntime findRuntime() throws Exception {
+
+ if (instance != null) {
+
+ return instance;
+ }
+ String runtimeClassName = System.getProperty(OSGiRuntime.class.getName());
+
+
+ if (runtimeClassName != null) {
+ try {
+ Class<?> runtimeClass = OSGiRuntime.class.getClassLoader().loadClass(runtimeClassName);
+ Method method = runtimeClass.getMethod("getInstance");
+ instance = (OSGiRuntime) method.invoke(null);
+ return instance;
+
+ } catch (Exception e) {
+ throw new BundleException("Could not start OSGi runtime " + runtimeClassName, e);
+ }
+ }
+
+ try {
+
+ instance = EquinoxRuntime.getInstance();
+ return instance;
+
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ } catch (Throwable e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ }
+
+ try {
+
+ instance = FelixRuntime.getInstance();
+ return instance;
+
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ } catch (Throwable e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ }
+
+ try {
+
+ instance = KnopflerfishRuntime.getInstance();
+ return instance;
+
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ } catch (Throwable e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ }
+
+ throw new BundleException("Could not start OSGi runtime from the classpath");
+ }
+
+
+ public static synchronized OSGiRuntime getRuntime() throws Exception {
+ return getRuntime(false);
+ }
+
+ public static synchronized OSGiRuntime getRuntime(boolean tuscanyRunningInOSGiContainer) throws Exception {
+
+ instance = findRuntime();
+
+ if (instance != null) {
+
+ if (instance.bundleContext == null) {
+ instance.tuscanyRunningInOSGiContainer = tuscanyRunningInOSGiContainer;
+ instance.startRuntime(tuscanyRunningInOSGiContainer);
+ instance.initialize();
+ }
+ return instance;
+ }
+ return instance;
+ }
+
+
+ public void shutdown() throws Exception {
+
+ bundleContext = null;
+ packageAdmin = null;
+ }
+
+ protected void setBundleContext(BundleContext bundleContext) {
+ instance.tuscanyRunningInOSGiContainer = true;
+ this.bundleContext = bundleContext;
+ }
+
+
+
+ public ClassLoader getContextClassLoader() {
+ return contextClassLoader;
+ }
+
+ protected void setContextClassLoader(ClassLoader contextClassLoader) {
+ this.contextClassLoader = contextClassLoader;
+ }
+
+ protected void initialize() {
+
+ bundleContext = getBundleContext();
+
+ if (bundleContext != null) {
+
+ org.osgi.framework.ServiceReference packageAdminReference =
+ bundleContext.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (packageAdminReference != null) {
+
+ packageAdmin = (PackageAdmin)bundleContext.getService(packageAdminReference);
+ }
+ }
+
+ }
+
+ public Bundle findBundle(String bundleSymbolicName, String bundleVersion) {
+
+ if (bundleContext != null) {
+ Bundle[] installedBundles = bundleContext.getBundles();
+ for (Bundle bundle : installedBundles) {
+ if (bundleSymbolicName.equals(bundle.getSymbolicName()) && (bundleVersion == null || bundleVersion
+ .equals(bundle.getHeaders().get("Bundle-Version"))))
+ return bundle;
+ }
+
+ }
+ return null;
+ }
+
+ public static synchronized Bundle findInstalledBundle(String bundleLocation) {
+ if (instance != null) {
+ if (bundleLocation.startsWith("bundle:")||bundleLocation.startsWith("bundleresource:")) {
+ try {
+ return findInstalledBundle(new URL(bundleLocation));
+ } catch (MalformedURLException e) {
+ // ignore
+ }
+ } else {
+ return instance.findBundle(bundleLocation);
+ }
+ }
+ return null;
+ }
+
+ public static synchronized Bundle findInstalledBundle(URL bundleURL) {
+ if (instance != null) {
+ if (instance.bundleContext != null) {
+ Bundle[] installedBundles = instance.bundleContext.getBundles();
+ for (Bundle bundle : installedBundles) {
+ try {
+ if (bundle.getEntry("/").getHost().equals(bundleURL.getHost()))
+ return bundle;
+ } catch (Exception e) {
+ // Ignore exception
+ }
+ }
+ }
+ return null;
+ }
+ return null;
+ }
+
+ public Bundle findBundle(String bundleLocation) {
+
+ if (bundleContext != null) {
+ Bundle[] installedBundles = bundleContext.getBundles();
+ for (Bundle bundle : installedBundles) {
+ if (bundle.getLocation().equals(bundleLocation))
+ return bundle;
+ }
+
+ }
+ return null;
+ }
+
+ public Bundle installBundle(String bundleLocation, InputStream inputStream) {
+
+ try {
+ if (bundleContext != null) {
+ Bundle bundle = findBundle(bundleLocation);
+ if (bundle != null)
+ return bundle;
+ if (inputStream == null)
+ bundle = bundleContext.installBundle(bundleLocation);
+ else
+ bundle = bundleContext.installBundle(bundleLocation, inputStream);
+
+ if (bundle != null && packageAdmin != null)
+ packageAdmin.refreshPackages(null);
+
+ return bundle;
+ }
+ } catch (BundleException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Stops the OSGi instance.
+ *
+ * @throws Exception Failed to shutdown the OSGi instance.
+ */
+ public static synchronized void stop() throws Exception {
+ if (instance != null && !instance.tuscanyRunningInOSGiContainer) {
+ instance.shutdown();
+ instance = null;
+ }
+ }
+
+}
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeModuleActivator.java b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeModuleActivator.java
new file mode 100644
index 0000000000..1dbe75f431
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeModuleActivator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.ModuleActivator;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class OSGiRuntimeModuleActivator implements ModuleActivator {
+
+ /**
+ * @see org.apache.tuscany.sca.core.ModuleActivator#start(org.apache.tuscany.sca.core.ExtensionPointRegistry)
+ */
+ public void start(ExtensionPointRegistry registry) {
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.core.ModuleActivator#stop(org.apache.tuscany.sca.core.ExtensionPointRegistry)
+ */
+ public void stop(ExtensionPointRegistry registry) {
+ try {
+ OSGiRuntime.stop();
+ } catch (Throwable e) {
+ // Ignore the exception
+ }
+ }
+
+}
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator b/branches/sca-equinox/modules/osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator
new file mode 100644
index 0000000000..bd3fd72280
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator
@@ -0,0 +1,18 @@
+# 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.
+# Implementation class for the ModuleActivator
+org.apache.tuscany.sca.osgi.runtime.OSGiRuntimeModuleActivator
diff --git a/branches/sca-equinox/modules/osgi-runtime/src/test/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeTestCase.java b/branches/sca-equinox/modules/osgi-runtime/src/test/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeTestCase.java
new file mode 100644
index 0000000000..7ce3f6c18f
--- /dev/null
+++ b/branches/sca-equinox/modules/osgi-runtime/src/test/java/org/apache/tuscany/sca/osgi/runtime/OSGiRuntimeTestCase.java
@@ -0,0 +1,78 @@
+/*
+ * 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.tuscany.sca.osgi.runtime;
+
+import junit.framework.TestCase;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Test OSGi runtime.
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiRuntimeTestCase extends TestCase {
+ private OSGiRuntime runtime;
+
+ /**
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ try {
+ this.runtime = OSGiRuntime.getRuntime();
+ } catch ( Throwable e ) {
+ System.out.println( "DOB: OSGiRuntimeTestCase.setUp error=" + e );
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ OSGiRuntime.stop();
+ }
+
+ public void testRuntime() throws Exception {
+
+ BundleContext bc1 = runtime.getBundleContext();
+
+ assertNotNull(bc1);
+
+ BundleContext bc2 = runtime.getBundleContext();
+
+ assertNotNull(bc2);
+
+ assertTrue(bc1 == bc2);
+
+ OSGiRuntime.stop();
+ runtime = OSGiRuntime.getRuntime();
+
+ BundleContext bc3 = runtime.getBundleContext();
+
+ assertNotNull(bc3);
+
+ assertTrue(bc1 != bc3);
+
+ }
+
+}