Author: bdelacretaz
Date: Fri Aug 14 09:42:59 2009
New Revision: 804142

URL: http://svn.apache.org/viewvc?rev=804142&view=rev
Log:
SLING-1078 - client must supply digest for InstallableResource that wraps an 
InputStream

Added:
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java
      - copied, changed from r804107, 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiController.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
      - copied, changed from r804107, 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
Removed:
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiController.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/InputStreamDigestTest.java
Modified:
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/InstallableResource.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallRemoveTask.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceTest.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/Utilities.java

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/InstallableResource.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/InstallableResource.java?rev=804142&r1=804141&r2=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/InstallableResource.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/InstallableResource.java
 Fri Aug 14 09:42:59 2009
@@ -28,6 +28,7 @@
 public class InstallableResource {
        private final String url;
        private final String extension;
+       private final String digest;
        private final InputStream inputStream;
        private final Dictionary<String, Object> dictionary;
        
@@ -37,22 +38,41 @@
                this.extension = getExtension(url);
                this.inputStream = null;
                this.dictionary = null;
+               this.digest = null;
        }
        
-       /** Create a data object that wraps an InputStream */
-       public InstallableResource(String url, InputStream is) {
+       /** Create a data object that wraps an InputStream 
+        *  @param url unique URL of the supplied data, must start with the 
scheme used 
+        *     {...@link OsgiInstaller#registerResources} call
+        *  @param is the resource contents
+        *  @param digest must be supplied by client. Does not need to be an 
actual digest
+        *     of the contents, but must change if the contents change. Having 
this supplied
+        *     by the client avoids having to compute real digests to find out 
if a resource
+        *     has changed, which can be expensive.        
+        */
+       public InstallableResource(String url, InputStream is, String digest) {
                this.url = url;
                this.extension = getExtension(url);
                this.inputStream = is;
                this.dictionary = null;
+               this.digest = digest;
        }
        
-       /** Create a data object that wraps a Dictionary */
+       /** Create a data object that wraps a Dictionary. Digest will be 
computed
+        *  by the installer in this case, as configuration dictionaries are 
+        *  usually small so computing a real digest to find out if they changed
+        *  is ok.
+        *  
+     *  @param url unique URL of the supplied data, must start with the scheme 
used 
+     *     {...@link OsgiInstaller#registerResources} call
+     *  @param is the resource contents
+        */
        public InstallableResource(String url, Dictionary<String, Object> d) {
                this.url = url;
                this.extension = getExtension(url);
                this.inputStream = null;
                this.dictionary = d;
+        this.digest = null;
        }
 
        @Override
@@ -66,9 +86,9 @@
                return (pos < 0 ? "" : url.substring(pos+1));
        }
        
-       /** Return this data's URL. It is opaque for the {...@link 
OsgiController}
+       /** Return this data's URL. It is opaque for the {...@link 
OsgiInstaller}
         *      but the scheme must be the one used in the 
-        *      {...@link OsgiController#registerResources} call.
+        *      {...@link OsgiInstaller#registerResources} call.
         */
        public String getURL() {
                return url;
@@ -89,4 +109,8 @@
        public Dictionary<String, Object> getDictionary() {
                return dictionary;
        }
+       
+       public String getDigest() {
+           return digest;
+       }
 }

Copied: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java
 (from r804107, 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiController.java)
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java?p2=sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java&p1=sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiController.java&r1=804107&r2=804142&rev=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiController.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java
 Fri Aug 14 09:42:59 2009
@@ -22,21 +22,23 @@
 import java.util.Collection;
 import java.util.Map;
 
-/** Controller that installs/updates/removes InstallableData
- *     in the OSGi framework. The client can register a number of such
- *  resources, and the controller decides based on the resource weights,
- *     bundle version numbers, etc. which ones are actually installed.
+/** OSGi Service that installs/updates/removes InstallableData
+ *     in the OSGi framework. 
+ * 
+ *  The client can register a number of such resources, and the 
+ *  installer decides based on the resource weights, bundle version 
+ *  numbers, etc. which ones are actually installed.
  *
  *     An InstallableResource can be a bundle, a configuration, and later 
  *     we might support deployment packages as well.           
  */
