package gov.nasa.arc.mct.launch; /******************************************************************************* * Mission Control Technologies, Copyright (c) 2009-2012, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * * The MCT platform is licensed 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. * * MCT includes source code licensed under additional open source licenses. See * the MCT Open Source Licenses file included with this distribution or the About * MCT Licenses dialog available at runtime from the MCT Help menu for additional * information. *******************************************************************************/ import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.ServiceLoader; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.launch.Framework; import org.osgi.framework.launch.FrameworkFactory; public class Startup { /** * A directory along the classpath where we expect to find base OSGi * bundles. */ private static final String OSGI_BUNDLE_DIR = "osgi"; private static final String OSGI_BUNDLE_SYS_PROPERTY = "osgiPluginsList"; /** A directory along the classpath where we expect to find MCT plugins. */ private static final String PLATFORM_BUNDLE_DIR = "platform"; private static final String PLATFORM_BUNDLE_SYS_PROPERTY = "platformPluginsList"; Startup() { try { startOSGI(); } catch (Exception t) { t.printStackTrace(System.err); System.exit(1); } } /** * Substitutes expression. * @param expression - the string. * @param evars - environment variables. * @return the substitute string. */ private static String substitute(String expression, Properties evars) { assert evars != null && expression != null; final String regex = "([^\\)]*)(%\\()([\\w]+)(\\))"; // four groups final Pattern pattern = Pattern.compile(regex); Matcher m = pattern.matcher(expression); StringBuffer sb = new StringBuffer(); while (m.find()) { String evarReplacement = evars.getProperty(m.group(3)); if (evarReplacement == null) { System.err.println(String.format("Expression: %s substituting empty string because evar %s is undefined", expression, m.group(3))); evarReplacement = ""; } String beforeReplacement = m.group(1); sb.append(beforeReplacement + evarReplacement); expression = expression.substring(m.end()); m = pattern.matcher(expression); } return sb.toString() + expression; } private File getCacheDir() { String filePath = substitute(MCTProperties.DEFAULT_MCT_PROPERTIES.getProperty("cacheDir"),System.getProperties()); // Want to make sure that any old bundles are cleared out. File cacheDir = new File(filePath); if (cacheDir.exists()) { if (!deleteDir(cacheDir)) { System.err.println("Could not delete OSGi cache directory"); } } // (Re)create the cache directory. if (!cacheDir.mkdirs()) { throw new RuntimeException("Could not create osgi cache dir (" + cacheDir + "). Ensure that the directory is writable and executable."); } return cacheDir; } private boolean deleteDir(File f) { if (f.isDirectory()) { for (File child : f.listFiles()) { if (!deleteDir(child)) { return false; } } } // The directory is now empty so delete it return f.delete(); } private void startOSGI() { Map<String, String> props = new HashMap<String, String>(); // Start with a clean bundle cache. props.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT); // Set the cache directory path. props.put(Constants.FRAMEWORK_STORAGE, getCacheDir().getAbsolutePath()); // Bundles should have the extension classloader as their parent classloader. props.put(Constants.FRAMEWORK_BUNDLE_PARENT, Constants.FRAMEWORK_BUNDLE_PARENT_EXT); // felix specific properties props.put("org.osgi.framework.bootdelegation", MCTProperties.DEFAULT_MCT_PROPERTIES.getProperty("org.osgi.framework.bootdelegation", "")); //props.put("felix.log.level","4"); // Add all system properties that seem to be OSGi property names. for (String key : System.getProperties().stringPropertyNames()) { if (key.startsWith("osgi.") || key.startsWith("org.osgi.")) { props.put(key, System.getProperty(key)); } } Framework framework = null; // Iterate over frameworks on the classpath to see if one matches. See the // Javadoc for org.osgi.framework.launch.FrameworkFactory for information // about using ServiceLoader to find the available framework implementations. for (FrameworkFactory factory : ServiceLoader.load(FrameworkFactory.class)) { framework = factory.newFramework(props); } if (framework == null) { throw new RuntimeException("Cannot find an OSGi framework"); } try { framework.start(); } catch (BundleException e) { throw new RuntimeException("Cannot start OSGi framework", e); } BundleContext bc = framework.getBundleContext(); startOSGIBundles(bc); startPlatformBundles(bc); } public void startPlatformBundles(BundleContext bc) { List<String> platformBundles = getBundleList(new DirectoryBundlesListTracker(), PLATFORM_BUNDLE_SYS_PROPERTY, PLATFORM_BUNDLE_DIR, Collections.<String>emptySet()); assert platformBundles != null && platformBundles.size() > 0; loadBundles(platformBundles,bc); } private void startOSGIBundles(BundleContext bc) { List<String> osgiBundleList = getBundleList(new DirectoryBundlesListTracker(), OSGI_BUNDLE_SYS_PROPERTY, OSGI_BUNDLE_DIR, Collections.<String>emptySet()); loadBundles(osgiBundleList, bc); } private List<String> getBundleList(DirectoryBundlesListTracker bundleListTracker, String bundleListSysProperty, String bundleListPath, Collection<String> excludeBundles) { String propertyVal = MCTProperties.DEFAULT_MCT_PROPERTIES.getProperty(bundleListSysProperty); if (propertyVal != null) { String[] bundles = propertyVal.split("[ \\t]*,[ \\t]*"); for (String bundlePath : bundles) { if (!excludeBundles.contains(bundlePath)) { bundleListTracker.addBundle(bundlePath); } } } List<String> bundlesLoc = bundleListTracker.getBundlesLocation(); if (bundlesLoc == null || bundlesLoc.isEmpty()) { URL bundleDirURL = getClass().getClassLoader().getResource(bundleListPath); if (bundleDirURL == null) { System.err.println("Bundle directory not found, skipped: " + bundleListPath); return Collections.emptyList(); } File bundleDir; try { bundleDir = new File(bundleDirURL.toURI()); } catch (URISyntaxException e) { System.err.println("Error getting path to bundle directory " + bundleListPath); return Collections.emptyList(); } if (!bundleDir.isDirectory()) { System.err.println("Bundle directory path not a directory: " + bundleListPath); return Collections.emptyList(); } File[] bundles = bundleDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".jar"); } }); for (File bundleFile : bundles) { if (!excludeBundles.contains(bundleFile.getName())) { bundleListTracker.addBundle(bundleFile.getAbsolutePath()); } } } return bundleListTracker.getBundlesLocation(); } private void loadBundles(List<String> bundlesList, BundleContext bc) { List<Bundle> bundles = new ArrayList<Bundle>(); for (String bundlePath : bundlesList) { File bundleFile = new File(bundlePath); if (!bundleFile.exists()) { throw new RuntimeException("Plugin path not found: " + bundlePath); } else if (!bundleFile.canRead()) { throw new RuntimeException("Cannot read plugin file: " + bundlePath); } else { Bundle b = loadBundle(bundleFile, bc); if (b != null) { bundles.add(b); } } } startBundles(bundles); } Bundle loadBundle(File bundleFile, BundleContext bc) { String bundleURL = null; try { if (bundleFile.isDirectory()) { bundleURL = "reference:" + bundleFile.toURI().toURL().toExternalForm(); } else { bundleURL = bundleFile.toURI().toURL().toExternalForm(); } } catch (MalformedURLException e) { throw new RuntimeException("Bad path to plugin bundle: " + bundleFile.getAbsolutePath()); } try { Bundle b = bc.installBundle(URLDecoder.decode(bundleURL, "UTF8")); return b; } catch (Exception e) { throw new RuntimeException("Error installing bundle from " + bundleURL, e); } } /** * Starts an ordered list of bundles. * * @param bundles * the list of bundles to start */ private void startBundles(List<Bundle> bundles) { for (Bundle bundle : bundles) { if (!isFragment(bundle)) { try { bundle.start(); } catch (BundleException ex) { throw new RuntimeException("Error starting bundle " + bundle.getLocation(),ex); } } } } private boolean isFragment(Bundle bundle) { return (bundle.getHeaders().get("Fragment-Host") != null); } /** * @param args */ public static void main(String[] args) { // MCT needs certain properties to be specified if (System.getProperty("rwRoot") == null) { System.setProperty("rwRoot", "."); } if (System.getProperty("mct.db.check-schema-version") == null) { System.setProperty("mct.db.check-schema-version", "false"); } if (System.getProperty("disableShiftChangeMonitor") == null) { System.setProperty("disableShiftChangeMonitor", "true"); } new Startup(); } }