Author: cziegeler
Date: Mon Aug 23 17:19:28 2010
New Revision: 988214

URL: http://svn.apache.org/viewvc?rev=988214&view=rev
Log:
SLING-1560 : InstallabeResource should just be a data object

Added:
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
   (contents, props changed)
      - copied, changed from r987481, 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerThread.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java
   (with props)
Removed:
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerThread.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/InstallableResourceTest.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/LocalFileRegisteredResource.java
Modified:
    
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/ConfigNodeConverter.java
    
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/OsgiInstallerTask.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java
    
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/DictionaryDigestTest.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceComparatorTest.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/TaskOrderingTest.java
    
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/MockBundleTaskCreator.java

Modified: 
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/ConfigNodeConverter.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/ConfigNodeConverter.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/ConfigNodeConverter.java
 (original)
+++ 
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/ConfigNodeConverter.java
 Mon Aug 23 17:19:28 2010
@@ -18,9 +18,16 @@
  */
 package org.apache.sling.jcr.jcrinstall.impl;
 
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
 import java.lang.reflect.Array;
+import java.math.BigInteger;
+import java.security.MessageDigest;
 import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import javax.jcr.Node;
 import javax.jcr.Property;
@@ -49,7 +56,8 @@ class ConfigNodeConverter implements Jcr
 
                // We only consider CONFIG_NODE_TYPE nodes
                if(n.isNodeType(CONFIG_NODE_TYPE)) {
-                       result = new InstallableResource(n.getPath(), null, 
load(n), null, null, priority);
+                   final Dictionary<String, Object> dict = load(n);
+                       result = new InstallableResource(n.getPath(), null, 
dict, computeDigest(dict), null, priority);
                        log.debug("Converted node {} to {}", n.getPath(), 
result);
                } else {
                        log.debug("Node is not a {} node, ignored:{}", 
CONFIG_NODE_TYPE, n.getPath());
@@ -120,4 +128,37 @@ class ConfigNodeConverter implements Jcr
         log.debug("Value of type {} ignored", v.getType());
         return null;
     }
+
+    /** convert digest to readable string 
(http://www.javalobby.org/java/forums/t84420.html) */
+    private static String digestToString(MessageDigest d) {
+        final BigInteger bigInt = new BigInteger(1, d.digest());
+        return new String(bigInt.toString(16));
+    }
+
+    /** Digest is needed to detect changes in data, and must not depend on 
dictionary ordering */
+    private static String computeDigest(Dictionary<String, Object> data) {
+        try {
+            final MessageDigest d = MessageDigest.getInstance("MD5");
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            final ObjectOutputStream oos = new ObjectOutputStream(bos);
+
+            final SortedSet<String> sortedKeys = new TreeSet<String>();
+            if(data != null) {
+                for(Enumeration<String> e = data.keys(); e.hasMoreElements(); 
) {
+                    final String key = e.nextElement();
+                    sortedKeys.add(key);
+                }
+            }
+            for(String key : sortedKeys) {
+                oos.writeObject(key);
+                oos.writeObject(data.get(key));
+            }
+
+            bos.flush();
+            d.update(bos.toByteArray());
+            return digestToString(d);
+        } catch (Exception ignore) {
+            return data.toString();
+        }
+    }
 }
\ No newline at end of file

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=988214&r1=988213&r2=988214&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
 Mon Aug 23 17:19:28 2010
