You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2009/09/18 14:51:06 UTC

svn commit: r816609 - in /sling/trunk/installer/osgi/installer/src: main/java/org/apache/sling/osgi/installer/impl/ test/java/org/apache/sling/osgi/installer/impl/

Author: bdelacretaz
Date: Fri Sep 18 12:51:05 2009
New Revision: 816609

URL: http://svn.apache.org/viewvc?rev=816609&view=rev
Log:
SLING-1078 - store bundle digests in a single file

Added:
    sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java   (with props)
    sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java   (with props)
Modified:
    sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java

Added: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java?rev=816609&view=auto
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java (added)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java Fri Sep 18 12:51:05 2009
@@ -0,0 +1,107 @@
+/*
+ * 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.sling.osgi.installer.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.TreeSet;
+
+import org.osgi.service.log.LogService;
+
+/** Store bundle digests in a file, to avoid re-installing
+ *  snapshots needlessly when restarting.
+ */
+class BundleDigestsStorage {
+    private Properties digests = new Properties();
+    private final File dataFile;
+    private final OsgiInstallerContext ctx;
+    
+    /** Load the list from supplied file, which is also
+     *  used by purgeAndSave to save our data
+     */
+    BundleDigestsStorage(OsgiInstallerContext ctx, File dataFile) throws IOException {
+        this.ctx = ctx;
+        this.dataFile = dataFile;
+        InputStream is = null;
+        try {
+            is = new FileInputStream(dataFile);
+            digests.load(is);
+            if(ctx.getLogService() != null) {
+                ctx.getLogService().log(LogService.LOG_INFO, "Digests restored from data file " + dataFile.getName());
+            }
+        } catch(IOException ioe) {
+            if(ctx.getLogService() != null) {
+                ctx.getLogService().log(LogService.LOG_INFO, 
+                        "No digests retrieved, cannot read properties file " + dataFile.getName());
+            }
+        } finally {
+            if(is != null) {
+                is.close();
+            }
+        }
+    }
+    
+    /** Remove digests which do not belong to installed bundles,
+     *  and save our data
+     */
+    void purgeAndSave(TreeSet<String> installedBundlesSymbolicNames) throws IOException {
+        final List<String> toRemove = new ArrayList<String>();
+        for(Object o : digests.keySet()) {
+            final String key = (String)o;
+            if(!installedBundlesSymbolicNames.contains(key)) {
+                toRemove.add(key);
+            }
+        }
+        for(String key : toRemove) {
+            digests.remove(key);
+        }
+        
+        OutputStream os = null;
+        try {
+            os = new FileOutputStream(dataFile);
+            digests.store(os, "Stored by " + getClass().getName());
+        } finally {
+            if(os != null) {
+                os.flush();
+                os.close();
+            }
+        }
+        if(ctx.getLogService() != null) {
+            ctx.getLogService().log(LogService.LOG_INFO, 
+                    "Stored digests of " + digests.size() + " bundles in data file " + dataFile.getName());
+        }
+    }
+    
+    /** Store a bundle digest - not persisted until purgeAndSave is called */
+    void putDigest(String bundleSymbolicName, String digest) {
+        digests.setProperty(bundleSymbolicName, digest);
+    }
+    
+    /** Retrieve digest, null if not found */
+    String getDigest(String bundleSymbolicName) {
+        return digests.getProperty(bundleSymbolicName);
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorage.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java?rev=816609&r1=816608&r2=816609&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java Fri Sep 18 12:51:05 2009
@@ -18,19 +18,14 @@
  */
 package org.apache.sling.osgi.installer.impl;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.util.Collection;
+import java.util.TreeSet;
 
 import org.apache.sling.osgi.installer.InstallableResource;
 import org.apache.sling.osgi.installer.OsgiInstaller;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -48,9 +43,8 @@
     private final ServiceTracker logServiceTracker;
     private final OsgiInstallerThread installerThread;
     private long [] counters = new long[COUNTERS_SIZE];
+    private BundleDigestsStorage bundleDigestsStorage;  
     
-    public static String BUNDLE_DIGEST_PREFIX = "bundle-digest-";
-
     public OsgiInstallerImpl(final BundleContext bc,
                               final PackageAdmin pa,
                               final ServiceTracker logServiceTracker)
@@ -58,15 +52,22 @@
         this.bundleContext = bc;
         this.packageAdmin = pa;
         this.logServiceTracker = logServiceTracker;
+        bundleDigestsStorage = new BundleDigestsStorage(this, bc.getDataFile("bundle-digests.properties"));
         
         installerThread = new OsgiInstallerThread(this);
         installerThread.setDaemon(true);
         installerThread.start();
     }
 
-    public void deactivate() throws InterruptedException {
+    public void deactivate() throws InterruptedException, IOException {
         installerThread.deactivate();
         
+        final TreeSet<String> installedBundlesSymbolicNames = new TreeSet<String>();
+        for(Bundle b : bundleContext.getBundles()) {
+            installedBundlesSymbolicNames.add(b.getSymbolicName());
+        }
+        bundleDigestsStorage.purgeAndSave(installedBundlesSymbolicNames);
+        
         if(getLogService() != null) {
             getLogService().log(LogService.LOG_INFO, "Waiting for installer thread to stop");
         }
@@ -172,35 +173,13 @@
 	}
 
     public String getBundleDigest(Bundle b) throws IOException {
-        // TODO it would be cleaner to use a single file to 
-        // store those digests - and currently digests files
-        // are not purged
-        String result = null;
-        final File f = getBundleDigestFile(b);
-        if(f.exists()) {
-            final FileReader fr = new FileReader(f);
-            try {
-                result = new BufferedReader(fr).readLine();
-            } finally {
-                fr.close();
-            }
+        if(bundleDigestsStorage == null) {
+            return null;
         }
-        return result;
+        return bundleDigestsStorage.getDigest(b.getSymbolicName());
     }
 
     public void saveBundleDigest(Bundle b, String digest) throws IOException {
-        final File f = getBundleDigestFile(b);
-        final FileWriter fw = new FileWriter(f);
-        try {
-            new PrintWriter(fw).write(digest);
-        } finally {
-            fw.close();
-        }
-    }
-    
-    private File getBundleDigestFile(Bundle b) {
-        final String version = (String)b.getHeaders().get(Constants.BUNDLE_VERSION);
-        final String filename = BUNDLE_DIGEST_PREFIX + b.getSymbolicName() + version + ".txt";
-        return bundleContext.getDataFile(filename);
+        bundleDigestsStorage.putDigest(b.getSymbolicName(), digest);
     }
-}
\ No newline at end of file
+ }
\ No newline at end of file

Added: sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java?rev=816609&view=auto
==============================================================================
--- sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java (added)
+++ sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java Fri Sep 18 12:51:05 2009
@@ -0,0 +1,87 @@
+/*
+ * 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.sling.osgi.installer.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.TreeSet;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class BundleDigestsStorageTest {
+    private BundleDigestsStorage storage;
+    private File testFile;
+    private TreeSet<String> installedBundles;
+    
+    @Before
+    public void setUp() throws Exception {
+        testFile = File.createTempFile(getClass().getSimpleName(), "properties");
+        testFile.deleteOnExit();
+        storage = new BundleDigestsStorage(new MockOsgiInstallerContext(), testFile);
+        installedBundles = new TreeSet<String>();
+    }
+    
+    @Test
+    public void testCloseAndReopen() throws IOException {
+        storage.putDigest("foo", "bar");
+        assertEquals("Before save, expecting bar digest", "bar", storage.getDigest("foo"));
+        installedBundles.add("foo");
+        storage.purgeAndSave(installedBundles);
+        assertEquals("After save, expecting bar digest", "bar", storage.getDigest("foo"));
+        storage.putDigest("foo", "wii");
+        assertEquals("After change, expecting wii digest", "wii", storage.getDigest("foo"));
+        storage = null;
+        final BundleDigestsStorage copy = new BundleDigestsStorage(new MockOsgiInstallerContext(), testFile);
+        assertEquals("In copy saved before change, expecting bar digest", "bar", copy.getDigest("foo"));
+    }
+    
+    @Test
+    public void testPurge() throws IOException {
+        for(int i=0; i < 50; i++) {
+            storage.putDigest("foo" + i, "bar" + i);
+            if(i % 2 == 0) {
+                installedBundles.add("foo" + i);
+            }
+        }
+        for(int i=0; i < 50; i++) {
+            assertEquals("Before save, expecting digest to match at step " + i, "bar" + i, storage.getDigest("foo" + i));
+        }
+        storage.purgeAndSave(installedBundles);
+        for(int i=0; i < 50; i++) {
+            if(i % 2 != 0) {
+                assertNull("After purge, expecting null digest at step " + i, storage.getDigest("foo" + i));
+            } else {
+                assertEquals("After purge, expecting digest to match at step " + i, "bar" + i, storage.getDigest("foo" + i));
+            }
+        }
+        storage = null;
+        final BundleDigestsStorage copy = new BundleDigestsStorage(new MockOsgiInstallerContext(), testFile);
+        for(int i=0; i < 50; i++) {
+            if(i % 2 != 0) {
+                assertNull("In copy, expecting null digest at step " + i, copy.getDigest("foo" + i));
+            } else {
+                assertEquals("In copy, expecting digest to match at step " + i, "bar" + i, copy.getDigest("foo" + i));
+            }
+        }
+    }
+ }

Propchange: sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/BundleDigestsStorageTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL