incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1057284 [1/2] - in /sling/trunk/installer/core/src: main/java/org/apache/sling/installer/api/ main/java/org/apache/sling/installer/api/tasks/ main/java/org/apache/sling/installer/core/impl/ main/java/org/apache/sling/installer/core/impl/co...
Date Mon, 10 Jan 2011 17:06:31 GMT
Author: cziegeler
Date: Mon Jan 10 17:06:30 2011
New Revision: 1057284

URL: http://svn.apache.org/viewvc?rev=1057284&view=rev
Log:
SLING-1923 : Improve the (internal) resource handling

Added:
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java   (with props)
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java   (with props)
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java   (with props)
Removed:
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/PersistentResourceListTest.java
Modified:
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/InstallableResource.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/TransformationResult.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileUtil.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/RegisteredResourceImpl.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigTaskCreator.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/DictionaryDigestTest.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/MockBundleResource.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/RegisteredResourceComparatorTest.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/RegisteredResourceTest.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/TaskOrderingTest.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/InstallableResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/InstallableResource.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/InstallableResource.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/InstallableResource.java Mon Jan 10 17:06:30 2011
@@ -35,6 +35,11 @@ import java.util.Dictionary;
  */
 public class InstallableResource {
 
+    /** @since 3.1 */
+    public static final String TYPE_PROPERTIES = "properties";
+    /** @since 3.1 */
+    public static final String TYPE_FILE = "file";
+
     /**
      * The type for a bundle - in this case {@link #getInputStream} must
      * return an input stream to the bundle. {@link #getDictionary()} might
@@ -71,8 +76,11 @@ public class InstallableResource {
      *           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 digest A digest of the data - providers should make sure to set
+     *               a digest. Calculating a digest by the installer can be very
+     *               expensive.
+     * @param type The resource type if known, otherwise {@link #TYPE_PROPERTIES}
+     *             or {@link #TYPE_FILE}
      * @param priority Optional priority - if not specified {@link #DEFAULT_PRIORITY}
      *                 is used
      * @throws IllegalArgumentException if something is wrong

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/TransformationResult.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/TransformationResult.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/TransformationResult.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/TransformationResult.java Mon Jan 10 17:06:30 2011
@@ -31,6 +31,9 @@ public class TransformationResult {
     /** A new input stream. */
     private InputStream inputStream;
 
+    /** Unique id. */
+    private String id;
+
     /**
      * Get the new resource type
      * @return New resource type or <code>null</code>.
@@ -48,6 +51,14 @@ public class TransformationResult {
     }
 
     /**
+     * Get the new unique id
+     * @return New unique id or <code>null</code>.
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
      * Set a new resource type.
      * @param resourceType The resource type
      */
@@ -56,6 +67,14 @@ public class TransformationResult {
     }
 
     /**
+     * Set a new unique id.
+     * @param id The unique id
+     */
+    public void setId(final String id) {
+        this.id = id;
+    }
+
+    /**
      * Set a new input stream.
      * @param inputStream The input stream
      */

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java Mon Jan 10 17:06:30 2011
@@ -18,10 +18,13 @@
  */
 package org.apache.sling.installer.core.impl;
 
+import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.apache.sling.installer.api.OsgiInstaller;
 import org.apache.sling.installer.api.tasks.InstallTaskFactory;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
 import org.apache.sling.installer.core.impl.config.ConfigTaskCreator;
 import org.apache.sling.installer.core.impl.tasks.BundleTaskCreator;
 import org.osgi.framework.BundleActivator;
@@ -38,21 +41,18 @@ public class Activator implements Bundle
     /** Vendor of all registered services. */
     private static final String VENDOR = "The Apache Software Foundation";
 
+    private List<InternalService> services = new ArrayList<InternalService>();
+    private List<ServiceRegistration> registrations = new ArrayList<ServiceRegistration>();
+
     private OsgiInstallerImpl osgiControllerService;
     private ServiceRegistration osgiControllerServiceReg;
 
-    private BundleTaskCreator bundleTaskFactory;
-    private ServiceRegistration bundleTaskFactoryReg;
-
-    private ConfigTaskCreator configTaskFactory;
-    private ServiceRegistration configTaskFactoryReg;
-
     /**
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
     public void start(final BundleContext context) throws Exception {
-        // register install task factories
-        this.registerFactories(context);
+        // register internal services
+        this.registerServices(context);
 
         // register osgi installer service
         final Hashtable<String, String> props = new Hashtable<String, String>();
@@ -77,48 +77,63 @@ public class Activator implements Bundle
             this.osgiControllerService.deactivate();
             this.osgiControllerService = null;
         }
-        // unregister service
         if ( this.osgiControllerServiceReg != null ) {
             this.osgiControllerServiceReg.unregister();
             this.osgiControllerServiceReg = null;
         }
-        if ( this.bundleTaskFactoryReg != null ) {
-            this.bundleTaskFactoryReg.unregister();
-            this.bundleTaskFactoryReg = null;
-        }
-        if ( this.bundleTaskFactory != null ) {
-            this.bundleTaskFactory.deactivate();
-            this.bundleTaskFactory = null;
-        }
-        if ( this.configTaskFactoryReg != null ) {
-            this.configTaskFactoryReg.unregister();
-            this.configTaskFactoryReg = null;
-        }
-        if ( this.configTaskFactory != null ) {
-            this.configTaskFactory.deactivate();
-            this.configTaskFactory = null;
+        // unregister services
+        for(final ServiceRegistration reg : this.registrations) {
+            reg.unregister();
+        }
+        this.registrations.clear();
+        // stop services
+        for(final InternalService service : this.services) {
+            service.deactivate();
         }
+        this.services.clear();
     }
 
-    private void registerFactories(final BundleContext context) {
-        final String [] serviceInterfaces = {
-                InstallTaskFactory.class.getName()
-        };
-
-        Hashtable<String, String> props = new Hashtable<String, String>();
-        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Bundle Install Task Factory");
-        props.put(Constants.SERVICE_VENDOR, VENDOR);
-
-        this.bundleTaskFactory = new BundleTaskCreator(context);
-        this.bundleTaskFactoryReg = context.registerService(serviceInterfaces,
-                bundleTaskFactory, props);
+    /**
+     * Register internal services.
+     */
+    private void registerServices(final BundleContext context) throws Exception {
 
-        props = new Hashtable<String, String>();
-        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Configuration Install Task Factory");
-        props.put(Constants.SERVICE_VENDOR, VENDOR);
+        final Class<?>[] serviceClasses = new Class<?>[] {
+            BundleTaskCreator.class,
+            ConfigTaskCreator.class,
+            DefaultTransformer.class
+        };
+        for(final Class<?> serviceClass : serviceClasses) {
+            final InternalService service = (InternalService) serviceClass.newInstance();
 
-        this.configTaskFactory = new ConfigTaskCreator(context);
-        this.configTaskFactoryReg = context.registerService(serviceInterfaces,
-                configTaskFactory, props);
+            final Hashtable<String, String> props = new Hashtable<String, String>();
+            props.put(Constants.SERVICE_DESCRIPTION, service.getDescription());
+            props.put(Constants.SERVICE_VENDOR, VENDOR);
+
+            final String[] serviceInterfaces;
+            if ( service instanceof ResourceTransformer && service instanceof InstallTaskFactory ) {
+                serviceInterfaces = new String[] {
+                        ResourceTransformer.class.getName(),
+                        InstallTaskFactory.class.getName()
+                };
+            } else if ( service instanceof ResourceTransformer ) {
+                serviceInterfaces = new String[] {
+                        ResourceTransformer.class.getName()
+                };
+
+            } else if ( service instanceof InstallTaskFactory ) {
+                serviceInterfaces = new String[] {
+                        InstallTaskFactory.class.getName()
+                };
+            } else {
+                serviceInterfaces = null;
+            }
+            if ( serviceInterfaces != null ) {
+                this.services.add(service);
+                service.init(context);
+                this.registrations.add(context.registerService(
+                        serviceInterfaces, service, props));
+            }
+        }
     }
 }

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java?rev=1057284&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java Mon Jan 10 17:06:30 2011
@@ -0,0 +1,205 @@
+/*
+ * 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.installer.core.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.tasks.RegisteredResource;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.apache.sling.installer.api.tasks.TransformationResult;
+import org.apache.sling.installer.core.impl.config.ConfigTaskCreator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * The default transformer transforms:
+ * - file resources containing a bundle into OSGI bundle resources
+ * - properties resources with specific extensions into OSGi configurations
+ */
+public class DefaultTransformer
+    implements InternalService, ResourceTransformer {
+
+    /**
+     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext)
+     */
+    public void init(BundleContext bctx) {
+        // nothing to do
+    }
+
+    /**
+     * @see org.apache.sling.installer.core.impl.InternalService#deactivate()
+     */
+    public void deactivate() {
+        // nothing to do
+    }
+
+    /**
+     * @see org.apache.sling.installer.core.impl.InternalService#getDescription()
+     */
+    public String getDescription() {
+        return "Apache Sling Installer - Default Resource Transformer";
+    }
+
+    /**
+     * @see org.apache.sling.installer.api.tasks.ResourceTransformer#transform(org.apache.sling.installer.api.tasks.RegisteredResource)
+     */
+    public TransformationResult transform(final RegisteredResource resource) {
+        if ( resource.getType().equals(InstallableResource.TYPE_FILE) ) {
+            return checkBundle(resource);
+        } else if ( resource.getType().equals(InstallableResource.TYPE_PROPERTIES) ) {
+            return checkConfiguration(resource);
+        }
+        return null;
+    }
+
+    /**
+     * Check if the registered resource is a bundle.
+     * @return
+     */
+    private TransformationResult checkBundle(final RegisteredResource resource) {
+        try {
+            final Manifest m = getManifest(resource.getInputStream());
+            if (m != null) {
+                final String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+                if (sn != null) {
+                    final String v = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+                    if (v != null) {
+                        resource.getAttributes().put(Constants.BUNDLE_SYMBOLICNAME, sn);
+                        resource.getAttributes().put(Constants.BUNDLE_VERSION, v.toString());
+
+                        final TransformationResult tr = new TransformationResult();
+                        tr.setId(sn);
+                        tr.setResourceType(InstallableResource.TYPE_BUNDLE);
+
+                        return tr;
+                    }
+                }
+            }
+        } catch (final IOException ignore) {
+            // ignore
+        }
+        return null;
+    }
+
+    /**
+     * Check if the registered resource is a configuration
+     * @param resource The resource
+     */
+    private TransformationResult checkConfiguration(final RegisteredResource resource) {
+        final String url = resource.getURL();
+        String lastIdPart = url;
+        final int pos = lastIdPart.lastIndexOf('/');
+        if ( pos != -1 ) {
+            lastIdPart = lastIdPart.substring(pos + 1);
+        }
+
+        final String pid;
+        // remove extension if known
+        if ( isConfigExtension(getExtension(lastIdPart)) ) {
+            final int lastDot = lastIdPart.lastIndexOf('.');
+            pid = lastIdPart.substring(0, lastDot);
+        } else {
+            pid = lastIdPart;
+        }
+
+        // split pid and factory pid alias
+        final String factoryPid;
+        final String configPid;
+        int n = pid.indexOf('-');
+        if (n > 0) {
+            configPid = pid.substring(n + 1);
+            factoryPid = pid.substring(0, n);
+        } else {
+            factoryPid = null;
+            configPid = pid;
+        }
+
+        resource.getAttributes().put(Constants.SERVICE_PID, configPid);
+        // Add pseudo-properties
+        resource.getDictionary().put(ConfigTaskCreator.CONFIG_PATH_KEY, resource.getURL());
+
+        // Factory?
+        if (factoryPid != null) {
+            resource.getAttributes().put(ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid);
+            resource.getDictionary().put(ConfigTaskCreator.ALIAS_KEY, configPid);
+        }
+
+        final TransformationResult tr = new TransformationResult();
+        final String id = (factoryPid == null ? "" : factoryPid + ".") + configPid;
+        tr.setId(id);
+        tr.setResourceType(InstallableResource.TYPE_CONFIG);
+
+        return tr;
+    }
+
+    /**
+     * Read the manifest from supplied input stream, which is closed before return.
+     */
+    private Manifest getManifest(final InputStream ins) throws IOException {
+        Manifest result = null;
+
+        JarInputStream jis = null;
+        try {
+            jis = new JarInputStream(ins);
+            result= jis.getManifest();
+
+        } finally {
+
+            // close the jar stream or the inputstream, if the jar
+            // stream is set, we don't need to close the input stream
+            // since closing the jar stream closes the input stream
+            if (jis != null) {
+                try {
+                    jis.close();
+                } catch (IOException ignore) {
+                }
+            } else {
+                try {
+                    ins.close();
+                } catch (IOException ignore) {
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Compute the extension
+     */
+    private static String getExtension(String url) {
+        final int pos = url.lastIndexOf('.');
+        return (pos < 0 ? "" : url.substring(pos+1));
+    }
+
+    private static boolean isConfigExtension(String extension) {
+        if ( extension.equals("cfg")
+                || extension.equals("config")
+                || extension.equals("xml")
+                || extension.equals("properties")) {
+            return true;
+        }
+        return false;
+    }
+}

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

Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileUtil.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileUtil.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileUtil.java Mon Jan 10 17:06:30 2011
@@ -18,7 +18,12 @@
  */
 package org.apache.sling.installer.core.impl;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 import org.osgi.framework.BundleContext;
 
@@ -41,6 +46,8 @@ public class FileUtil {
 
     private final File directory;
 
+    public static FileUtil SHARED;
+
     /**
      * Create a file util instance and detect the installer directory.
      */
@@ -86,6 +93,7 @@ public class FileUtil {
         }
 
         this.directory = locationFile;
+        SHARED = this;
     }
 
     /**
@@ -117,4 +125,22 @@ public class FileUtil {
         final String filename = hint + "-resource-" + getNextSerialNumber() + ".ser";
         return this.getDataFile(filename);
     }
+
+    /**
+     * Copy data to local storage.
+     */
+    public void copyToLocalStorage(final InputStream data,
+            final File dataFile) throws IOException {
+        final OutputStream os = new BufferedOutputStream(new FileOutputStream(dataFile));
+        try {
+            final byte[] buffer = new byte[16384];
+            int count = 0;
+            while( (count = data.read(buffer, 0, buffer.length)) > 0) {
+                os.write(buffer, 0, count);
+            }
+            os.flush();
+        } finally {
+            os.close();
+        }
+    }
 }
\ No newline at end of file

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java?rev=1057284&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java Mon Jan 10 17:06:30 2011
@@ -0,0 +1,273 @@
+/*
+ * 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.installer.core.impl;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+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;
+import org.apache.sling.installer.api.InstallableResource;
+
+/**
+ * Internal resource is a private data object which wraps
+ * an installable resource and is used to create a registered
+ * resource.
+ *
+ * An internal resource has always:
+ * - a resource type
+ * - a digest
+ *
+ */
+public class InternalResource extends InstallableResource {
+
+    /**
+     * Create an internal resource.
+     * @throws IOException if something is wrong
+     */
+    public static InternalResource create(
+            final String scheme,
+            final InstallableResource resource)
+    throws IOException {
+        // installable resource has an id, a priority and either
+        // an input stream or a dictionary
+        InputStream is = resource.getInputStream();
+        Dictionary<String, Object> dict = resource.getDictionary();
+        String type = resource.getType();
+        // Handle deprecated types and map them to new types
+        if ( InstallableResource.TYPE_BUNDLE.equals(type) ) {
+            type = InstallableResource.TYPE_FILE;
+        } else if ( InstallableResource.TYPE_CONFIG.equals(type) ) {
+            type = InstallableResource.TYPE_PROPERTIES;
+        }
+
+        if ( is != null && InstallableResource.TYPE_PROPERTIES.equals(type) ) {
+            dict = readDictionary(is, getExtension(resource.getId()));
+            if ( dict == null ) {
+                throw new IOException("Unable to read dictionary from input stream: " + resource.getId());
+            }
+            is = null;
+        }
+
+        File dataFile = null;
+        final String digest;
+        if ( is == null ) {
+            // if input stream is null, properties is expected!
+            type = (type != null ? type : InstallableResource.TYPE_PROPERTIES);
+            digest = (resource.getDigest() != null && resource.getDigest().length() > 0
+                      ? resource.getDigest() : resource.getId() + ":" + computeDigest(dict));
+        } else {
+            // if input stream is not null, file is expected!
+            dataFile = FileUtil.SHARED.createNewDataFile(resource.getType());
+            FileUtil.SHARED.copyToLocalStorage(is, dataFile);
+            type = (type != null ? type : InstallableResource.TYPE_FILE);
+            if (resource.getDigest() != null && resource.getDigest().length() > 0) {
+                digest = resource.getDigest();
+            } else {
+                digest = computeDigest(dataFile);
+            }
+        }
+        return new InternalResource(scheme,
+                resource.getId(),
+                is,
+                dict,
+                type,
+                digest,
+                resource.getPriority(),
+                dataFile);
+    }
+
+    /** The unique resource url. */
+    private final String url;
+
+    /** The data file (if copied) */
+    private File dataFile;
+
+    private InternalResource(
+            final String scheme,
+            final String id,
+            final InputStream is,
+            final Dictionary<String, Object> dict,
+            final String type,
+            final String digest,
+            final Integer priority,
+            final File dataFile) {
+        super(id, is, dict, digest, type, priority);
+        this.url = scheme + ':' + id;
+        this.dataFile = dataFile;
+    }
+
+    /** The unique url of the resource. */
+    public String getURL() {
+        return this.url;
+    }
+
+    /**
+     * Copy given Dictionary
+     */
+    public Dictionary<String, Object> getPrivateCopyOfDictionary() {
+        final Dictionary<String, Object> d = this.getDictionary();
+        if ( d == null ) {
+            return null;
+        }
+
+        final Dictionary<String, Object> result = new Hashtable<String, Object>();
+        final Enumeration<String> e = d.keys();
+        while(e.hasMoreElements()) {
+            final String key = e.nextElement();
+            result.put(key, d.get(key));
+        }
+        return result;
+    }
+
+    /**
+     * Copy the given file and return it.
+     */
+    public File getPrivateCopyOfFile() throws IOException {
+        if ( this.dataFile == null && this.getInputStream() != null ) {
+            this.dataFile = FileUtil.SHARED.createNewDataFile(this.getType());
+            FileUtil.SHARED.copyToLocalStorage(this.getInputStream(), this.dataFile);
+        }
+        return this.dataFile;
+    }
+
+    /** 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;
+    }
+
+    /** 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();
+        }
+    }
+
+    /**
+     * Compute the extension
+     */
+    private static String getExtension(String url) {
+        final int pos = url.lastIndexOf('.');
+        return (pos < 0 ? "" : url.substring(pos+1));
+    }
+}
\ No newline at end of file

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

Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java?rev=1057284&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java Mon Jan 10 17:06:30 2011
@@ -0,0 +1,33 @@
+/*
+ * 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.installer.core.impl;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Internal service interface for easier registration handling.
+ */
+public interface InternalService {
+
+    void init(BundleContext bctx);
+
+    void deactivate();
+
+    String getDescription();
+}

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

Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java Mon Jan 10 17:06:30 2011
@@ -22,7 +22,6 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -76,10 +75,10 @@ public class OsgiInstallerImpl
     private final BundleContext ctx;
 
     /** New clients are joining through this map. */
-    private final Map<String, List<RegisteredResource>> newResourcesSchemes = new HashMap<String, List<RegisteredResource>>();
+    private final Map<String, List<InternalResource>> newResourcesSchemes = new HashMap<String, List<InternalResource>>();
 
     /** New resources added by clients. */
-    private final List<RegisteredResource> newResources = new LinkedList<RegisteredResource>();
+    private final List<InternalResource> newResources = new LinkedList<InternalResource>();
 
     /** Removed resources from clients. */
     private final Set<String> urlsToRemove = new HashSet<String>();
@@ -93,18 +92,22 @@ public class OsgiInstallerImpl
     /** The persistent resource list. */
     private PersistentResourceList persistentList;
 
-    private final FileUtil fileUtil;
-
     /** A tracker for the factories. */
     private ServiceTracker factoryTracker;
 
     /** A tracker for the transformers. */
     private ServiceTracker transformerTracker;
 
+    /** New resources lock. */
+    private final Object resourcesLock = new Object();
+
     /** Constructor */
     public OsgiInstallerImpl(final BundleContext ctx) {
         this.ctx = ctx;
-        this.fileUtil = new FileUtil(ctx);
+        // Initialize file util
+        new FileUtil(ctx);
+        final File f = FileUtil.SHARED.getDataFile("RegisteredResourceList.ser");
+        this.persistentList = new PersistentResourceList(f);
     }
 
     /**
@@ -121,10 +124,11 @@ public class OsgiInstallerImpl
         ctx.removeBundleListener(this);
         ctx.removeFrameworkListener(this);
 
+        // remove file util
+        FileUtil.SHARED = null;
+
         // wake up sleeping thread
-        synchronized (newResources) {
-            newResources.notify();
-        }
+        this.wakeUp();
         this.logger.debug("Waiting for installer thread to stop");
         try {
             this.join();
@@ -149,8 +153,6 @@ public class OsgiInstallerImpl
         this.ctx.addFrameworkListener(this);
         this.ctx.addBundleListener(this);
         setName(getClass().getSimpleName());
-        final File f = this.fileUtil.getDataFile("RegisteredResourceList.ser");
-        this.persistentList = new PersistentResourceList(f);
         this.logger.info("Apache Sling OSGi Installer Service started.");
     }
 
@@ -158,7 +160,8 @@ public class OsgiInstallerImpl
     public void run() {
         this.init();
         while (active) {
-            this.mergeNewResources();
+            boolean sleep = true;
+            this.mergeNewlyRegisteredResources();
 
             // invoke transformers
             this.transformResources();
@@ -173,19 +176,18 @@ public class OsgiInstallerImpl
 
             // if we don't have any tasks, we go to sleep
             if (!tasksCreated) {
-                synchronized (newResources) {
-                    // before we go to sleep, check if new resources arrived in the meantime
-                    if ( !this.hasNewResources()) {
-                        // No tasks to execute - wait until new resources are
-                        // registered
-                        logger.debug("No tasks to process, going idle");
-                        try {
-                            newResources.wait();
-                        } catch (InterruptedException ignore) {}
-                        logger.debug("Notified of new resources, back to work");
-                    }
+                // No tasks to execute - wait until new resources are
+                // registered
+                logger.debug("No tasks to process, going idle");
+                synchronized ( this.resourcesLock ) {
+                    try {
+                        this.resourcesLock.wait();
+                    } catch (InterruptedException ignore) {}
                 }
-            } else {
+                logger.debug("Notified of new resources, back to work");
+                sleep = false;
+            }
+            if ( sleep ) {
                 // Some integration tests depend on this delay, make sure to
                 // rerun/adapt them if changing this value
                 try {
@@ -209,21 +211,22 @@ public class OsgiInstallerImpl
     }
 
     /**
-     * Create registered resources for all installable resources.
+     * Create new installable resources for all installable resources.
+     * The new versions has a set resource type.
      */
-    private List<RegisteredResource> createResources(final String scheme,
-                                                     final InstallableResource[] resources) {
+    private List<InternalResource> createResources(final String scheme,
+                                                   final InstallableResource[] resources) {
         checkScheme(scheme);
-        List<RegisteredResource> createdResources = null;
+        List<InternalResource> createdResources = null;
         if ( resources != null && resources.length > 0 ) {
-            createdResources = new ArrayList<RegisteredResource>();
+            createdResources = new ArrayList<InternalResource>();
             for(final InstallableResource r : resources ) {
                 try {
-                    final RegisteredResource rr = RegisteredResourceImpl.create(ctx, r, scheme, this.fileUtil);
+                    final InternalResource rr = InternalResource.create(scheme, r);
                     createdResources.add(rr);
                     logger.debug("Registering new resource: {}", rr);
                 } catch (final IOException ioe) {
-                    logger.warn("Cannot create RegisteredResource (resource will be ignored):" + r, ioe);
+                    logger.warn("Cannot create internal resource (resource will be ignored):" + r, ioe);
                 }
             }
         }
@@ -257,49 +260,46 @@ public class OsgiInstallerImpl
                                 final InstallableResource[] resources,
                                 final String[] ids) {
         try {
-            final List<RegisteredResource> updatedResources = this.createResources(scheme, resources);
+            final List<InternalResource> updatedResources = this.createResources(scheme, resources);
 
-            synchronized (newResources) {
-                boolean doNotify = false;
+            boolean doProcess = false;
+            synchronized ( this.resourcesLock ) {
                 if ( updatedResources != null && updatedResources.size() > 0 ) {
-                    newResources.addAll(updatedResources);
-                    doNotify = true;
+                    this.newResources.addAll(updatedResources);
+                    doProcess = true;
                 }
                 if ( ids != null && ids.length > 0 ) {
                     for(final String id : ids) {
                         final String url = scheme + ':' + id;
                         // Will mark all resources which have r's URL as uninstallable
-                        logger.debug("Adding URL {} to urlsToRemove", url);
-
-                        urlsToRemove.add(url);
+                        this.urlsToRemove.add(url);
                     }
-                    doNotify = true;
-                }
-                if ( doNotify ) {
-                    newResources.notify();
+                    doProcess = true;
                 }
             }
+            if ( doProcess ) {
+                this.wakeUp();
+            }
         } finally {
             // we simply close all input streams now
             this.closeInputStreams(resources);
         }
     }
-
     /**
      * @see org.apache.sling.installer.api.OsgiInstaller#registerResources(java.lang.String, org.apache.sling.installer.api.InstallableResource[])
      */
     public void registerResources(final String scheme, final InstallableResource[] resources) {
         try {
-            List<RegisteredResource> registeredResources = this.createResources(scheme, resources);
+            List<InternalResource> registeredResources = this.createResources(scheme, resources);
             if ( registeredResources == null ) {
-                // make sure we have a list, this makes processing later on easier
-                registeredResources = Collections.emptyList();
+                // create empty list to make processing easier
+                registeredResources = new ArrayList<InternalResource>();
             }
-            synchronized (newResources) {
-                logger.debug("Registered new resource scheme: {}", scheme);
-                newResourcesSchemes.put(scheme, registeredResources);
-                newResources.notify();
+            logger.debug("Registered new resource scheme: {}", scheme);
+            synchronized (this.resourcesLock) {
+                this.newResourcesSchemes.put(scheme, registeredResources);
             }
+            this.wakeUp();
         } finally {
             // we simply close all input streams now
             this.closeInputStreams(resources);
@@ -307,85 +307,88 @@ public class OsgiInstallerImpl
     }
 
     /**
-     * Checks if new resources are available.
-     * This method should only be invoked from within a synchronized (newResources) block!
+     * This is the heart of the installer.
+     * It processes the rendezvous between a resource provider and available resources.
      */
-    private boolean hasNewResources() {
-        return !this.newResources.isEmpty() || !this.newResourcesSchemes.isEmpty() || !this.urlsToRemove.isEmpty();
-    }
-
-    /**
-     * This is the heart of the installer - it processes new resources and merges them
-     * with existing resources.
-     * The second part consists of detecting the resources to be processsed.
-     */
-    private void mergeNewResources() {
-        synchronized (newResources) {
-            final boolean changed = this.hasNewResources();
-
-            if ( changed ) {
-                // check for new resource providers (schemes)
-                // if we have new providers we have to sync them with existing resources
-                for(final Map.Entry<String, List<RegisteredResource>> entry : this.newResourcesSchemes.entrySet()) {
-                    logger.debug("Processing set of new resources with scheme {}", entry.getKey());
-
-                    // set all previously found resources that are not available anymore to uninstall
-                    // if they have been installed - remove resources with a different state
-                    for(final String entityId : this.persistentList.getEntityIds()) {
-                        final EntityResourceList group = this.persistentList.getEntityResourceList(entityId);
-
-                        final List<RegisteredResource> toRemove = new ArrayList<RegisteredResource>();
-                        boolean first = true;
-                        for(final RegisteredResource r : group.getResources()) {
-                            if ( r.getScheme().equals(entry.getKey()) ) {
-                                logger.debug("Checking {}", r);
-                                // search if we have a new entry with the same url
-                                boolean found = false;
-                                final Iterator<RegisteredResource> m = entry.getValue().iterator();
+    private void mergeNewlyRegisteredResources() {
+        synchronized ( this.resourcesLock ) {
+            for(final Map.Entry<String, List<InternalResource>> entry : this.newResourcesSchemes.entrySet()) {
+                final String scheme = entry.getKey();
+                final List<InternalResource> registeredResources = entry.getValue();
+
+                logger.debug("Processing set of new resources with scheme {}", scheme);
+
+                // set all previously found resources that are not available anymore to uninstall
+                // if they have been installed - remove resources with a different state
+                for(final String entityId : this.persistentList.getEntityIds()) {
+                    final EntityResourceList group = this.persistentList.getEntityResourceList(entityId);
+
+                    final List<RegisteredResource> toRemove = new ArrayList<RegisteredResource>();
+                    boolean first = true;
+                    for(final RegisteredResource r : group.getResources()) {
+                        if ( r.getScheme().equals(scheme) ) {
+                            logger.debug("Checking {}", r);
+                            // search if we have a new entry with the same url
+                            boolean found = false;
+                            if ( registeredResources != null ) {
+                                final Iterator<InternalResource> m = registeredResources.iterator();
                                 while ( !found && m.hasNext() ) {
-                                    final RegisteredResource testResource = m.next();
+                                    final InternalResource testResource = m.next();
                                     found = testResource.getURL().equals(r.getURL());
                                 }
-                                if ( !found) {
-                                    logger.debug("Resource {} seems to be removed.", r);
-                                    if ( first && (r.getState() == RegisteredResource.State.INSTALLED
-                                               ||  r.getState() == RegisteredResource.State.INSTALL) ) {
-                                         r.setState(RegisteredResource.State.UNINSTALL);
-                                    } else {
-                                        toRemove.add(r);
-                                    }
+                            }
+                            if ( !found) {
+                                logger.debug("Resource {} seems to be removed.", r);
+                                if ( first && (r.getState() == RegisteredResource.State.INSTALLED
+                                           ||  r.getState() == RegisteredResource.State.INSTALL) ) {
+                                     r.setState(RegisteredResource.State.UNINSTALL);
+                                } else {
+                                    toRemove.add(r);
                                 }
                             }
-                            first = false;
-                        }
-                        for(final RegisteredResource rr : toRemove) {
-                            this.persistentList.remove(rr);
                         }
+                        first = false;
                     }
-                    logger.debug("Added set of {} new resources with scheme {} : {}",
-                            new Object[] {entry.getValue().size(), entry.getKey(), entry.getValue()});
-                    newResources.addAll(entry.getValue());
-                }
-
-                newResourcesSchemes.clear();
-
-                for(RegisteredResource r : newResources) {
-                    this.persistentList.addOrUpdate(r);
-                }
-                newResources.clear();
-
-                // Mark resources for removal according to urlsToRemove
-                if (!urlsToRemove.isEmpty()) {
-                    for(final String url : urlsToRemove ) {
-                        this.persistentList.remove(url);
+                    for(final RegisteredResource rr : toRemove) {
+                        this.persistentList.remove(rr);
                     }
                 }
-                urlsToRemove.clear();
+                if ( registeredResources != null ) {
+                    this.newResources.addAll(registeredResources);
+                }
+            }
+            this.newResourcesSchemes.clear();
+            this.mergeNewResources();
+            printResources("Merged");
+            // persist list
+            this.persistentList.save();
+        }
+    }
 
-                printResources("Merged");
-                // persist list
-                this.persistentList.save();
+    /**
+     * This is the heart of the installer -
+     * it processes new resources and deleted resources and
+     * merges them with existing resources.
+     */
+    private void mergeNewResources() {
+        // if we have new resources we have to sync them
+        if ( newResources.size() > 0 ) {
+            logger.debug("Added set of {} new resources: {}",
+                    new Object[] {newResources.size(), newResources});
+
+            for(final InternalResource r : newResources) {
+                this.persistentList.addOrUpdate(r);
+            }
+            newResources.clear();
+        }
+        // Mark resources for removal according to urlsToRemove
+        if (!urlsToRemove.isEmpty()) {
+            logger.debug("Removing set of {} resources: {}",
+                    new Object[] {urlsToRemove.size(), urlsToRemove});
+            for(final String url : urlsToRemove ) {
+                this.persistentList.remove(url);
             }
+            urlsToRemove.clear();
         }
     }
 
@@ -517,41 +520,36 @@ public class OsgiInstallerImpl
      * Invoke the transformers on the resources.
      */
     private void transformResources() {
-        // Walk the list of resources and invoke all transformers
+        boolean changed = false;
+
         final Object[] services = this.transformerTracker.getServices();
+
         if ( services != null && services.length > 0 ) {
-            boolean changed = false;
-            for(final String entityId : this.persistentList.getEntityIds()) {
-                final EntityResourceList group = this.persistentList.getEntityResourceList(entityId);
-                // Check the first resource in each group
-                final RegisteredResource toActivate = group.getActiveResource();
-                if ( toActivate != null && toActivate.getState() == RegisteredResource.State.INSTALL ) {
-                    for(int i=0; i<services.length; i++) {
-                        if ( services[i] instanceof ResourceTransformer ) {
-                            final ResourceTransformer transformer = (ResourceTransformer)services[i];
-                            final TransformationResult tr = transformer.transform(toActivate);
-                            if ( tr != null ) {
-                                if ( tr.getResourceType() != null ) {
-                                    this.persistentList.remove(toActivate);
-                                }
-                                if ( ((RegisteredResourceImpl)toActivate).update(tr) ) {
-                                    if ( tr.getResourceType() != null ) {
-                                        this.persistentList.addOrUpdate(toActivate);
-                                    }
-                                } else {
-                                    // ignore this resource from now on
-                                    toActivate.setState(RegisteredResource.State.IGNORED);
-                                }
-                                changed = true;
-                            }
+            // Walk the list of unknown resources and invoke all transformers
+            int index = 0;
+            final List<RegisteredResource> unknownList = this.persistentList.getUnknownResources();
+
+            while ( index < unknownList.size() ) {
+                final RegisteredResource resource = unknownList.get(index);
+                for(int i=0; i<services.length; i++) {
+                    if ( services[i] instanceof ResourceTransformer ) {
+                        final ResourceTransformer transformer = (ResourceTransformer)services[i];
+
+                        final TransformationResult tr = transformer.transform(resource);
+                        if ( tr != null ) {
+                            this.persistentList.transform(resource, tr);
+                            changed = true;
+                            index--;
+                            break;
                         }
                     }
                 }
+                index++;
             }
-            if ( changed ) {
-                this.persistentList.save();
-                printResources("Transformed");
-            }
+        }
+        if ( changed ) {
+            this.persistentList.save();
+            printResources("Transformed");
         }
     }
 
@@ -582,9 +580,7 @@ public class OsgiInstallerImpl
             logger.debug("Received BundleEvent that might allow installed bundles to start, scheduling retries if any");
             // TODO - for now we always reschedule regardless if we have retries
             // If the config task factory is only registered when config admin is available we can relax this again.
-            synchronized (newResources) {
-                newResources.notify();
-            }
+            this.wakeUp();
         }
     }
 
@@ -627,9 +623,13 @@ public class OsgiInstallerImpl
      */
     public Object addingService(ServiceReference reference) {
         // new factory has been added, wake up main thread
-        synchronized (newResources) {
-            newResources.notify();
-        }
+        this.wakeUp();
         return ctx.getService(reference);
     }
+
+    private void wakeUp() {
+        synchronized (this.resourcesLock) {
+            this.resourcesLock.notify();
+        }
+    }
 }
\ No newline at end of file

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java Mon Jan 10 17:06:30 2011
@@ -26,12 +26,16 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.tasks.RegisteredResource;
+import org.apache.sling.installer.api.tasks.TransformationResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,7 +46,7 @@ import org.slf4j.LoggerFactory;
 public class PersistentResourceList {
 
     /** Serialization version. */
-    private static final int VERSION = 1;
+    private static final int VERSION = 2;
 
     /** The logger */
     private final Logger logger =  LoggerFactory.getLogger(this.getClass());
@@ -54,24 +58,34 @@ public class PersistentResourceList {
      * same entity. Usually this is just one resource per entity.
      */
     private final Map<String, EntityResourceList> data;
+
+    /** The persistence file. */
     private final File dataFile;
 
+    /** All unknown resources. */
+    private final List<RegisteredResource> unknownResources;
+
     @SuppressWarnings("unchecked")
     public PersistentResourceList(final File dataFile) {
         this.dataFile = dataFile;
 
         Map<String, EntityResourceList> restoredData = null;
+        List<RegisteredResource> unknownList = null;
         if ( dataFile.exists() ) {
             ObjectInputStream ois = null;
             try {
                 ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(dataFile)));
                 final int version = ois.readInt();
-                if ( version == VERSION ) {
+                if ( version > 0 && version <= VERSION ) {
                     restoredData = (Map<String, EntityResourceList>)ois.readObject();
+                    if ( version == VERSION ) {
+                        unknownList = (List<RegisteredResource>)ois.readObject();
+                    }
                 } else {
                     logger.warn("Unknown version for persistent resource list: {}", version);
                 }
                 logger.debug("Restored resource list: {}", restoredData);
+                logger.debug("Restored unknown resource list: {}", unknownList);
             } catch (final Exception e) {
                 logger.warn("Unable to restore data, starting with empty list (" + e.getMessage() + ")", e);
             } finally {
@@ -85,6 +99,7 @@ public class PersistentResourceList {
             }
         }
         data = restoredData != null ? restoredData : new HashMap<String, EntityResourceList>();
+        this.unknownResources = unknownList != null ? unknownList : new ArrayList<RegisteredResource>();
     }
 
     public void save() {
@@ -93,6 +108,7 @@ public class PersistentResourceList {
             try {
                 oos.writeInt(VERSION);
                 oos.writeObject(data);
+                oos.writeObject(unknownResources);
                 logger.debug("Persisted resource list.");
             } finally {
                 oos.close();
@@ -106,16 +122,66 @@ public class PersistentResourceList {
         return this.data.keySet();
     }
 
-    public void addOrUpdate(final RegisteredResource r) {
-        EntityResourceList t = this.data.get(r.getEntityId());
-        if (t == null) {
-            t = new EntityResourceList();
-            this.data.put(r.getEntityId(), t);
+    /**
+     * Add or update an installable resource.
+     * @param input The installable resource
+     */
+    public void addOrUpdate(final InternalResource input) {
+        boolean found = false;
+        // first check if there are resources with the same url and digest
+        for(final EntityResourceList group : this.data.values()) {
+            for(final RegisteredResource rr : group.getResources()) {
+                if ( rr.getURL().equals(input.getURL()) && ( rr.getDigest().equals(input.getDigest()))) {
+                    found = true;
+                    break;
+                }
+            }
+            if ( found ) {
+                break;
+            }
+        }
+        // if we found the resource we can immediately return
+        if ( found ) {
+            return;
+        }
+        try {
+            final RegisteredResource registeredResource = RegisteredResourceImpl.create(input);
+            this.checkInstallable(registeredResource);
+        } catch (final IOException ioe) {
+            logger.warn("Ignoring resource. Error during processing of " + input.getURL(), ioe);
         }
+    }
 
-        t.addOrUpdate(r);
+    /**
+     * Check if the provided installable resource is already installable (has a
+     * known resource type)
+     */
+    private void checkInstallable(final RegisteredResource input) {
+        if ( !InstallableResource.TYPE_FILE.equals(input.getType())
+             && !InstallableResource.TYPE_PROPERTIES.equals(input.getType()) ) {
+
+            EntityResourceList t = this.data.get(input.getEntityId());
+            if (t == null) {
+                t = new EntityResourceList();
+                this.data.put(input.getEntityId(), t);
+            }
+
+            t.addOrUpdate(input);
+        } else {
+            this.unknownResources.add(input);
+        }
     }
 
+    /**
+     * Get the list of unknown resources = resources without resource type
+     */
+    public List<RegisteredResource> getUnknownResources() {
+        return this.unknownResources;
+    }
+    /**
+     * Remove a resource by url
+     * @param url The url to remove
+     */
     public void remove(final String url) {
         for(final EntityResourceList group : this.data.values()) {
             group.remove(url);
@@ -148,4 +214,19 @@ public class PersistentResourceList {
         return changed;
     }
 
+    /**
+     * Transform an unknown resource to a registered one
+     */
+    public void transform(final RegisteredResource resource,
+            final TransformationResult tr) {
+        // remove resource from unknown list
+        this.unknownResources.remove(resource);
+        try {
+            ((RegisteredResourceImpl)resource).update(tr);
+            this.checkInstallable(resource);
+        } catch (final IOException ioe) {
+            logger.warn("Ignoring resource. Error during processing of " + resource, ioe);
+        }
+    }
+
 }

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/RegisteredResourceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/RegisteredResourceImpl.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/RegisteredResourceImpl.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/RegisteredResourceImpl.java Mon Jan 10 17:06:30 2011
@@ -19,38 +19,21 @@
 package org.apache.sling.installer.core.impl;
 
 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.installer.api.InstallableResource;
 import org.apache.sling.installer.api.tasks.RegisteredResource;
 import org.apache.sling.installer.api.tasks.TransformationResult;
-import org.apache.sling.installer.core.impl.config.ConfigTaskCreator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
-import org.osgi.service.cm.ConfigurationAdmin;
 
 /**
  * Implementation of the registered resource
@@ -82,7 +65,7 @@ public class RegisteredResourceImpl
 	/** Additional attributes. */
 	private final Map<String, Object> attributes = new HashMap<String, Object>();
 
-	private final File dataFile;
+	private File dataFile;
 
 	private final int priority;
 
@@ -142,41 +125,17 @@ public class RegisteredResourceImpl
     /**
      * Try to create a registered resource.
      */
-    public static RegisteredResourceImpl create(final BundleContext ctx,
-            final InstallableResource input,
-            final String scheme,
-            final FileUtil fileUtil) 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 ( 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,
+    public static RegisteredResourceImpl create(
+            final InternalResource input)
+    throws IOException {
+        final int schemePos = input.getURL().indexOf(':');
+        return new RegisteredResourceImpl(input.getId(),
+                input.getPrivateCopyOfFile(),
+                input.getPrivateCopyOfDictionary(),
+                input.getType(),
                 input.getDigest(),
                 input.getPriority(),
-                scheme,
-                fileUtil);
+                input.getURL().substring(0, schemePos));
     }
 
 	/**
@@ -185,43 +144,20 @@ public class RegisteredResourceImpl
 	 * we don't have to validate values - this has already been done
 	 * The only exception is the digest!
 	 */
-	private RegisteredResourceImpl(final BundleContext ctx,
-	        final String id,
-	        final InputStream is,
+	private RegisteredResourceImpl(final String id,
+	        final File file,
 	        final Dictionary<String, Object> dict,
 	        final String type,
 	        final String digest,
 	        final int priority,
-	        final String scheme,
-	        final FileUtil fileUtil) throws IOException {
+	        final String scheme) {
         this.url = scheme + ':' + id;
+        this.dataFile = file;
+        this.dictionary = dict;
+        this.resourceType = type;
+        this.digest = digest;
+        this.priority = priority;
         this.urlScheme = scheme;
-		this.priority = priority;
-        this.dictionary = copy(dict);
-
-		if (type.equals(InstallableResource.TYPE_BUNDLE)) {
-            try {
-                this.dataFile = fileUtil.createNewDataFile(type);
-                this.copyToLocalStorage(is);
-                this.setAttributesFromManifest(false);
-                this.digest = (digest != null && digest.length() > 0 ? digest : id + ":" + computeDigest(this.dataFile));
-            } finally {
-                is.close();
-            }
-		} else if ( type.equals(InstallableResource.TYPE_CONFIG)) {
-            this.dataFile = null;
-            this.digest = (digest != null && digest.length() > 0 ? digest : id + ":" + computeDigest(dict));
-		} else {
-		    // we just copy the input stream
-            try {
-                this.dataFile = fileUtil.createNewDataFile(getType());
-                copyToLocalStorage(is);
-                this.digest = (digest != null && digest.length() > 0 ? digest : id + ":" + computeDigest(this.dataFile));
-            } finally {
-                is.close();
-            }
-		}
-		this.updateResourceType(id, type, false);
 	}
 
 	@Override
@@ -273,39 +209,6 @@ public class RegisteredResourceImpl
 	}
 
     /**
-     * Copy data to local storage.
-     */
-	private void copyToLocalStorage(final InputStream data) throws IOException {
-		final OutputStream os = new BufferedOutputStream(new FileOutputStream(this.dataFile));
-		try {
-			final byte[] buffer = new byte[16384];
-			int count = 0;
-			while( (count = data.read(buffer, 0, buffer.length)) > 0) {
-				os.write(buffer, 0, count);
-			}
-			os.flush();
-		} finally {
-			os.close();
-		}
-	}
-
-	/**
-	 * Copy given Dictionary
-	 */
-	private Dictionary<String, Object> copy(final Dictionary<String, Object> d) {
-	    if ( d == null ) {
-	        return null;
-	    }
-	    final Dictionary<String, Object> result = new Hashtable<String, Object>();
-	    final Enumeration<String> e = d.keys();
-	    while(e.hasMoreElements()) {
-	        final String key = e.nextElement();
-            result.put(key, d.get(key));
-	    }
-	    return result;
-	}
-
-    /**
      * @see org.apache.sling.installer.api.tasks.RegisteredResource#getType()
      */
     public String getType() {
@@ -326,62 +229,6 @@ public class RegisteredResourceImpl
 		return attributes;
 	}
 
-    /** Read the manifest from supplied input stream, which is closed before return */
-    private Manifest getManifest(InputStream ins) throws IOException {
-        Manifest result = null;
-
-        JarInputStream jis = null;
-        try {
-            jis = new JarInputStream(ins);
-            result= jis.getManifest();
-
-        } finally {
-
-            // close the jar stream or the inputstream, if the jar
-            // stream is set, we don't need to close the input stream
-            // since closing the jar stream closes the input stream
-            if (jis != null) {
-                try {
-                    jis.close();
-                } catch (IOException ignore) {
-                }
-            } else {
-                try {
-                    ins.close();
-                } catch (IOException ignore) {
-                }
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Set the manifest attributes from the data file.
-     * @throws IOException If anything goes wrong
-     */
-    private void setAttributesFromManifest(final boolean ignoreError) throws IOException {
-        attributes.remove(Constants.BUNDLE_SYMBOLICNAME);
-        attributes.remove(Constants.BUNDLE_VERSION);
-    	final Manifest m = getManifest(getInputStream());
-    	if (m == null) {
-    	    if ( ignoreError) {
-    	        return;
-    	    }
-            throw new IOException("Cannot get manifest of bundle resource");
-    	}
-
-    	final String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
-        if (sn != null) {
-            final String v = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
-            if (v == null) {
-                throw new IOException("Manifest does not supply " + Constants.BUNDLE_VERSION);
-            }
-            attributes.put(Constants.BUNDLE_SYMBOLICNAME, sn);
-            attributes.put(Constants.BUNDLE_VERSION, v.toString());
-        }
-    }
-
     /**
      * @see org.apache.sling.installer.api.tasks.RegisteredResource#getScheme()
      */
@@ -420,6 +267,9 @@ public class RegisteredResourceImpl
         if ( ! (obj instanceof RegisteredResource) ) {
             return false;
         }
+        if ( this.entity == null ) {
+            return this.getURL().equals(((RegisteredResource)obj).getURL());
+        }
         return compareTo((RegisteredResource)obj) == 0;
     }
 
@@ -497,141 +347,6 @@ public class RegisteredResourceImpl
     }
 
     /**
-     * Compute the extension
-     */
-    public 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 ( isConfigExtension(extension) ) {
-            return InstallableResource.TYPE_CONFIG;
-        }
-        return extension;
-    }
-
-    public static boolean isConfigExtension(String extension) {
-        if ( extension.equals("cfg")
-                || extension.equals("config")
-                || extension.equals("xml")
-                || extension.equals("properties")) {
-            return true;
-        }
-        return false;
-    }
-
-    /** 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;
-    }
-
-    /**
      * @see org.apache.sling.installer.api.tasks.RegisteredResource#getTemporaryAttribute(java.lang.String)
      */
     public Object getTemporaryAttribute(final String key) {
@@ -660,86 +375,37 @@ public class RegisteredResourceImpl
      * Currently only the input stream and resource type is updated.
      * @param tr Transformation result
      */
-    public boolean update(final TransformationResult tr) {
+    public void update(final TransformationResult tr)
+    throws IOException {
         final InputStream is = tr.getInputStream();
+        if ( tr.getResourceType() != null ) {
+            this.resourceType = tr.getResourceType();
+            if ( tr.getId() != null ) {
+                this.entity = this.resourceType + ':' + tr.getId();
+            } else {
+                if ( !InstallableResource.TYPE_FILE.equals(this.getType())
+                      && !InstallableResource.TYPE_PROPERTIES.equals(this.getType()) ) {
+
+                    String lastIdPart = this.getURL();
+                    final int slashPos = lastIdPart.lastIndexOf('/');
+                    if ( slashPos != -1 ) {
+                        lastIdPart = lastIdPart.substring(slashPos + 1);
+                    }
+                    this.entity = this.resourceType + ':' + lastIdPart;
+                }
+            }
+        }
         if ( is != null ) {
             try {
-                this.copyToLocalStorage(is);
-                this.setAttributesFromManifest(true);
-            } catch (final IOException ioe) {
-                // if an error occurs, we can ignore this resource from now on!
-                return false;
+                final File newDataFile = FileUtil.SHARED.createNewDataFile(this.getType());
+                FileUtil.SHARED.copyToLocalStorage(is, newDataFile);
+                this.cleanup();
+                this.dataFile = newDataFile;
             } finally {
                 try {
                     is.close();
                 } catch (final IOException ignore) {}
             }
         }
-        if ( tr.getResourceType() != null ) {
-            try {
-                updateResourceType(this.getURL(), tr.getResourceType(), true);
-            } catch (final IOException ioe) {
-                // if an error occurs, we can ignore this resource from now on!
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private void updateResourceType(final String id, final String type, final boolean ignoreErrors) throws IOException {
-        String lastIdPart = id;
-        final int slashPos = lastIdPart.lastIndexOf('/');
-        if ( slashPos != -1 ) {
-            lastIdPart = lastIdPart.substring(slashPos + 1);
-        }
-
-        if (type.equals(InstallableResource.TYPE_BUNDLE)) {
-            this.setAttributesFromManifest(ignoreErrors);
-            final String name = (String)attributes.get(Constants.BUNDLE_SYMBOLICNAME);
-            if (name == null) {
-                // not a bundle - we assume it to be a jar, this allows
-                // a resource transformer to transform it into a bundle
-                this.resourceType = "jar";
-                entity = resourceType + ':' + lastIdPart;
-            } else {
-                this.resourceType = InstallableResource.TYPE_BUNDLE;
-                entity = resourceType + ':' + name;
-            }
-        } else if ( type.equals(InstallableResource.TYPE_CONFIG)) {
-            this.resourceType = InstallableResource.TYPE_CONFIG;
-            // remove path
-            String pid = lastIdPart;
-            // remove extension
-            if ( RegisteredResourceImpl.isConfigExtension(RegisteredResourceImpl.getExtension(pid))) {
-                final int lastDot = pid.lastIndexOf('.');
-                pid = pid.substring(0, lastDot);
-            }
-            // split pid and factory pid alias
-            final String factoryPid;
-            final String configPid;
-            int n = pid.indexOf('-');
-            if (n > 0) {
-                configPid = pid.substring(n + 1);
-                factoryPid = pid.substring(0, n);
-            } else {
-                factoryPid = null;
-                configPid = pid;
-            }
-            this.entity = resourceType + ':' + (factoryPid == null ? "" : factoryPid + ".") + configPid;
-
-            attributes.put(Constants.SERVICE_PID, configPid);
-            // Add pseudo-properties
-            this.dictionary.put(ConfigTaskCreator.CONFIG_PATH_KEY, this.getURL());
-
-            // Factory?
-            if (factoryPid != null) {
-                attributes.put(ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid);
-                this.dictionary.put(ConfigTaskCreator.ALIAS_KEY, configPid);
-            }
-
-        } else {
-            this.resourceType = type;
-            this.entity = resourceType + ':' + lastIdPart;
-        }
     }
 }
\ No newline at end of file

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigTaskCreator.java?rev=1057284&r1=1057283&r2=1057284&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigTaskCreator.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigTaskCreator.java Mon Jan 10 17:06:30 2011
@@ -23,6 +23,7 @@ import org.apache.sling.installer.api.ta
 import org.apache.sling.installer.api.tasks.InstallTaskFactory;
 import org.apache.sling.installer.api.tasks.RegisteredResource;
 import org.apache.sling.installer.api.tasks.RegisteredResourceGroup;
+import org.apache.sling.installer.core.impl.InternalService;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.util.tracker.ServiceTracker;
@@ -30,7 +31,7 @@ import org.osgi.util.tracker.ServiceTrac
 /**
  * Task creator for configurations.
  */
-public class ConfigTaskCreator implements InstallTaskFactory {
+public class ConfigTaskCreator implements InternalService, InstallTaskFactory {
 
     public static final String ALIAS_KEY = "org.apache.sling.installer.osgi.factoryaliaspid";
     public static final String CONFIG_PATH_KEY = "org.apache.sling.installer.osgi.path";
@@ -40,24 +41,34 @@ public class ConfigTaskCreator implement
     private static String CONFIG_ADMIN_SERVICE_NAME = ConfigurationAdmin.class.getName();
 
     /** Service tracker for the configuration admin. */
-    private final ServiceTracker configAdminServiceTracker;
+    private ServiceTracker configAdminServiceTracker;
 
     /**
-     * Constructor
+     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext)
      */
-    public ConfigTaskCreator(final BundleContext bc) {
+    public void init(final BundleContext bc) {
         this.configAdminServiceTracker = new ServiceTracker(bc, CONFIG_ADMIN_SERVICE_NAME, null);
         this.configAdminServiceTracker.open();
     }
 
     /**
-     * Deactivate this creator.
+     * @see org.apache.sling.installer.core.impl.InternalService#deactivate()
      */
     public void deactivate() {
-        this.configAdminServiceTracker.close();
+        if ( this.configAdminServiceTracker != null ) {
+            this.configAdminServiceTracker.close();
+            this.configAdminServiceTracker = null;
+        }
+    }
+
+    /**
+     * @see org.apache.sling.installer.core.impl.InternalService#getDescription()
+     */
+    public String getDescription() {
+        return "Apache Sling Configuration Install Task Factory";
     }
 
-	/**
+    /**
      * Create a task to install or uninstall a configuration.
      *
 	 * @see org.apache.sling.installer.api.tasks.InstallTaskFactory#createTask(org.apache.sling.installer.api.tasks.RegisteredResourceGroup)



Mime
View raw message