@@ -18,27 +18,20 @@
  */
 package org.apache.sling.osgi.installer;
 
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.io.InputStream;
-import java.io.ObjectOutputStream;
-import java.math.BigInteger;
-import java.security.MessageDigest;
 import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Properties;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import org.apache.felix.cm.file.ConfigurationHandler;
 
 
 /**
  * A piece of data that can be installed by the {...@link OsgiInstaller}
  * Currently the OSGi installer supports bundles and configurations.
  *
+ * The installable resource contains as much information as the client
+ * can provide. An input stream or dictionary is mandatory everything
+ * else is optional. All optional values will be tried to be evaluated
+ * by the OSGi installer. If such evaluation fails the resource will
+ * be ignore during installation.
+ *
  */
 public class InstallableResource {
 
@@ -74,13 +67,21 @@ public class InstallableResource {
     /**
      * Create a data object - this is a simple constructor just using the
      * values as they are provided.
+     * @param id Unique id for the resource, For auto detection if the resource
+     *           type, the id should contain an extension like .jar, .cfg etc.
+     * @param is The input stream to the data or
+     * @param dict A dictionary with data
+     * @param digest A digest of the data
+     * @param type The resource type if known
+     * @param priority Optional priority - if not specified {...@link 
#DEFAULT_PRIORITY}
+     *                 is used
      * @throws IllegalArgumentException if something is wrong
      */
     public InstallableResource(final String id,
-            InputStream is,
-            Dictionary<String, Object> dict,
-            String digest,
-            String type,
+            final InputStream is,
+            final Dictionary<String, Object> dict,
+            final String digest,
+            final String type,
             final Integer priority) {
         if ( id == null ) {
             throw new IllegalArgumentException("id must not be null.");
@@ -90,26 +91,6 @@ public class InstallableResource {
             if ( dict == null ) {
                 throw new IllegalArgumentException("dictionary must not be 
null (or input stream must not be null).");
             }
-            type = (type != null ? type : InstallableResource.TYPE_CONFIG);
-        }
-        final String resourceType = (type != null ? type : 
computeResourceType(getExtension(id)));
-        if ( resourceType == null ) {
-            throw new IllegalArgumentException("Resource type must not be 
null");
-        }
-        if ( is != null && resourceType.equals(InstallableResource.TYPE_CONFIG 
) ) {
-            dict = readDictionary(is, getExtension(id));
-            if ( dict == null ) {
-                throw new IllegalArgumentException("Unable to read dictionary 
from input stream: " + id);
-            }
-            is = null;
-        }
-        if ( resourceType.equals(InstallableResource.TYPE_CONFIG) ) {
-            digest = (digest != null ? digest : id + ":" + 
computeDigest(dict));
-        }
-
-        // TODO - compute digest if digest is null - for now we throw
-        if ( digest == null || digest.length() == 0 ) {
-            throw new IllegalArgumentException("digest must not be null");
         }
 
         this.id = id;
@@ -117,7 +98,7 @@ public class InstallableResource {
         this.dictionary = dict;
         this.digest = digest;
         this.priority = (priority != null ? priority : DEFAULT_PRIORITY);
-        this.resourceType = resourceType;
+        this.resourceType = type;
     }
 
     /**
@@ -131,7 +112,7 @@ public class InstallableResource {
 
     /**
      * Return the type of this resource.
-     * @return The resource type.
+     * @return The resource type or <code>null</code> if the type is unnown 
for the client.
      */
     public String getType() {
         return this.resourceType;
@@ -163,6 +144,7 @@ public class InstallableResource {
     /**
      * Return this resource's digest. Not necessarily an actual md5 or other 
digest of the
      * data, can be any string that changes if the data changes.
+     * @return The digest or null
      */
     public String getDigest() {
         return this.digest;
@@ -181,109 +163,4 @@ public class InstallableResource {
     public String toString() {
         return getClass().getSimpleName() + ", priority=" + priority + ", id=" 
+ id;
     }
-
-    /**
-     * Compute the extension
-     */
-    private static String getExtension(String url) {
-        final int pos = url.lastIndexOf('.');
-        return (pos < 0 ? "" : url.substring(pos+1));
-    }
-
-    /**
-     * Compute the resource type
-     */
-    private static String computeResourceType(String extension) {
-        if (extension.equals("jar")) {
-            return InstallableResource.TYPE_BUNDLE;
-        }
-        if ( extension.equals("cfg")
-             || extension.equals("config")
-             || extension.equals("xml")
-             || extension.equals("properties")) {
-            return InstallableResource.TYPE_CONFIG;
-        }
-        return extension;
-    }
-
-    /** convert digest to readable string 
(http://www.javalobby.org/java/forums/t84420.html) */
-    private static String digestToString(MessageDigest d) {
-        final BigInteger bigInt = new BigInteger(1, d.digest());
-        return new String(bigInt.toString(16));
-    }
-
-    /** Digest is needed to detect changes in data, and must not depend on 
dictionary ordering */
-    private static String computeDigest(Dictionary<String, Object> data) {
-        try {
-            final MessageDigest d = MessageDigest.getInstance("MD5");
-            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-            final ObjectOutputStream oos = new ObjectOutputStream(bos);
-
-            final SortedSet<String> sortedKeys = new TreeSet<String>();
-            if(data != null) {
-                for(Enumeration<String> e = data.keys(); e.hasMoreElements(); 
) {
-                    final String key = e.nextElement();
-                    sortedKeys.add(key);
-                }
-            }
-            for(String key : sortedKeys) {
-                oos.writeObject(key);
-                oos.writeObject(data.get(key));
-            }
-
-            bos.flush();
-            d.update(bos.toByteArray());
-            return digestToString(d);
-        } catch (Exception ignore) {
-            return data.toString();
-        }
-    }
-
-    /**
-     * Read dictionary from an input stream.
-     * We use the same logic as Apache Felix FileInstall here:
-     * - *.cfg files are treated as property files
-     * - *.config files are handled by the Apache Felix ConfigAdmin file reader
-     * @param is
-     * @param extension
-     * @return
-     * @throws IOException
-     */
-    private static Dictionary<String, Object> readDictionary(
-            final InputStream is, final String extension) {
-        final Hashtable<String, Object> ht = new Hashtable<String, Object>();
-        final InputStream in = new BufferedInputStream(is);
-        try {
-            if ( !extension.equals("config") ) {
-                final Properties p = new Properties();
-                in.mark(1);
-                boolean isXml = in.read() == '<';
-                in.reset();
-                if (isXml) {
-                    p.loadFromXML(in);
-                } else {
-                    p.load(in);
-                }
-                final Enumeration<Object> i = p.keys();
-                while ( i.hasMoreElements() ) {
-                    final Object key = i.nextElement();
-                    ht.put(key.toString(), p.get(key));
-                }
-            } else {
-                @SuppressWarnings("unchecked")
-                final Dictionary<String, Object> config = 
ConfigurationHandler.read(in);
-                final Enumeration<String> i = config.keys();
-                while ( i.hasMoreElements() ) {
-                    final String key = i.nextElement();
-                    ht.put(key, config.get(key));
-                }
-            }
-        } catch ( IOException ignore ) {
-            return null;
-        } finally {
-            try { in.close(); } catch (IOException ignore) {}
-        }
-
-        return ht;
-    }
 }

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=988214&r1=988213&r2=988214&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
 Mon Aug 23 17:19:28 2010
@@ -39,7 +39,7 @@ public class Activator implements Bundle
     /** Vendor of all registered services. */
     private static final String VENDOR = "The Apache Software Foundation";
 
-    private OsgiInstallerThread osgiControllerService;
+    private OsgiInstallerImpl osgiControllerService;
     private ServiceRegistration osgiControllerServiceReg;
 
     /** Tracker for the log service. */
@@ -59,7 +59,7 @@ public class Activator implements Bundle
         props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Install 
Controller Service");
         props.put(Constants.SERVICE_VENDOR, VENDOR);
 
-        this.osgiControllerService = new OsgiInstallerThread(context);
+        this.osgiControllerService = new OsgiInstallerImpl(context);
         this.osgiControllerService.setDaemon(true);
         this.osgiControllerService.start();
         final String [] serviceInterfaces = {

Copied: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
 (from r987481, 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerThread.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/OsgiInstallerThread.java&r1=987481&r2=988214&rev=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerThread.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
 Mon Aug 23 17:19:28 2010
@@ -49,7 +49,7 @@ import org.osgi.framework.FrameworkListe
  *  that are updated or removed during a cycle, and merged with
  *  the main list at the end of the cycle.
  */
-public class OsgiInstallerThread
+public class OsgiInstallerImpl
     extends Thread
     implements BundleListener, FrameworkListener,
                OsgiInstaller {
@@ -70,7 +70,7 @@ public class OsgiInstallerThread
     private final BundleTaskCreator bundleTaskCreator;
     private final ConfigTaskCreator configTaskCreator;
 
-    OsgiInstallerThread(final BundleContext ctx) {
+    OsgiInstallerImpl(final BundleContext ctx) {
         this.ctx = ctx;
         // listen to framework and bundle events
         this.ctx.addFrameworkListener(this);
@@ -168,7 +168,7 @@ public class OsgiInstallerThread
         checkScheme(scheme);
         RegisteredResource rr = null;
         try {
-            rr = new RegisteredResourceImpl(ctx, r, scheme);
+            rr = RegisteredResourceImpl.create(ctx, r, scheme);
         } catch(IOException ioe) {
             Logger.logWarn("Cannot create RegisteredResource (resource will be 
ignored):" + r, ioe);
             return;
@@ -190,7 +190,7 @@ public class OsgiInstallerThread
         for(InstallableResource r : data) {
             RegisteredResource rr =  null;
             try {
-                rr = new RegisteredResourceImpl(ctx, r, scheme);
+                rr = RegisteredResourceImpl.create(ctx, r, scheme);
             } catch(IOException ioe) {
                 Logger.logWarn("Cannot create RegisteredResource (resource 
will be ignored):" + r, ioe);
                 continue;

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

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

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java
 Mon Aug 23 17:19:28 2010
@@ -19,7 +19,7 @@
 package org.apache.sling.osgi.installer.impl;
 
 
-/** Base class for tasks that can be executed by the {...@link 
OsgiInstallerThread} */
+/** Base class for tasks that can be executed by the {...@link 
OsgiInstallerImpl} */
 public abstract class OsgiInstallerTask implements 
Comparable<OsgiInstallerTask> {
 
     public abstract void execute(OsgiInstallerContext ctx);

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java
 Mon Aug 23 17:19:28 2010
@@ -20,21 +20,29 @@ package org.apache.sling.osgi.installer.
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.MessageDigest;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 
+import org.apache.felix.cm.file.ConfigurationHandler;
 import org.apache.sling.osgi.installer.InstallableResource;
 import org.apache.sling.osgi.installer.impl.config.ConfigurationPid;
 import org.osgi.framework.BundleContext;
@@ -65,44 +73,90 @@ public class RegisteredResourceImpl
 
     private final String resourceType;
 
+    /**
+     * Try to create a registered resource.
+     */
+    public static RegisteredResourceImpl create(final BundleContext ctx,
+            final InstallableResource input,
+            final String scheme) throws IOException {
+        // installable resource has an id, a priority and either
+        // an input stream or a dictionary
+        InputStream is = input.getInputStream();
+        Dictionary<String, Object> dict = input.getDictionary();
+        String type = input.getType();
+        if ( is == null ) {
+            // if input stream is null, config through dictionary is expected!
+            type = (type != null ? type : InstallableResource.TYPE_CONFIG);
+        }
+        final String resourceType = (type != null ? type : 
computeResourceType(getExtension(input.getId())));
+        if ( resourceType == null ) {
+            // unknown resource type
+            throw new IOException("Unknown resource type for resource " + 
input.getId());
+        }
+        if ( !resourceType.equals(InstallableResource.TYPE_CONFIG) && 
!resourceType.equals(InstallableResource.TYPE_BUNDLE) ) {
+            throw new IOException("Unsupported resource type " + resourceType 
+ " for resource " + input.getId());
+        }
+        if ( is != null && resourceType.equals(InstallableResource.TYPE_CONFIG 
) ) {
+            dict = readDictionary(is, getExtension(input.getId()));
+            if ( dict == null ) {
+                throw new IOException("Unable to read dictionary from input 
stream: " + input.getId());
+            }
+            is = null;
+        }
+
+        return new RegisteredResourceImpl(ctx,
+                input.getId(),
+                is,
+                dict,
+                resourceType,
+                input.getDigest(),
+                input.getPriority(),
+                scheme);
+    }
+
        /**
         * Create a RegisteredResource from given data.
-        * As this data object is filled from an {...@link InstallableResource}
+        * As this data object is filled from an {...@link 
#create(BundleContext, InstallableResource, String)}
         * we don't have to validate values - this has already been done
-        * by the installable resource!
+        * The only exception is the digest!
         */
-       public RegisteredResourceImpl(final BundleContext ctx,
-               final InstallableResource input,
+       private RegisteredResourceImpl(final BundleContext ctx,
+               final String id,
+               final InputStream is,
+               final Dictionary<String, Object> dict,
+               final String type,
+               final String digest,
+               final int priority,
                final String scheme) throws IOException {
-        this.id = input.getId();
+        this.id = id;
         this.urlScheme = scheme;
-               this.resourceType = input.getType();
-               this.priority = input.getPriority();
-        this.dictionary = copy(input.getDictionary());
-        this.digest = input.getDigest();
+               this.resourceType = type;
+               this.priority = priority;
+        this.dictionary = copy(dict);
                this.serialNumber = getNextSerialNumber();
 
                if (resourceType.equals(InstallableResource.TYPE_BUNDLE)) {
-                   final InputStream is = input.getInputStream();
             try {
                 this.dataFile = getDataFile(ctx);
                 Logger.logDebug("Copying data to local storage " + 
this.dataFile);
-                copyToLocalStorage(input.getInputStream());
+                copyToLocalStorage(is);
                 setAttributesFromManifest();
                 final String name = 
(String)attributes.get(Constants.BUNDLE_SYMBOLICNAME);
                 if (name == null) {
                     // not a bundle
                     throw new IOException("Bundle resource does not contain a 
bundle " + this.urlScheme + ":" + this.id);
                 }
+                this.digest = (digest != null && digest.length() > 0 ? digest 
: id + ":" + computeDigest(this.dataFile));
                 entity = ENTITY_BUNDLE_PREFIX + name;
             } finally {
                 is.close();
             }
                } else if ( 
resourceType.equals(InstallableResource.TYPE_CONFIG)) {
             this.dataFile = null;
-            final ConfigurationPid pid = new ConfigurationPid(scheme + ':' + 
input.getId());
+            final ConfigurationPid pid = new ConfigurationPid(scheme + ':' + 
id);
             entity = ENTITY_CONFIG_PREFIX + pid.getCompositePid();
             attributes.put(CONFIG_PID_ATTRIBUTE, pid);
+            this.digest = (digest != null && digest.length() > 0 ? digest : id 
+ ":" + computeDigest(dict));
                } else {
                    throw new IOException("Unknown type " + resourceType);
                }
@@ -393,4 +447,132 @@ public class RegisteredResourceImpl
 
         return result;
     }
+
+    /**
+     * Compute the extension
+     */
+    private static String getExtension(String url) {
+        final int pos = url.lastIndexOf('.');
+        return (pos < 0 ? "" : url.substring(pos+1));
+    }
+
+    /**
+     * Compute the resource type
+     */
+    private static String computeResourceType(String extension) {
+        if (extension.equals("jar")) {
+            return InstallableResource.TYPE_BUNDLE;
+        }
+        if ( extension.equals("cfg")
+             || extension.equals("config")
+             || extension.equals("xml")
+             || extension.equals("properties")) {
+            return InstallableResource.TYPE_CONFIG;
+        }
+        return extension;
+    }
+
+    /** convert digest to readable string 
(http://www.javalobby.org/java/forums/t84420.html) */
+    private static String digestToString(MessageDigest d) {
+        final BigInteger bigInt = new BigInteger(1, d.digest());
+        return new String(bigInt.toString(16));
+    }
+
+    /** Digest is needed to detect changes in data, and must not depend on 
dictionary ordering */
+    private static String computeDigest(Dictionary<String, Object> data) {
+        try {
+            final MessageDigest d = MessageDigest.getInstance("MD5");
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            final ObjectOutputStream oos = new ObjectOutputStream(bos);
+
+            final SortedSet<String> sortedKeys = new TreeSet<String>();
+            if(data != null) {
+                for(Enumeration<String> e = data.keys(); e.hasMoreElements(); 
) {
+                    final String key = e.nextElement();
+                    sortedKeys.add(key);
+                }
+            }
+            for(String key : sortedKeys) {
+                oos.writeObject(key);
+                oos.writeObject(data.get(key));
+            }
+
+            bos.flush();
+            d.update(bos.toByteArray());
+            return digestToString(d);
+        } catch (Exception ignore) {
+            return data.toString();
+        }
+    }
+
+    /** Digest is needed to detect changes in data */
+    private static String computeDigest(final File data) throws IOException {
+        try {
+            final InputStream is = new FileInputStream(data);
+            try {
+                final MessageDigest d = MessageDigest.getInstance("MD5");
+
+                final byte[] buffer = new byte[8192];
+                int count = 0;
+                while( (count = is.read(buffer, 0, buffer.length)) > 0) {
+                    d.update(buffer, 0, count);
+                }
+                return digestToString(d);
+            } finally {
+                is.close();
+            }
+        } catch (IOException ioe) {
+            throw ioe;
+        } catch (Exception ignore) {
+            return data.toString();
+        }
+    }
+
+    /**
+     * Read dictionary from an input stream.
+     * We use the same logic as Apache Felix FileInstall here:
+     * - *.cfg files are treated as property files
+     * - *.config files are handled by the Apache Felix ConfigAdmin file reader
+     * @param is
+     * @param extension
+     * @return
+     * @throws IOException
+     */
+    private static Dictionary<String, Object> readDictionary(
+            final InputStream is, final String extension) {
+        final Hashtable<String, Object> ht = new Hashtable<String, Object>();
+        final InputStream in = new BufferedInputStream(is);
+        try {
+            if ( !extension.equals("config") ) {
+                final Properties p = new Properties();
+                in.mark(1);
+                boolean isXml = in.read() == '<';
+                in.reset();
+                if (isXml) {
+                    p.loadFromXML(in);
+                } else {
+                    p.load(in);
+                }
+                final Enumeration<Object> i = p.keys();
+                while ( i.hasMoreElements() ) {
+                    final Object key = i.nextElement();
+                    ht.put(key.toString(), p.get(key));
+                }
+            } else {
+                @SuppressWarnings("unchecked")
+                final Dictionary<String, Object> config = 
ConfigurationHandler.read(in);
+                final Enumeration<String> i = config.keys();
+                while ( i.hasMoreElements() ) {
+                    final String key = i.nextElement();
+                    ht.put(key, config.get(key));
+                }
+            }
+        } catch ( IOException ignore ) {
+            return null;
+        } finally {
+            try { in.close(); } catch (IOException ignore) {}
+        }
+
+        return ht;
+    }
 }
\ No newline at end of file

Modified: 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
 Mon Aug 23 17:19:28 2010
@@ -23,7 +23,7 @@ import java.text.DecimalFormat;
 import org.apache.sling.osgi.installer.impl.Logger;
 import org.apache.sling.osgi.installer.impl.OsgiInstallerContext;
 import org.apache.sling.osgi.installer.impl.OsgiInstallerTask;
-import org.apache.sling.osgi.installer.impl.OsgiInstallerThread;
+import org.apache.sling.osgi.installer.impl.OsgiInstallerImpl;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 
@@ -70,7 +70,7 @@ public class BundleStartTask extends Osg
         }
 
         // Do not execute this task if waiting for events
-        final long eventsCount = OsgiInstallerThread.getTotalEventsCount();
+        final long eventsCount = OsgiInstallerImpl.getTotalEventsCount();
         if (eventsCount < eventsCountForRetrying) {
             Logger.logDebug(this + " is not executable at this time, 
counters=" + eventsCountForRetrying + "/" + eventsCount);
             ctx.addTaskToNextCycle(this);
@@ -100,9 +100,9 @@ public class BundleStartTask extends Osg
             // that warrants a retry), but for the next ones wait for at least 
one bundle
             // event or framework event
             if (retryCount == 0) {
-                eventsCountForRetrying = 
OsgiInstallerThread.getTotalEventsCount();
+                eventsCountForRetrying = 
OsgiInstallerImpl.getTotalEventsCount();
             } else {
-                eventsCountForRetrying = 
OsgiInstallerThread.getTotalEventsCount() + 1;
+                eventsCountForRetrying = 
OsgiInstallerImpl.getTotalEventsCount() + 1;
             }
             retryCount++;
             ctx.addTaskToNextCycle(this);

Modified: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/DictionaryDigestTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/DictionaryDigestTest.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/DictionaryDigestTest.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/DictionaryDigestTest.java
 Mon Aug 23 17:19:28 2010
@@ -21,6 +21,7 @@ package org.apache.sling.osgi.installer.
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import java.io.IOException;
 import java.util.Dictionary;
 import java.util.Hashtable;
 
@@ -28,15 +29,20 @@ import org.apache.sling.osgi.installer.I
 
 
 public class DictionaryDigestTest {
-       private void setTestData(Hashtable<String, Object> d) {
+
+    private void setTestData(Hashtable<String, Object> d) {
                d.put("str", "value");
                d.put("long", new Long(12));
                d.put("array", new String[] { "a", "b"});
        }
 
-       private String testDigestChanged(Dictionary<String, Object> d,
+    private RegisteredResourceImpl create(final InstallableResource is) throws 
IOException {
+        return RegisteredResourceImpl.create(new MockBundleContext(), is, 
"test");
+    }
+
+    private String testDigestChanged(Dictionary<String, Object> d,
                        String oldDigest, int step, boolean shouldChange) 
throws Exception {
-               final String newDigest = new InstallableResource("a", null, d, 
null, null, null).getDigest();
+               final String newDigest = create(new InstallableResource("a", 
null, d, null, null, null)).getDigest();
                if(shouldChange) {
                        assertTrue("Digest (" + newDigest + ") should have 
changed at step " + step, !newDigest.equals(oldDigest));
                } else {
@@ -54,8 +60,8 @@ public class DictionaryDigestTest {
 
                assertEquals(
                                "Two dictionary with same values have the same 
key",
-                       new InstallableResource("a", null, d1, null, null, 
null).getDigest(),
-                new InstallableResource("a", null, d2, null, null, 
null).getDigest()
+                       create(new InstallableResource("a", null, d1, null, 
null, null)).getDigest(),
+                create(new InstallableResource("a", null, d2, null, null, 
null)).getDigest()
                );
        }
 
@@ -103,8 +109,8 @@ public class DictionaryDigestTest {
                b.put("three", "C");
 
                assertEquals("Same data in different order must have same 
digest",
-                new InstallableResource("a", null, a, null, null, 
null).getDigest(),
-                new InstallableResource("a", null, b, null, null, 
null).getDigest()
+                create(new InstallableResource("a", null, a, null, null, 
null)).getDigest(),
+                create(new InstallableResource("a", null, b, null, null, 
null)).getDigest()
                );
        }
 }
\ No newline at end of file

Added: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java?rev=988214&view=auto
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java
 (added)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java
 Mon Aug 23 17:19:28 2010
@@ -0,0 +1,161 @@
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.util.Dictionary;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+public class MockBundleContext implements BundleContext {
+
+    public boolean ungetService(ServiceReference reference) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public void removeServiceListener(ServiceListener listener) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void removeFrameworkListener(FrameworkListener listener) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void removeBundleListener(BundleListener listener) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public ServiceRegistration registerService(String clazz, Object service,
+            Dictionary properties) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public ServiceRegistration registerService(String[] clazzes,
+            Object service, Dictionary properties) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Bundle installBundle(String location) throws BundleException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Bundle installBundle(String location, InputStream input)
+            throws BundleException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ServiceReference[] getServiceReferences(String clazz, String filter)
+            throws InvalidSyntaxException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ServiceReference getServiceReference(String clazz) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Object getService(ServiceReference reference) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getProperty(String key) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public File getDataFile(String filename) {
+        try {
+            final File f = File.createTempFile(filename, ".data");
+            f.deleteOnExit();
+            return f;
+        } catch (final IOException ioe) {
+            return null;
+        }
+    }
+
+    public Bundle[] getBundles() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Bundle getBundle(long id) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Bundle getBundle() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ServiceReference[] getAllServiceReferences(String clazz,
+            String filter) throws InvalidSyntaxException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Filter createFilter(String filter) throws InvalidSyntaxException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void addServiceListener(ServiceListener listener) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void addServiceListener(ServiceListener listener, String filter)
+            throws InvalidSyntaxException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void addFrameworkListener(FrameworkListener listener) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void addBundleListener(BundleListener listener) {
+        // TODO Auto-generated method stub
+
+    }
+}
\ No newline at end of file

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

Propchange: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceComparatorTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceComparatorTest.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceComparatorTest.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceComparatorTest.java
 Mon Aug 23 17:19:28 2010
@@ -49,7 +49,7 @@ public class RegisteredResourceComparato
             data.put("foo", "bar");
         }
         final InstallableResource r = new InstallableResource(url, null, data, 
null, null, priority);
-        return new RegisteredResourceImpl(null, r, "test");
+        return RegisteredResourceImpl.create(null, r, "test");
     }
 
     private void assertOrder(RegisteredResource[] inOrder) {

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=988214&r1=988213&r2=988214&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
 Mon Aug 23 17:19:28 2010
@@ -28,11 +28,14 @@ import static org.junit.Assert.fail;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Dictionary;
 import java.util.Hashtable;
 
 import org.apache.sling.osgi.installer.InstallableResource;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 
 public class RegisteredResourceTest {
@@ -47,7 +50,7 @@ public class RegisteredResourceTest {
     @org.junit.Test public void testResourceType() throws Exception {
         {
             final InputStream s = new 
FileInputStream(getTestBundle("testbundle-1.0.jar"));
-            final RegisteredResource r = new LocalFileRegisteredResource(new 
InstallableResource("test:1.jar", s, null, "some digest", null, null));
+            final RegisteredResource r = create(new 
InstallableResource("test:1.jar", s, null, "some digest", null, null));
             assertEquals(".jar URL creates a BUNDLE resource",
                     InstallableResource.TYPE_BUNDLE, r.getType());
             final InputStream rs = r.getInputStream();
@@ -61,7 +64,7 @@ public class RegisteredResourceTest {
             final Hashtable<String, Object> data = new Hashtable<String, 
Object>();
             data.put("foo", "bar");
             data.put("other", 2);
-            final RegisteredResource r = new LocalFileRegisteredResource(new 
InstallableResource("test:1", null, data, null, null, null));
+            final RegisteredResource r = create(new 
InstallableResource("test:1", null, data, null, null, null));
             assertEquals("No-extension URL with Dictionary creates a CONFIG 
resource",
                     InstallableResource.TYPE_CONFIG, r.getType());
             final InputStream rs = r.getInputStream();
@@ -74,12 +77,21 @@ public class RegisteredResourceTest {
     }
 
        @org.junit.Test public void testLocalFileCopy() throws Exception {
+           final File localFile = File.createTempFile("testLocalFileCopy", 
".data");
+        localFile.deleteOnExit();
+           final BundleContext bc = new MockBundleContext() {
+
+            public File getDataFile(String filename) {
+                return localFile;
+            }
+
+           };
            final File f = getTestBundle("testbundle-1.0.jar");
         final InputStream s = new FileInputStream(f);
-               final LocalFileRegisteredResource r = new 
LocalFileRegisteredResource(new InstallableResource("test:1.jar", s, null, 
"somedigest", null, null));
-               assertTrue("Local file exists", r.getDataFile(null).exists());
+               RegisteredResourceImpl.create(bc, new 
InstallableResource("test:1.jar", s, null, "somedigest", null, null), "test");
+               assertTrue("Local file exists", localFile.exists());
 
-               assertEquals("Local file length matches our data", f.length(), 
r.getDataFile(null).length());
+               assertEquals("Local file length matches our data", f.length(), 
localFile.length());
        }
 
     @org.junit.Test public void testMissingDigest() throws Exception {
@@ -87,23 +99,23 @@ public class RegisteredResourceTest {
         final InputStream in = new ByteArrayInputStream(data.getBytes());
 
         try {
-            new LocalFileRegisteredResource(new 
InstallableResource("test:1.jar", in, null, null, null, null));
-            fail("With jar extension, expected an IllegalArgumentException as 
digest is null");
-        } catch(IllegalArgumentException asExpected) {
+            create(new InstallableResource("test:1.jar", in, null, null, null, 
null));
+            fail("With jar extension, expected an IOException as digest is 
null");
+        } catch(IOException asExpected) {
         }
     }
 
     @org.junit.Test public void testBundleManifest() throws Exception {
         final File f = getTestBundle("testbundle-1.0.jar");
         final InstallableResource i = new InstallableResource("test:" + 
f.getAbsolutePath(), new FileInputStream(f), null, f.getName(), null, null);
-        final RegisteredResource r = new LocalFileRegisteredResource(i);
+        final RegisteredResource r = create(i);
         assertNotNull("RegisteredResource must have bundle symbolic name", 
r.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME));
         assertEquals("RegisteredResource entity ID must match", 
"bundle:osgi-installer-testbundle", r.getEntityId());
     }
 
     @org.junit.Test public void testConfigEntity() throws Exception {
         final InstallableResource i = new 
InstallableResource("test:/foo/someconfig", null, new Hashtable<String, 
Object>(), null, null, null);
-        final RegisteredResource r = new LocalFileRegisteredResource(i);
+        final RegisteredResource r = create(i);
         assertNull("RegisteredResource must not have bundle symbolic name", 
r.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME));
         assertEquals("RegisteredResource entity ID must match", 
"config:someconfig", r.getEntityId());
     }
@@ -114,6 +126,39 @@ public class RegisteredResourceTest {
         final InstallableResource rB = new InstallableResource("test:urlB", 
null, data, null, null, null);
         assertFalse(
                 "Expecting configs with same data but different URLs to have 
different digests",
-                rA.getDigest().equals(rB.getDigest()));
+                create(rA).getDigest().equals(create(rB).getDigest()));
+    }
+
+    @Test
+    public void testDictionaryDigest() throws IOException {
+        final Dictionary<String, Object> d = new Hashtable<String, Object>();
+        final InstallableResource r = new InstallableResource("x:url", null, 
d, null, null, null);
+        assertNotNull("Expected RegisteredResource to compute its own digest", 
create(r).getDigest());
+    }
+
+    @org.junit.Test public void testDictionaryDigestFromDictionaries() 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 InstallableResource r1 = new InstallableResource("test:url1", 
null, d1, null, null, null);
+        final InstallableResource r2 = new InstallableResource("test:url1", 
null, d2, null, null, null);
+
+        assertEquals(
+                "Two InstallableResource (Dictionary) with same values but 
different key orderings must have the same key",
+                create(r1).getDigest(),
+                create(r2).getDigest()
+        );
+    }
+
+    private RegisteredResourceImpl create(final InstallableResource is) throws 
IOException {
+        return RegisteredResourceImpl.create(new MockBundleContext(), is, 
"test");
     }
 }
\ No newline at end of file

Modified: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/TaskOrderingTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/TaskOrderingTest.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/TaskOrderingTest.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/TaskOrderingTest.java
 Mon Aug 23 17:19:28 2010
@@ -49,7 +49,7 @@ public class TaskOrderingTest {
        }
 
        private static RegisteredResource getRegisteredResource(String url) 
throws IOException {
-               return new RegisteredResourceImpl(null,
+               return RegisteredResourceImpl.create(null,
                        new InstallableResource(url, null, new 
Hashtable<String, Object>(), null, null, null),
                        "test");
        }

Modified: 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/MockBundleTaskCreator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/MockBundleTaskCreator.java?rev=988214&r1=988213&r2=988214&view=diff
==============================================================================
--- 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/MockBundleTaskCreator.java
 (original)
+++ 
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/MockBundleTaskCreator.java
 Mon Aug 23 17:19:28 2010
@@ -18,25 +18,13 @@
  */
 package org.apache.sling.osgi.installer.impl.tasks;
 
-import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.sling.osgi.installer.impl.MockBundleContext;
 import org.apache.sling.osgi.installer.impl.RegisteredResource;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.BundleListener;
 import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkListener;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.Version;
 
 /** BundleTaskCreator that simulates the presence and state of bundles */
@@ -45,131 +33,7 @@ class MockBundleTaskCreator extends Bund
     private final Map<String, BundleInfo> fakeBundleInfo = new HashMap<String, 
BundleInfo>();
 
     public MockBundleTaskCreator() throws IOException {
-        super(new BundleContext() {
-
-            public boolean ungetService(ServiceReference reference) {
-                // TODO Auto-generated method stub
-                return false;
-            }
-
-            public void removeServiceListener(ServiceListener listener) {
-                // TODO Auto-generated method stub
-
-            }
-
-            public void removeFrameworkListener(FrameworkListener listener) {
-                // TODO Auto-generated method stub
-
-            }
-
-            public void removeBundleListener(BundleListener listener) {
-                // TODO Auto-generated method stub
-
-            }
-
-            @SuppressWarnings("unchecked")
-            public ServiceRegistration registerService(String clazz, Object 
service,
-                    Dictionary properties) {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            @SuppressWarnings("unchecked")
-            public ServiceRegistration registerService(String[] clazzes,
-                    Object service, Dictionary properties) {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public Bundle installBundle(String location) throws 
BundleException {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public Bundle installBundle(String location, InputStream input)
-                    throws BundleException {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public ServiceReference[] getServiceReferences(String clazz, 
String filter)
-                    throws InvalidSyntaxException {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public ServiceReference getServiceReference(String clazz) {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public Object getService(ServiceReference reference) {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public String getProperty(String key) {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public File getDataFile(String filename) {
-                try {
-                    final File f = 
File.createTempFile(MockBundleTaskCreator.class.getSimpleName(), ".data");
-                    f.deleteOnExit();
-                    return f;
-                } catch (final IOException ioe) {
-                    return null;
-                }
-            }
-
-            public Bundle[] getBundles() {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public Bundle getBundle(long id) {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public Bundle getBundle() {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public ServiceReference[] getAllServiceReferences(String clazz,
-                    String filter) throws InvalidSyntaxException {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public Filter createFilter(String filter) throws 
InvalidSyntaxException {
-                // TODO Auto-generated method stub
-                return null;
-            }
-
-            public void addServiceListener(ServiceListener listener) {
-                // TODO Auto-generated method stub
-
-            }
-
-            public void addServiceListener(ServiceListener listener, String 
filter)
-                    throws InvalidSyntaxException {
-                // TODO Auto-generated method stub
-
-            }
-
-            public void addFrameworkListener(FrameworkListener listener) {
-                // TODO Auto-generated method stub
-
-            }
-
-            public void addBundleListener(BundleListener listener) {
-                // TODO Auto-generated method stub
-
-            }
-        });
+        super(new MockBundleContext());
     }
 
     void addBundleInfo(String symbolicName, String version, int state) {


Reply via email to