-public interface OsgiController {
+public interface OsgiInstaller {
        
-       /** Provide the controller with the complete list of installable
+       /** Provide the installer with the complete list of installable
         *      resources for a given client.
         * 
-        *      Client must call this at startup and/or when the controller 
-        *      service becomes available. The controller stores the list of
+        *      Client must call this at startup and/or when the installer 
+        *      service becomes available. The installer stores the list of
         *      previously registered/added resources, compares with the new
         *      list and removes resources that have disappeared.
         * 
@@ -46,14 +48,14 @@
         */
        void registerResources(Collection<InstallableResource> data, String 
urlScheme) throws IOException;
        
-       /** Inform the controller that a resource is available for installation.
+       /** Inform the installer that a resource is available for installation.
         *      also called if the resource has been modified since it was 
registered.
         */
        void addResource(InstallableResource d) throws IOException;
        
-       /** Inform the controller that a resource is no longer available */
+       /** Inform the installer that a resource is no longer available */
        void removeResource(InstallableResource d) throws IOException;
        
        /** Return counters used for statistics, console display, testing, etc. 
*/
        Map<String, Long> getCounters();
-}
+}
\ No newline at end of file

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java?rev=804142&r1=804141&r2=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
 Fri Aug 14 09:42:59 2009
@@ -20,7 +20,7 @@
 
 import java.util.Hashtable;
 
-import org.apache.sling.osgi.installer.OsgiController;
+import org.apache.sling.osgi.installer.OsgiInstaller;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
@@ -43,7 +43,7 @@
     private ServiceTracker startLevelTracker;
     private ServiceTracker packageAdminTracker;
     private ServiceTracker logServiceTracker;
-    private OsgiControllerImpl osgiControllerService;
+    private OsgiInstallerImpl osgiControllerService;
     private ServiceRegistration osgiControllerServiceReg;
     
     private static long eventsCount;
@@ -71,11 +71,11 @@
             
             // Assume PackageAdmin is available before this bundle is started.
             // That's the case when using Felix OSGi, not sure about other 
frameworks.
-            this.osgiControllerService = new OsgiControllerImpl(context,
+            this.osgiControllerService = new OsgiInstallerImpl(context,
                     
(PackageAdmin)checkNotNull(this.packageAdminTracker.getService(), 
"PackageAdmin"),
                     logServiceTracker);
             final String [] serviceInterfaces = {
-                    OsgiController.class.getName()
+                    OsgiInstaller.class.getName()
             };
             osgiControllerServiceReg = 
context.registerService(serviceInterfaces, osgiControllerService, props);
         }

Copied: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
 (from r804107, 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java)
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java?p2=sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java&p1=sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java&r1=804107&r2=804142&rev=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
 Fri Aug 14 09:42:59 2009
@@ -24,7 +24,7 @@
 import java.util.Map;
 
 import org.apache.sling.osgi.installer.InstallableResource;
-import org.apache.sling.osgi.installer.OsgiController;
+import org.apache.sling.osgi.installer.OsgiInstaller;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -32,15 +32,15 @@
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.util.tracker.ServiceTracker;
 
