changeset 556:517f3d4796af

Fix osgi cache sharing (PR1110). All thermostat commands fire up their own OSGi framework. However, they used to share the OSGi cache location $THERMOSTAT_HOME/osgi by setting the org.osgi.framework.storage config option on framework start-up. Since the cache contains information about installed bundles as well as about the current state of bundles this can be problematic. This patch fixes this by creating a temporary directory in $TERMOSTAT_HOME/osgi-cache which gets deleted once the VM shuts down. Note that the cache is supposed to speed up application-start-up-time. By deleting the osgi cache on VM shutdown we won't have that benefit. Very informal testing didn't show significant speed-ups for me. That being said, we might want to revisit this again if it becomes a problem. The nice thing about the temp directory is that users won't have to specify it on the command-line. I've also added the START_TRANSIENT option to bundle.start() calls so as to avoid auto-starting of bundles. Reviewed-by: vanaltj, neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-August/002836.html PR1110
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 20 Aug 2012 15:29:14 +0200
parents f7f315bd6a53
children 4e9f1b8d4463
files bundles/src/main/java/com/redhat/thermostat/bundles/impl/BundleLoader.java distribution/pom.xml main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java
diffstat 3 files changed, 43 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/impl/BundleLoader.java	Mon Aug 20 18:22:27 2012 +0200
+++ b/bundles/src/main/java/com/redhat/thermostat/bundles/impl/BundleLoader.java	Mon Aug 20 15:29:14 2012 +0200
@@ -81,7 +81,9 @@
             if (printOSGiInfo) {
                 System.out.println("BundleLoader: starting bundle: \"" + bundle.getBundleId() + "\"");
             }
-            bundle.start();
+            // We don't want for the framework to set the auto-start bit. Thus, passing
+            // START_TRANSIENT explicitly
+            bundle.start(Bundle.START_TRANSIENT);
         }
     }
 
--- a/distribution/pom.xml	Mon Aug 20 18:22:27 2012 +0200
+++ b/distribution/pom.xml	Mon Aug 20 15:29:14 2012 +0200
@@ -167,7 +167,7 @@
                 <mkdir dir="${project.build.directory}/agent/logs" />
                 <mkdir dir="${project.build.directory}/agent/run" />
                 <mkdir dir="${project.build.directory}/client" />
-                <mkdir dir="${project.build.directory}/osgi" />
+                <mkdir dir="${project.build.directory}/osgi-cache" />
                 <mkdir dir="${project.build.directory}/libs/native" />
                 
                 <!--  also copy the native libraries -->
--- a/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java	Mon Aug 20 18:22:27 2012 +0200
+++ b/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java	Mon Aug 20 15:29:14 2012 +0200
@@ -43,6 +43,8 @@
 import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
 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;
@@ -51,10 +53,10 @@
 import java.util.Properties;
 import java.util.ServiceLoader;
 
-import org.osgi.framework.launch.FrameworkFactory;
 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.bundles.OSGiRegistryService;
@@ -70,6 +72,8 @@
 
     private boolean printOSGiInfo;
     private String thermostatHome;
+    // The framework cache location; Must not be shared between apps!
+    private Path osgiCacheStorage;
 
     public FrameworkProvider(Configuration config) {
         printOSGiInfo = config.getPrintOSGiInfo();
@@ -139,6 +143,11 @@
                     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);
                 }
@@ -147,15 +156,42 @@
 
     }
 
+    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 thermostatBundleHome = new File(thermostatHome, "osgi");
+        File osgiCacheDir = new File(thermostatHome, "osgi-cache");
 
+        // 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, thermostatBundleHome.getAbsolutePath());
+        bundleConfigurations.put(Constants.FRAMEWORK_STORAGE, osgiCacheStorage.toFile().getAbsolutePath());
         Iterator<FrameworkFactory> factories = loader.iterator();
         if (factories.hasNext()) {
             // we just want the first found