/* * 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.node.equinox.launcher; import static java.lang.System.currentTimeMillis; import static java.lang.System.setProperty; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.LAUNCHER_EQUINOX_LIBRARIES; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.artifactId; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.bundleName; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.file; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.fixupBundle; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.jarVersion; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.runtimeClasspathEntries; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.string; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.thirdPartyLibraryBundle; import static org.apache.tuscany.sca.node.equinox.launcher.NodeLauncherUtil.thisBundleLocation; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.core.runtime.adaptor.EclipseStarter; import org.eclipse.core.runtime.adaptor.LocationManager; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; /** * Wraps the Equinox runtime. */ public class EquinoxHost { private static Logger logger = Logger.getLogger(EquinoxHost.class.getName()); static { if (getSystemProperty("osgi.debug") != null) { logger.setLevel(Level.FINE); } } private BundleContext bundleContext; private Bundle launcherBundle; private boolean startedEclipse; private List bundleFiles = new ArrayList(); private List bundleNames = new ArrayList(); private Collection jarFiles = new HashSet(); private Map allBundles = new HashMap(); private List installedBundles = new ArrayList(); private Set bundleLocations; private boolean aggregateThirdPartyJars = false; public EquinoxHost() { super(); } public EquinoxHost(Set urls) { super(); this.bundleLocations = urls; } private static String getSystemProperty(final String name) { return AccessController.doPrivileged(new PrivilegedAction() { public String run() { return System.getProperty(name); } }); } private static Properties getSystemProperties() { return AccessController.doPrivileged(new PrivilegedAction() { public Properties run() { Properties props = new Properties(); for (Map.Entry e : System.getProperties().entrySet()) { if (e.getKey() instanceof String) { String prop = (String)e.getKey(); if (prop.startsWith("osgi.") || prop.startsWith("eclipse.")) { props.put(prop, e.getValue()); } } } return props; } }); } private static void put(Properties props, String key, String value) { if (!props.contains(key)) { props.put(key, value); } } /** * Start the Equinox host. * * @return */ public BundleContext start() { try { if (!EclipseStarter.isRunning()) { String version = getSystemProperty("java.specification.version"); String profile = "J2SE-1.5.profile"; if (version.startsWith("1.6")) { profile = "JavaSE-1.6.profile"; } Properties props = new Properties(); InputStream is = getClass().getResourceAsStream(profile); if (is != null) { props.load(is); is.close(); } props.putAll(getSystemProperties()); // Configure Eclipse properties // Use the boot classloader as the parent classloader put(props, "osgi.contextClassLoaderParent", "app"); // Set startup properties put(props, EclipseStarter.PROP_CLEAN, "true"); // Set location properties // FIXME Use proper locations String tmpDir = getSystemProperty("java.io.tmpdir"); File root = new File(tmpDir); // Add user name as the prefix. For multiple users on the same Lunix, // there will be permission issue if one user creates the .tuscany folder // first under /tmp with no write permission for others. String userName = getSystemProperty("user.name"); if (userName != null) { root = new File(root, userName); } root = new File(root, ".tuscany/equinox/" + UUID.randomUUID().toString()); if (logger.isLoggable(Level.FINE)) { logger.fine("Equinox location: " + root); } put(props, LocationManager.PROP_INSTANCE_AREA_DEFAULT, new File(root, "workspace").toURI().toString()); put(props, LocationManager.PROP_INSTALL_AREA, new File(root, "install").toURI().toString()); put(props, LocationManager.PROP_CONFIG_AREA_DEFAULT, new File(root, "config").toURI().toString()); put(props, LocationManager.PROP_USER_AREA_DEFAULT, new File(root, "user").toURI().toString()); EclipseStarter.setInitialProperties(props); // Test if the configuration/config.ini or osgi.bundles has been set // If yes, try to avoid discovery of bundles if (bundleLocations == null) { if (props.getProperty("osgi.bundles") != null) { bundleLocations = Collections.emptySet(); } else { String config = props.getProperty(LocationManager.PROP_CONFIG_AREA); File ini = new File(config, "config.ini"); if (ini.isFile()) { Properties iniProps = new Properties(); iniProps.load(new FileInputStream(ini)); if (iniProps.getProperty("osgi.bundles") != null) { bundleLocations = Collections.emptySet(); } } } } // Start Eclipse bundleContext = EclipseStarter.startup(new String[] {}, null); startedEclipse = true; } else { // Get bundle context from the running Eclipse instance bundleContext = EclipseStarter.getSystemBundleContext(); } // Determine the runtime classpath entries Set urls; urls = findBundleLocations(); // Sort out which are bundles (and not already installed) and which are just // regular JARs for (URL url : urls) { File file = file(url); String bundleName = bundleName(file); if (bundleName != null) { bundleFiles.add(url); bundleNames.add(bundleName); } else { if (file.isFile()) { jarFiles.add(url); } } } // Get the already installed bundles for (Bundle bundle : bundleContext.getBundles()) { allBundles.put(bundle.getSymbolicName(), bundle); } // Install the launcher bundle if necessary String launcherBundleName = "org.apache.tuscany.sca.node.launcher.equinox"; String launcherBundleLocation; launcherBundle = allBundles.get(launcherBundleName); if (launcherBundle == null) { launcherBundleLocation = thisBundleLocation(); if (logger.isLoggable(Level.FINE)) { logger.fine("Installing launcher bundle: " + launcherBundleLocation); } fixupBundle(launcherBundleLocation); launcherBundle = bundleContext.installBundle(launcherBundleLocation); allBundles.put(launcherBundleName, launcherBundle); installedBundles.add(launcherBundle); } else { if (logger.isLoggable(Level.FINE)) { logger.fine("Launcher bundle is already installed: " + string(launcherBundle, false)); } // launcherBundleLocation = thisBundleLocation(launcherBundle); } // FIXME: SDO bundles dont have the correct dependencies setProperty("commonj.sdo.impl.HelperProvider", "org.apache.tuscany.sdo.helper.HelperProviderImpl"); // Install the Tuscany bundles long start = currentTimeMillis(); if (logger.isLoggable(Level.FINE)) { logger.fine("Generating third-party library bundle."); } long libraryStart = currentTimeMillis(); if (!aggregateThirdPartyJars) { for (URL jarFile : jarFiles) { installAsBundle(jarFile, null); } } else { installAsBundle(jarFiles, LAUNCHER_EQUINOX_LIBRARIES); } if (logger.isLoggable(Level.FINE)) { logger .fine("Third-party library bundle installed in " + (currentTimeMillis() - libraryStart) + " ms: "); } // Install all the other bundles that are not already installed for (URL bundleFile: bundleFiles) { fixupBundle(bundleFile.toString()); } for (int i = 0, n = bundleFiles.size(); i < n; i++) { URL bundleFile = bundleFiles.get(i); String bundleName = bundleNames.get(i); if (bundleName.contains("org.eclipse.jdt.junit")) { continue; } installBundle(bundleFile, bundleName); } long end = currentTimeMillis(); if (logger.isLoggable(Level.FINE)) { logger.fine("Tuscany bundles are installed in " + (end - start) + " ms."); } // Start the extensiblity and launcher bundles String extensibilityBundleName = "org.apache.tuscany.sca.extensibility.equinox"; Bundle extensibilityBundle = allBundles.get(extensibilityBundleName); if (extensibilityBundle != null) { if ((extensibilityBundle.getState() & Bundle.ACTIVE) == 0) { if (logger.isLoggable(Level.FINE)) { logger.fine("Starting bundle: " + string(extensibilityBundle, false)); } extensibilityBundle.start(); } else if (logger.isLoggable(Level.FINE)) { logger.fine("Bundle is already started: " + string(extensibilityBundle, false)); } } if ((launcherBundle.getState() & Bundle.ACTIVE) == 0) { if (logger.isLoggable(Level.FINE)) { logger.fine("Starting bundle: " + string(launcherBundle, false)); } launcherBundle.start(); } else if (logger.isLoggable(Level.FINE)) { logger.fine("Bundle is already started: " + string(launcherBundle, false)); } // Start all our bundles for now to help diagnose any class loading issues // startBundles( bundleContext ); return bundleContext; } catch (Exception e) { throw new IllegalStateException(e); } } /** * Start all the bundles as a check for class loading issues * @param bundleContext - the bundle context */ private void startBundles( BundleContext bundleContext ) { for (Bundle bundle: bundleContext.getBundles()) { // if (bundle.getSymbolicName().startsWith("org.apache.tuscany.sca")) { if ((bundle.getState() & Bundle.ACTIVE) == 0) { if (logger.isLoggable(Level.FINE)) { logger.fine("Starting bundle: " + string(bundle, false)); } // end if try { bundle.start(); } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); // throw e; } // end try if (logger.isLoggable(Level.FINE)) { logger.fine("Bundle: " + string(bundle, false)); } // end if } // end if // } // end if } // end for logger.fine("Tuscany bundles are started."); return; } // end startBundles public Bundle installAsBundle(Collection jarFiles, String libraryBundleName) throws IOException, BundleException { // Install a single 'library' bundle for the third-party JAR files Bundle libraryBundle = allBundles.get(libraryBundleName); if (libraryBundle == null) { InputStream library = thirdPartyLibraryBundle(jarFiles, libraryBundleName, null); libraryBundle = bundleContext.installBundle(libraryBundleName, library); allBundles.put(libraryBundleName, libraryBundle); installedBundles.add(libraryBundle); } else { if (logger.isLoggable(Level.FINE)) { logger.fine("Third-party library bundle is already installed: " + string(libraryBundle, false)); } } return libraryBundle; } public Bundle installBundle(URL bundleFile, String bundleName) throws MalformedURLException, BundleException { if (bundleName == null) { try { bundleName = bundleName(file(bundleFile)); } catch (IOException e) { bundleName = null; } } Bundle bundle = allBundles.get(bundleName); if (bundle == null) { long installStart = currentTimeMillis(); String location = bundleFile.toString(); if ("file".equals(bundleFile.getProtocol())) { File target = file(bundleFile); // Use a special "reference" scheme to install the bundle as a reference // instead of copying the bundle location = "reference:file:/" + target.getPath(); } bundle = bundleContext.installBundle(location); if (logger.isLoggable(Level.FINE)) { logger.fine("Bundle installed in " + (currentTimeMillis() - installStart) + " ms: " + string(bundle, false)); } allBundles.put(bundleName, bundle); installedBundles.add(bundle); } return bundle; } public Bundle installAsBundle(URL jarFile, String symbolicName) throws IOException, BundleException { if (symbolicName == null) { symbolicName = LAUNCHER_EQUINOX_LIBRARIES + "." + artifactId(jarFile); } Bundle bundle = allBundles.get(symbolicName); if (bundle == null) { String version = jarVersion(jarFile); if (logger.isLoggable(Level.FINE)) { logger.fine("Installing third-party jar as bundle: " + jarFile); } InputStream is = thirdPartyLibraryBundle(Collections.singleton(jarFile), symbolicName, version); // try/catch and output message added 10/04/2009 Mike Edwards try { bundle = bundleContext.installBundle(symbolicName, is); allBundles.put(symbolicName, bundle); installedBundles.add(bundle); } catch (BundleException e) { System.out.println("EquinoxHost:installAsBundle - BundleException raised when dealing with jar " + symbolicName); throw (e); } // end try // end of addition } return bundle; } private Set findBundleLocations() throws FileNotFoundException, URISyntaxException, MalformedURLException { if (bundleLocations == null) { if (!startedEclipse) { // Use classpath entries from a distribution if there is one and the modules // directories available in a dev environment for example bundleLocations = runtimeClasspathEntries(true, false, true); } else { // Use classpath entries from a distribution if there is one and the classpath // entries on the current application's classloader // *** Changed by Mike Edwards, 9th April 2009 *** // -- this place is reached when starting from within Eclipse so why use the classpath?? // bundleLocations = runtimeClasspathEntries(true, true, false); // Instead search the modules directory bundleLocations = runtimeClasspathEntries(true, true, true); } } return bundleLocations; } /** * Stop the Equinox host. */ public void stop() { try { // Uninstall all the bundles we've installed for (int i = installedBundles.size() - 1; i >= 0; i--) { Bundle bundle = installedBundles.get(i); try { if (logger.isLoggable(Level.FINE)) { logger.fine("Uninstalling bundle: " + string(bundle, false)); } bundle.uninstall(); } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } } installedBundles.clear(); // Shutdown Eclipse if we started it ourselves if (startedEclipse) { startedEclipse = false; EclipseStarter.shutdown(); } } catch (Exception e) { throw new IllegalStateException(e); } } public void setBundleLocations(Set bundleLocations) { this.bundleLocations = bundleLocations; } }