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