-/** OsgiController service */
-public class OsgiControllerImpl implements OsgiController, 
OsgiControllerContext {
+/** OsgiInstaller service implementation */
+public class OsgiInstallerImpl implements OsgiInstaller, OsgiControllerContext 
{
 
        private final BundleContext bundleContext;
     private final PackageAdmin packageAdmin;
     private final ServiceTracker logServiceTracker;
     private Map<String, Long> counters = new HashMap<String, Long>();
 
-    public OsgiControllerImpl(final BundleContext bc,
+    public OsgiInstallerImpl(final BundleContext bc,
                               final PackageAdmin pa,
                               final ServiceTracker logServiceTracker)
     throws IOException {
@@ -52,7 +52,7 @@
     public void deactivate() {
         if(getLogService() != null) {
             getLogService().log(LogService.LOG_WARNING,
-                    OsgiController.class.getName()
+                    OsgiInstaller.class.getName()
                     + " service deactivated - this warning can be ignored if 
system is shutting down");
         }
     }

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java?rev=804142&r1=804141&r2=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java
 Fri Aug 14 09:42:59 2009
@@ -31,8 +31,12 @@
 import java.math.BigInteger;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
@@ -58,6 +62,8 @@
        public RegisteredResource(BundleContext ctx, InstallableResource input) 
throws IOException {
                url = input.getUrl();
                
+               // TODO if input.url ends with a "config" extension, convert to 
dictionary
+               
                try {
                        if(input.getDictionary() == null) {
                                dictionary = null;
@@ -65,12 +71,16 @@
                                        throw new 
IllegalArgumentException("input provides no Dictionary and no InputStream:" + 
input);
                                } else {
                                        dataFile = getDataFile(ctx);
-                                       digest = 
copyToLocalStorage(input.getInputStream(), dataFile);
+                                       
copyToLocalStorage(input.getInputStream(), dataFile);
+                                       digest = input.getDigest();
+                                       if(digest == null || digest.length() == 
0) {
+                                           throw new IllegalArgumentException(
+                                                   "Digest must be supplied 
for an InstallableResource that wraps an InputStream");
+                                       }
                                }
                        } else {
-                               // TODO Copy dictionary
                                dataFile = null;
-                               dictionary = input.getDictionary();
+                               dictionary = copy(input.getDictionary());
                                digest = computeDigest(dictionary);
                        }
                        
@@ -135,16 +145,14 @@
         return new String(bigInt.toString(16));
     }
     
-    /** Copy data to local storage and return digest */
-       private String copyToLocalStorage(InputStream data, File f) throws 
IOException, NoSuchAlgorithmException {
-        final MessageDigest d = MessageDigest.getInstance(DIGEST_TYPE);
+    /** Copy data to local storage */
+       private void copyToLocalStorage(InputStream data, File f) throws 
IOException, NoSuchAlgorithmException {
                final OutputStream os = new BufferedOutputStream(new 
FileOutputStream(f));
                try {
                        final byte[] buffer = new byte[16384];
                        int count = 0;
                        while( (count = data.read(buffer, 0, buffer.length)) > 
0) {
                                os.write(buffer, 0, count);
-                               d.update(buffer, 0, count);
                        }
                        os.flush();
                } finally {
@@ -152,7 +160,6 @@
                                os.close();
                        }
                }
-               return digestToString(d);
        }
        
        /** Convert InputStream to Dictionary using our extended properties 
format,
@@ -169,4 +176,19 @@
         }
         return result;
        }
+       
+       /** Copy given Dictionary, sorting keys */
+       static Dictionary<String, Object> copy(Dictionary<String, Object> d) {
+           final Dictionary<String, Object> result = new Hashtable<String, 
Object>();
+           final List<String> keys = new ArrayList<String>();
+           final Enumeration<String> e = d.keys();
+           while(e.hasMoreElements()) {
+               keys.add(e.nextElement());
+           }
+           Collections.sort(keys);
+           for(String key : keys) {
+               result.put(key, d.get(key));
+           }
+           return result;
+       }
 }

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallRemoveTask.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallRemoveTask.java?rev=804142&r1=804141&r2=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallRemoveTask.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallRemoveTask.java
 Fri Aug 14 09:42:59 2009
@@ -24,7 +24,7 @@
 import java.util.jar.Manifest;
 
 import org.apache.sling.osgi.installer.impl.OsgiControllerContext;
-import org.apache.sling.osgi.installer.impl.OsgiControllerImpl;
+import org.apache.sling.osgi.installer.impl.OsgiInstallerImpl;
 import org.apache.sling.osgi.installer.impl.RegisteredResource;
 import org.apache.sling.osgi.installer.impl.Storage;
 import org.osgi.framework.Bundle;

Modified: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceTest.java?rev=804142&r1=804141&r2=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceTest.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceTest.java
 Fri Aug 14 09:42:59 2009
@@ -20,11 +20,13 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.ByteArrayInputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Hashtable;
 
 import org.apache.sling.osgi.installer.InstallableResource;
 
@@ -49,7 +51,7 @@
                }
                
                final TestInputStream t = new TestInputStream(new 
ByteArrayInputStream(data.getBytes()));
-               final InstallableResource ir = new InstallableResource(data, t);
+               final InstallableResource ir = new InstallableResource(data, t, 
"somedigest");
                assertEquals("TestInputStream must not be closed before test", 
0, t.closeCount);
                new LocalFileRegisteredResource(ir);
                assertEquals("TestInputStream must be closed by 
RegisteredResource", 1, t.closeCount);
@@ -58,9 +60,42 @@
        @org.junit.Test public void testLocalFileCopy() throws Exception {
                final String data = "This is some data";
                final InputStream in = new 
ByteArrayInputStream(data.getBytes());
-               final LocalFileRegisteredResource r = new 
LocalFileRegisteredResource(new InstallableResource(data, in));
+               final LocalFileRegisteredResource r = new 
LocalFileRegisteredResource(new InstallableResource(data, in, "somedigest"));
                assertTrue("Local file exists", r.getDataFile(null).exists());
                assertEquals("Local file length matches our data", 
data.getBytes().length, r.getDataFile(null).length());
        }
        
-}
+    @org.junit.Test public void testMissingDigest() throws Exception {
+        final String data = "This is some data";
+        final InputStream in = new ByteArrayInputStream(data.getBytes());
+        try {
+            new LocalFileRegisteredResource(new InstallableResource(data, in, 
null));
+            fail("Expected an IllegalArgumentException as digest is null");
+        } catch(IllegalArgumentException asExpected) {
+        }
+    }
+    
+    @org.junit.Test public void testDictionaryDigestOutOfOrderData() throws 
Exception {
+        final Hashtable<String, Object> d1 = new Hashtable<String, Object>();
+        final Hashtable<String, Object> d2 = new Hashtable<String, Object>();
+        
+        final String [] keys = { "foo", "bar", "something" };
+        for(int i=0 ; i < keys.length; i++) {
+            d1.put(keys[i], keys[i] + "." + keys[i]);
+        }
+        for(int i=keys.length - 1 ; i >= 0; i--) {
+            d2.put(keys[i], keys[i] + "." + keys[i]);
+        }
+        
+        final RegisteredResource r1 = new RegisteredResource(null, new 
InstallableResource("url1", d1));
+        final RegisteredResource r2 = new RegisteredResource(null, new 
InstallableResource("url1", d2));
+        
+        assertEquals(
+                "Two RegisteredResource with same values but different key 
orderings must have the same key", 
+                r1.getDigest(),
+                r2.getDigest()
+        );
+        
+        // TODO do the same test starting with an InputStream, for configs
+    }
+}
\ No newline at end of file

Modified: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/Utilities.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/Utilities.java?rev=804142&r1=804141&r2=804142&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/Utilities.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/Utilities.java
 Fri Aug 14 09:42:59 2009
@@ -30,7 +30,7 @@
         return result;
     }
     
-    static void setStorage(OsgiControllerImpl c, Storage s) throws Exception {
+    static void setStorage(OsgiInstallerImpl c, Storage s) throws Exception {
         final Field f = c.getClass().getDeclaredField("storage");
         f.setAccessible(true);
         f.set(c, s);


Reply via email to