Mercurial > hg > release > thermostat-1.2
view main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java @ 1660:c6ae78b6f3ac
[Thermostat 1.2] Update copyright year to 2015
Reviewed-by: omajid
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-March/013127.html
PR2273
author | Severin Gehwolf <sgehwolf@redhat.com> |
---|---|
date | Wed, 11 Mar 2015 15:07:27 +0100 |
parents | f2dcec9f38e1 |
children |
line wrap: on
line source
/* * Copyright 2012-2015 Red Hat, Inc. * * This file is part of Thermostat. * * Thermostat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * Thermostat is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thermostat; see the file COPYING. If not see * <http://www.gnu.org/licenses/>. * * Linking this code with other modules is making a combined work * based on this code. Thus, the terms and conditions of the GNU * General Public License cover the whole combination. * * As a special exception, the copyright holders of this code give * you permission to link this code with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also * meet, for each linked independent module, the terms and conditions * of the license of that module. An independent module is a module * which is not derived from or based on this code. If you modify * this code, you may extend this exception to your version of the * library, but you are not obligated to do so. If you do not wish * to do so, delete this exception statement from your version. */ package com.redhat.thermostat.main.impl; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.ServiceLoader; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.launch.Framework; import org.osgi.framework.launch.FrameworkFactory; import org.osgi.util.tracker.ServiceTracker; import com.redhat.thermostat.launcher.BundleManager; import com.redhat.thermostat.launcher.Launcher; import com.redhat.thermostat.shared.config.CommonPaths; public class FrameworkProvider { private static final String DEBUG_PREFIX = "FrameworkProvider: "; private static final String PROPS_FILE = "/com/redhat/thermostat/main/impl/bootstrapbundles.properties"; private static final String BUNDLELIST = "bundles"; private CommonPaths paths; private boolean printOSGiInfo; private boolean ignoreBundleVersions; private String bootDelegation; // The framework cache location; Must not be shared between apps! private Path osgiCacheStorage; public FrameworkProvider(CommonPaths paths, boolean printOSGiInfo, boolean ignoreBundleVersions, String bootDelegation) { this.paths = paths; this.printOSGiInfo = printOSGiInfo; this.ignoreBundleVersions = ignoreBundleVersions; this.bootDelegation = bootDelegation; if ("".equals(bootDelegation)) { throw new RuntimeException("Unexpected string used with boot delegation: '" + bootDelegation + "'"); } } // This is our ticket into OSGi land. Unfortunately, we to use a bit of reflection here. // The launcher and bundleloader are instantiated from within their bundles, ie loaded // by the bundle classloader. public void start(String[] args) { try { Framework framework = makeFramework(); prepareFramework(framework); loadBootstrapBundles(framework); setLoaderVerbosity(framework); setIgnoreBundleVersions(framework); runLauncher(framework, args); } catch (InterruptedException | BundleException | IOException e) { throw new RuntimeException("Could not start framework.", e); } } private String getOSGiPublicPackages() throws FileNotFoundException, IOException { File osgiBundleDefinitions = new File(paths.getSystemConfigurationDirectory(), "osgi-export.properties"); Properties bundles = new Properties(); bundles.load(new FileInputStream(osgiBundleDefinitions)); StringBuilder publicPackages = new StringBuilder(); /* * Packages the launcher requires */ //publicPackages.append("com.redhat.thermostat.common.services"); boolean firstPackage = true; for (Object bundle : bundles.keySet()) { if (!firstPackage) { publicPackages.append(",\n"); } firstPackage = false; publicPackages.append(bundle); String bundleVersion = (String) bundles.get(bundle); if (!bundleVersion.isEmpty()) { publicPackages.append("; version=").append(bundleVersion); } } return publicPackages.toString(); } private void prepareFramework(final Framework framework) throws BundleException, IOException { framework.init(); framework.start(); if (printOSGiInfo) { System.out.println(DEBUG_PREFIX + "OSGi framework has started."); } Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { framework.stop(); framework.waitForStop(0); if (printOSGiInfo) { System.out.println(DEBUG_PREFIX + "OSGi framework has shut down."); } recursivelyDeleteDirectory(osgiCacheStorage.toFile()); if (printOSGiInfo) { System.out.println(DEBUG_PREFIX + "Removed OSGi cache directory: " + osgiCacheStorage.toFile().getAbsolutePath()); } } catch (Exception e) { throw new RuntimeException("Error shutting down framework.", e); } } }); } private void recursivelyDeleteDirectory(File directory) { for (File file: directory.listFiles()) { if (file.isDirectory()) { recursivelyDeleteDirectory(file); } file.delete(); } directory.delete(); } private Framework makeFramework() throws FileNotFoundException, IOException { File osgiCacheDir = new File(paths.getUserCacheDirectory(), "osgi-cache"); if (!osgiCacheDir.isDirectory() && !osgiCacheDir.mkdirs()) { throw new RuntimeException("Unable to create " + osgiCacheDir); } // Create temporary directory which will be used as cache for OSGi bundles. See // http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/Constants.html#FRAMEWORK_STORAGE // for details about what this location is used for. // // Agent, swing gui client application must not use the same location as this tricks the framework // into thinking that some bundles are installed and loaded when that might not actually be the case. // Note that we do not specify the org.osgi.framework.storage.clean property and the default is to NOT // clean the cache, which is when we might run into trouble if this location is shared. This // temp directory will be deleted on VM shutdown. // // This fixes Thermostat BZ 1110. osgiCacheStorage = Files.createTempDirectory(osgiCacheDir.toPath(), null); if (printOSGiInfo) { System.out.println(DEBUG_PREFIX + "OSGi cache location: " + osgiCacheStorage.toFile().getAbsolutePath()); } ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class, getClass().getClassLoader()); Map<String, String> bundleConfigurations = new HashMap<String, String>(); String extraPackages = getOSGiPublicPackages(); bundleConfigurations.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, extraPackages); bundleConfigurations.put(Constants.FRAMEWORK_STORAGE, osgiCacheStorage.toFile().getAbsolutePath()); if (bootDelegation != null) { if (printOSGiInfo) { System.out.println("Boot delegation: " + bootDelegation); } bundleConfigurations.put(Constants.FRAMEWORK_BOOTDELEGATION, bootDelegation); } Iterator<FrameworkFactory> factories = loader.iterator(); if (factories.hasNext()) { // we just want the first found return factories.next().newFramework(bundleConfigurations); } else { throw new InternalError("ServiceLoader cannot find a FrameworkFactory!"); } } private void loadBootstrapBundles(Framework framework) throws BundleException, InterruptedException { Properties bootstrapProps = new Properties(); // the properties file should be in the same package as this class InputStream res = getClass().getResourceAsStream(PROPS_FILE); if (res != null) { try { bootstrapProps.load(res); } catch (IOException e) { throw new RuntimeException("Could not load bootstrap bundle properties.", e); } } String[] bundles = bootstrapProps.getProperty(BUNDLELIST).split(","); List<String> locations = new ArrayList<>(); for (String bundle : bundles) { String trimmed = bundle.trim(); if (trimmed != null && trimmed.length() > 0) { String location = actualLocation(trimmed); locations.add(location); } } BundleManager.preLoadBundles(framework, locations, printOSGiInfo); } private void setLoaderVerbosity(Framework framework) throws InterruptedException { Object loader = getService(framework, BundleManager.class.getName()); callVoidReflectedMethod(loader, "setPrintOSGiInfo", printOSGiInfo); } private void setIgnoreBundleVersions(Framework framework) throws InterruptedException { Object loader = getService(framework, BundleManager.class.getName()); callVoidReflectedMethod(loader, "setIgnoreBundleVersions", ignoreBundleVersions); } private void runLauncher(Framework framework, String[] args) throws InterruptedException { Object launcher = getService(framework, Launcher.class.getName()); callVoidReflectedMethod(launcher, "run", args, false); } private Object getService(Framework framework, String name) throws InterruptedException { Object service = null; @SuppressWarnings({ "unchecked", "rawtypes" }) ServiceTracker tracker = new ServiceTracker(framework.getBundleContext(), name, null); tracker.open(); service = tracker.waitForService(0); tracker.close(); return service; } /** * Call {@code object}.{@code name} with {@code args} as the arguments. The * return value is ignored. The types of the method arguments must exactly * match the types of the supplied arguments, but primitives are used unboxed. */ private void callVoidReflectedMethod(Object object, String name, Object... args) { Class<?> clazz = object.getClass(); Class<?>[] classes = new Class<?>[args.length]; for (int i = 0; i < args.length; i++) { classes[i] = preferPrimitiveClass(args[i].getClass()); } try { Method m = clazz.getMethod(name, classes); m.invoke(object, args); } catch (ReflectiveOperationException e) { throw new AssertionError("Unable to call '" + name + "' method on object " + object, e); } } private static <T> Class<T> preferPrimitiveClass(Class<T> boxedPrimitive) { HashMap<Class<?>, Class<?>> map = new HashMap<>(); map.put(Byte.class, byte.class); map.put(Short.class, short.class); map.put(Integer.class, int.class); map.put(Long.class, long.class); map.put(Float.class, float.class); map.put(Double.class, double.class); map.put(Boolean.class, boolean.class); map.put(Character.class, char.class); if (map.containsKey(boxedPrimitive)) { return (Class<T>) map.get(boxedPrimitive); } else { return boxedPrimitive; } } // Resolve symlinks completely; This makes the behaviour of this class // consistent with BundleManagerImpl and avoid problems where two different // files across bootstrap and later code provide the same bundle symbolic // name version private String actualLocation(String resourceName) { File file = new File(paths.getSystemLibRoot(), resourceName); try { return file.getCanonicalFile().toURI().toString(); } catch (IOException e) { // okay, lets not canonicalize the path return file.toURI().toString(); } } }