/* * 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; public class FelixRuntime extends OSGiRuntime implements BundleActivator { private static BundleContext bundleContext; private static FelixRuntime instance; private static Class felixClass; private static Object felix; public static OSGiRuntime getInstance() throws Exception { if (instance == null) { FelixRuntime runtime = new FelixRuntime(); runtime.startRuntime(); 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(); } protected BundleContext startRuntime() throws Exception { if (bundleContext != null) return bundleContext; ClassLoader cl = FelixRuntime.class.getClassLoader(); Class felixMainClass = cl.loadClass("org.apache.felix.main.Main"); felixClass = cl.loadClass("org.apache.felix.framework.Felix"); Method propsMethod = felixMainClass.getMethod("loadConfigProperties"); Properties props = (Properties)propsMethod.invoke(null); File profileDir = new File(".felix"); 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"); props.put("org.osgi.framework.system.packages", "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.osoa.sca.annotations; version=1.0.0, " + "org.osoa.sca; version=1.0.0"); try { Constructor felixConstructor = felixClass.getConstructor(Map.class, List.class); List activators = new ArrayList(); 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 activators = new ArrayList(); 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 activators = new ArrayList(); 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 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; } }