incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1075697 - in /sling/trunk/installer/core: ./ src/main/java/org/apache/sling/installer/api/ src/main/java/org/apache/sling/installer/core/impl/ src/main/java/org/apache/sling/installer/core/impl/config/ src/main/java/org/apache/sling/instal...
Date Tue, 01 Mar 2011 08:16:24 GMT
Author: cziegeler
Date: Tue Mar  1 08:16:24 2011
New Revision: 1075697

URL: http://svn.apache.org/viewvc?rev=1075697&view=rev
Log:
SLING-1971 : Persist configuration (and bundle) changes not made through the installer

Added:
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/ResourceChangeListener.java   (with props)
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateHandler.java   (with props)
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateResult.java   (with props)
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/ResourceData.java   (with props)
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigUtil.java   (with props)
Modified:
    sling/trunk/installer/core/pom.xml
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/OsgiInstaller.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/DefaultTransformer.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileDataStore.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.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/SortingServiceTracker.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/AbstractConfigTask.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigInstallTask.java
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigRemoveTask.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/console/OsgiInstallerWebConsolePlugin.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/tasks/MockBundleTaskCreator.java

Modified: sling/trunk/installer/core/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/pom.xml?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/pom.xml (original)
+++ sling/trunk/installer/core/pom.xml Tue Mar  1 08:16:24 2011
@@ -58,7 +58,7 @@
                             javax.servlet;javax.servlet.http;resolution:=optional,*
                         </Import-Package>
 						<Export-Package>
-							org.apache.sling.installer.api;version=3.0.0,
+							org.apache.sling.installer.api;version=3.1.0,
                             org.apache.sling.installer.api.tasks;version=1.0.0
                         </Export-Package>
 						<Private-Package>
@@ -67,6 +67,7 @@
 						</Private-Package>
                         <Embed-Dependency>
                             org.apache.felix.configadmin;inline="org/apache/felix/cm/file/ConfigurationHandler.*"
+                            org.apache.sling.commons.osgi;inline="org/apache/sling/commons/osgi/OsgiUtil.*"
                         </Embed-Dependency>
 					</instructions>
 				</configuration>
@@ -82,7 +83,7 @@
 						</property>
                         <property>
                             <name>osgi.installer.pom.version</name>
-                            <value>${pom.version}</value>
+                            <value>${project.version}</value>
                         </property>
 					</systemProperties>
 				</configuration>
@@ -142,6 +143,12 @@
             <version>1.2.8</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.0.6</version>
+            <scope>provided</scope>
+        </dependency>
       <!-- Basic dependencies for Unit Tests -->
         <dependency>
             <groupId>junit</groupId>

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/OsgiInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/OsgiInstaller.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/OsgiInstaller.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/OsgiInstaller.java Tue Mar  1 08:16:24 2011
@@ -18,7 +18,6 @@
  */
 package org.apache.sling.installer.api;
 
-
 /**
  * OSGi Service that installs/updates/removes installable data
  * {@link InstallableResource} in the OSGi framework.
@@ -48,7 +47,7 @@ public interface OsgiInstaller {
 	 */
 	void registerResources(String urlScheme, InstallableResource[] resources);
 
-	/**
+    /**
 	 * Inform the installer that resources are available for installation
 	 * and/or other resources are no longer available.
 	 * This method is called if

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/ResourceChangeListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/ResourceChangeListener.java?rev=1075697&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/ResourceChangeListener.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/ResourceChangeListener.java Tue Mar  1 08:16:24 2011
@@ -0,0 +1,56 @@
+/*
+ * 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.api;
+
+import java.io.InputStream;
+import java.util.Dictionary;
+
+
+/**
+ * OSGi Service listening for changes of resources.
+ * These resources are not changed through the installer but through
+ * any other means like a bundle being installed directly through
+ * the framework or a configuration directly changed through the
+ * configuration admin.
+ *
+ * @since 3.1
+ */
+public interface ResourceChangeListener {
+
+    /**
+     * Inform the installer about an added or updated
+     * resource
+     * @param resourceType The resource type
+     * @param resourceId   The resource id (symbolic name etc.)
+     * @param is           Input stream or
+     * @param dict         Dictionary
+     */
+    void resourceAddedOrUpdated(final String resourceType,
+            final String resourceId,
+            final InputStream is,
+            final Dictionary<String, Object> dict);
+
+    /**
+     * Inform the installer about a removed resource
+     * @param resourceType The resource type
+     * @param resourceId   The resource id (symbolic name etc.)
+     */
+    void resourceRemoved(final String resourceType,
+            final String resourceId);
+}
\ No newline at end of file

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

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

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

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateHandler.java?rev=1075697&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateHandler.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateHandler.java Tue Mar  1 08:16:24 2011
@@ -0,0 +1,55 @@
+/*
+ * 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.api;
+
+import java.io.InputStream;
+import java.util.Dictionary;
+
+
+/**
+ * An update handler is a service handling updates of resources through other ways
+ * than the installer, e.g. handling a configuration change through the web console
+ * or directly through the configuration admin API.
+ *
+ * @since 3.1
+ */
+public interface UpdateHandler {
+
+    /**
+     * Required configuration property defining the schemes, this handler is handling.
+     * String or string array
+     */
+    String PROPERTY_SCHEMES = "handler.schemes";
+
+    /**
+     * Handle the update of a resource
+     * @param resourceType The resource type
+     * @param id The resource id, e.g. symbolic name etc.
+     * @param url The url where an earlier version of this resource came from (optional)
+     * @param is Input stream to the contents of the resource (optional)
+     * @param dict Dictionary (optional)
+     * @return If the handler could handle/perist the resource an update result is returned
+     *         otherwise the handler should return <code>null</code>
+     */
+    UpdateResult handleUpdate(final String resourceType,
+            final String id,
+            final String url,
+            final InputStream is,
+            final Dictionary<String, Object> dict);
+}
\ No newline at end of file

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

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

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

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateResult.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateResult.java?rev=1075697&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateResult.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/UpdateResult.java Tue Mar  1 08:16:24 2011
@@ -0,0 +1,105 @@
+/*
+ * 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.api;
+
+/**
+ * The update result is returned by an {@link UpdateHandler} if
+ * a resource could be persisted by the handler.
+ *
+ * @since 3.1
+ */
+public class UpdateResult {
+
+    private final String url;
+    private String digest;
+    private Integer priority;
+    private boolean resourceIsMoved = false;
+
+    /**
+     * Create an update result
+     *
+     * @param url Unique url for the resource. This should include the scheme!
+     */
+    public UpdateResult(final String url) {
+        if ( url == null ) {
+            throw new IllegalArgumentException("url must not be null.");
+        }
+
+        this.url = url;
+    }
+
+    /**
+     * Return this data's url. It is opaque for the {@link OsgiInstaller}
+     * but should uniquely identify the resource within the namespace of
+     * the used installation mechanism.
+     * The url includes the scheme followed by a colon followed by the unique id.
+     */
+    public String getURL() {
+        return this.url;
+    }
+
+    public String getScheme() {
+        final int pos = this.url.indexOf(':');
+        return this.url.substring(0, pos);
+    }
+
+    public String getResourceId() {
+        final int pos = this.url.indexOf(':');
+        return this.url.substring(pos + 1);
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Return the priority of this resource. Priorities are used to decide which
+     * resource to install when several are registered for the same OSGi entity
+     * (bundle, config, etc.)
+     */
+    public int getPriority() {
+        return this.priority != null ? this.priority : InstallableResource.DEFAULT_PRIORITY;
+    }
+
+    public void setPriority(final Integer prio) {
+        this.priority = prio;
+    }
+
+    public void setDigest(final String digest) {
+        this.digest = digest;
+    }
+
+    public void setResourceIsMoved(final boolean flag) {
+        this.resourceIsMoved = flag;
+    }
+
+    public boolean getResourceIsMoved() {
+        return this.resourceIsMoved;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + ", priority=" + this.getPriority() + ", url=" + url;
+    }
+}
\ No newline at end of file

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

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

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

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=1075697&r1=1075696&r2=1075697&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 Tue Mar  1 08:16:24 2011
@@ -24,6 +24,7 @@ import java.util.Hashtable;
 import java.util.List;
 
 import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.installer.api.ResourceChangeListener;
 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;
@@ -56,19 +57,22 @@ public class Activator implements Bundle
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
     public void start(final BundleContext context) throws Exception {
-        // register internal services
-        this.registerServices(context);
-
-        // register osgi installer service
+        // create osgi installer
         final Hashtable<String, String> props = new Hashtable<String, String>();
-        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Install Controller Service");
+        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Installer Controller Service");
         props.put(Constants.SERVICE_VENDOR, VENDOR);
 
         this.osgiControllerService = new OsgiInstallerImpl(context);
         this.osgiControllerService.setDaemon(true);
+
+        // register internal services
+        this.registerServices(context);
+
+        // start and register osgi installer service
         this.osgiControllerService.start();
         final String [] serviceInterfaces = {
-                OsgiInstaller.class.getName()
+                OsgiInstaller.class.getName(),
+                ResourceChangeListener.class.getName()
         };
         osgiControllerServiceReg = context.registerService(serviceInterfaces, osgiControllerService, props);
 
@@ -148,7 +152,7 @@ public class Activator implements Bundle
             }
             if ( serviceInterfaces != null ) {
                 this.services.add(service);
-                service.init(context);
+                service.init(context, this.osgiControllerService);
                 this.registrations.add(context.registerService(
                         serviceInterfaces, service, props));
             }

Modified: 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=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java Tue Mar  1 08:16:24 2011
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.ResourceChangeListener;
 import org.apache.sling.installer.api.tasks.RegisteredResource;
 import org.apache.sling.installer.api.tasks.ResourceTransformer;
 import org.apache.sling.installer.api.tasks.TransformationResult;
@@ -38,9 +39,9 @@ public class DefaultTransformer
     implements InternalService, ResourceTransformer {
 
     /**
-     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext)
+     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener)
      */
-    public void init(final BundleContext bctx) {
+    public void init(final BundleContext bctx, final ResourceChangeListener rcl) {
         // nothing to do
     }
 

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java Tue Mar  1 08:16:24 2011
@@ -107,6 +107,16 @@ public class EntityResourceList implemen
     }
 
     /**
+     * Return the first resource or null
+     */
+    public TaskResource getFirstResource() {
+        if ( !resources.isEmpty() ) {
+            return resources.first();
+        }
+        return null;
+    }
+
+    /**
      * Set the finish state for the resource.
      * If this resource has been uninstalled, check the next in the list if it needs to
      * be reactivated.

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileDataStore.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileDataStore.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileDataStore.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/FileDataStore.java Tue Mar  1 08:16:24 2011
@@ -19,13 +19,22 @@
 package org.apache.sling.installer.core.impl;
 
 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.math.BigInteger;
+import java.security.MessageDigest;
+import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import org.osgi.framework.BundleContext;
 import org.slf4j.LoggerFactory;
@@ -193,4 +202,60 @@ public class FileDataStore {
             }
         }
     }
+
+    /** Digest is needed to detect changes in data */
+    public 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();
+        }
+    }
+
+    /** 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 */
+    public 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/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=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalResource.java Tue Mar  1 08:16:24 2011
@@ -19,20 +19,13 @@
 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;
@@ -85,7 +78,7 @@ public class InternalResource extends In
             // 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));
+                      ? resource.getDigest() : resource.getId() + ":" + FileDataStore.computeDigest(dict));
         } else {
             final String url = scheme + ':' + resource.getId();
             // if input stream is not null, file is expected!
@@ -97,7 +90,7 @@ public class InternalResource extends In
             if (resource.getDigest() != null && resource.getDigest().length() > 0) {
                 digest = resource.getDigest();
             } else {
-                digest = computeDigest(dataFile);
+                digest = FileDataStore.computeDigest(dataFile);
                 FileDataStore.SHARED.updateDigestCache(url, digest);
             }
         }
@@ -117,7 +110,7 @@ public class InternalResource extends In
     /** The data file (if copied) */
     private File dataFile;
 
-    private InternalResource(
+    public InternalResource(
             final String scheme,
             final String id,
             final InputStream is,
@@ -161,39 +154,6 @@ public class InternalResource extends In
         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:
@@ -247,29 +207,6 @@ public class InternalResource extends In
         return "config".equals(ext) || "properties".equals(ext) || "cfg".equals(ext);
     }
 
-    /** 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
      */

Modified: 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=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java Tue Mar  1 08:16:24 2011
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.installer.core.impl;
 
+import org.apache.sling.installer.api.ResourceChangeListener;
 import org.osgi.framework.BundleContext;
 
 /**
@@ -25,7 +26,7 @@ import org.osgi.framework.BundleContext;
  */
 public interface InternalService {
 
-    void init(BundleContext bctx);
+    void init(BundleContext bctx, ResourceChangeListener listener);
 
     void deactivate();
 

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=1075697&r1=1075696&r2=1075697&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 Tue Mar  1 08:16:24 2011
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -33,8 +34,12 @@ import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+import org.apache.sling.commons.osgi.OsgiUtil;
 import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.installer.api.ResourceChangeListener;
+import org.apache.sling.installer.api.UpdateHandler;
+import org.apache.sling.installer.api.UpdateResult;
 import org.apache.sling.installer.api.tasks.InstallTask;
 import org.apache.sling.installer.api.tasks.InstallTaskFactory;
 import org.apache.sling.installer.api.tasks.InstallationContext;
@@ -65,7 +70,7 @@ import org.slf4j.LoggerFactory;
  */
 public class OsgiInstallerImpl
     extends Thread
-    implements BundleListener, FrameworkListener, OsgiInstaller {
+    implements BundleListener, FrameworkListener, OsgiInstaller, ResourceChangeListener {
 
     /** The logger */
     private final Logger logger =  LoggerFactory.getLogger(this.getClass());
@@ -100,6 +105,9 @@ public class OsgiInstallerImpl
     /** A tracker for the transformers. */
     private SortingServiceTracker<ResourceTransformer> transformerTracker;
 
+    /** A tracker for update handlers. */
+    private SortingServiceTracker<UpdateHandler> updateHandlerTracker;
+
     /** New resources lock. */
     private final Object resourcesLock = new Object();
 
@@ -150,6 +158,8 @@ public class OsgiInstallerImpl
         this.factoryTracker.open();
         this.transformerTracker = new SortingServiceTracker<ResourceTransformer>(ctx, ResourceTransformer.class.getName(), this);
         this.transformerTracker.open();
+        this.updateHandlerTracker = new SortingServiceTracker<UpdateHandler>(ctx, UpdateHandler.class.getName(), null);
+        this.updateHandlerTracker.open();
 
         // listen to framework and bundle events
         this.ctx.addFrameworkListener(this);
@@ -649,4 +659,175 @@ public class OsgiInstallerImpl
             this.resourcesLock.notify();
         }
     }
+
+    /**
+     * @see org.apache.sling.installer.api.ResourceChangeListener#resourceAddedOrUpdated(java.lang.String, java.lang.String, java.io.InputStream, java.util.Dictionary)
+     */
+    public void resourceAddedOrUpdated(final String resourceType,
+            final String resourceId,
+            final InputStream is,
+            final Dictionary<String, Object> dict) {
+        final String key = resourceType + ':' + resourceId;
+        try {
+            final ResourceData data = ResourceData.create(is, dict);
+            synchronized ( this.resourcesLock ) {
+                final EntityResourceList erl = this.persistentList.getEntityResourceList(key);
+                logger.info("Added or updated {}:{}: {}", new Object[] {resourceType, resourceId, erl});
+
+                // we first check for update
+                boolean updated = false;
+                if ( erl != null && erl.getFirstResource() != null ) {
+                    final TaskResource tr = erl.getFirstResource();
+                    final UpdateHandler handler = this.findHandler(tr.getScheme());
+                    if ( handler == null ) {
+                        logger.info("No handler found to handle update of resource with scheme {}", tr.getScheme());
+                    } else {
+                        final InputStream localIS = data.getInputStream();
+                        try {
+                            final UpdateResult result = handler.handleUpdate(resourceType, resourceId, tr.getURL(), localIS, data.getDictionary());
+                            if ( result != null ) {
+                                ((RegisteredResourceImpl)tr).update(
+                                        data.getDataFile(), data.getDictionary(),
+                                        data.getDigest(result.getURL(), result.getDigest()),
+                                        result.getPriority());
+                                // TODO : Handle move and add
+                                updated = true;
+                                // We first set the state of the resource to install to make setFinishState work in all cases
+                                ((RegisteredResourceImpl)tr).setState(ResourceState.INSTALL);
+                                erl.setFinishState(ResourceState.INSTALLED);
+                                erl.compact();
+                                this.persistentList.save();
+                                this.wakeUp();
+                            }
+                        } finally {
+                            if ( localIS != null ) {
+                                // always close the input stream!
+                                try {
+                                    localIS.close();
+                                } catch (final IOException ignore) {
+                                    // ignore
+                                }
+                            }
+                        }
+                    }
+
+                }
+
+                boolean created = false;
+                if ( !updated ) {
+                    // create
+                    final List<UpdateHandler> handlerList = this.updateHandlerTracker.getSortedServices();
+                    for(final UpdateHandler handler : handlerList) {
+                        final InputStream localIS = data.getInputStream();
+                        try {
+                            final UpdateResult result = handler.handleUpdate(resourceType, resourceId, null, localIS, data.getDictionary());
+                            if ( result != null ) {
+                                final InternalResource internalResource = new InternalResource(result.getScheme(),
+                                        result.getResourceId(),
+                                        null,
+                                        data.getDictionary(),
+                                        (data.getDictionary() != null ? InstallableResource.TYPE_PROPERTIES : InstallableResource.TYPE_FILE),
+                                        data.getDigest(result.getURL(), result.getDigest()),
+                                        result.getPriority(),
+                                        data.getDataFile());
+                                final RegisteredResource rr = this.persistentList.addOrUpdate(internalResource);
+                                final TransformationResult transRes = new TransformationResult();
+                                transRes.setId(resourceId);
+                                transRes.setResourceType(resourceType);
+                                this.persistentList.transform(rr, new TransformationResult[] {
+                                        transRes
+                                });
+                                this.persistentList.save();
+                                created = true;
+                                this.wakeUp();
+                                break;
+                            }
+                        } finally {
+                            if ( localIS != null ) {
+                                // always close the input stream!
+                                try {
+                                    localIS.close();
+                                } catch (final IOException ignore) {
+                                    // ignore
+                                }
+                            }
+                        }
+                    }
+                    if ( !created ) {
+                        logger.info("No handler found to handle creation of resource {}:{}", resourceType, resourceId);
+                    }
+                }
+
+            }
+        } catch (final IOException ioe) {
+            logger.error("Unable to handle resource add or update of " + key, ioe);
+        } finally {
+            // always close the input stream!
+            if ( is != null ) {
+                try {
+                    is.close();
+                } catch (final IOException ignore) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.sling.installer.api.ResourceChangeListener#resourceRemoved(java.lang.String, java.lang.String)
+     */
+    public void resourceRemoved(final String resourceType, final String resourceId) {
+        final String key = resourceType + ':' + resourceId;
+        synchronized ( this.resourcesLock ) {
+            final EntityResourceList erl = this.persistentList.getEntityResourceList(key);
+            logger.info("Removed {}:{}: {}", new Object[] {resourceType, resourceId, erl});
+            // if this is not registered at all, we can simply ignore this
+            if ( erl != null ) {
+                final TaskResource tr = erl.getFirstResource();
+                if ( tr != null ) {
+                    if ( tr.getState() != ResourceState.IGNORED ) {
+                        final UpdateHandler handler = this.findHandler(tr.getScheme());
+                        if ( handler == null ) {
+                            logger.info("No handler found to handle remove of resource with scheme {}", tr.getScheme());
+                        } else {
+                            // we don't need to check the result, we just check if a result is returned
+                            if ( handler.handleUpdate(resourceType, resourceId, tr.getURL(), null, null) != null ) {
+                                // We first set the state of the resource to uninstall to make setFinishState work in all cases
+                                ((RegisteredResourceImpl)tr).setState(ResourceState.UNINSTALL);
+                                erl.setFinishState(ResourceState.UNINSTALLED);
+                                erl.compact();
+                                this.persistentList.save();
+                                this.wakeUp();
+                            } else {
+                                logger.info("No handler found to handle remove of resource with scheme {}", tr.getScheme());
+                            }
+                        }
+                    } else {
+                        // if it has been ignored before, we activate it now again!
+                        ((RegisteredResourceImpl)tr).setState(ResourceState.INSTALL);
+                        this.persistentList.save();
+                        this.wakeUp();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Search a handler for the scheme.
+     */
+    private UpdateHandler findHandler(final String scheme) {
+        final List<ServiceReference> references = this.updateHandlerTracker.getSortedServiceReferences();
+        for(final ServiceReference ref : references) {
+            final String[] supportedSchemes = OsgiUtil.toStringArray(ref.getProperty(UpdateHandler.PROPERTY_SCHEMES));
+            if ( supportedSchemes != null ) {
+                for(final String support : supportedSchemes ) {
+                    if ( scheme.equals(support) ) {
+                        return (UpdateHandler) this.updateHandlerTracker.getService(ref);
+                    }
+                }
+            }
+        }
+        return null;
+    }
 }
\ 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=1075697&r1=1075696&r2=1075697&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 Tue Mar  1 08:16:24 2011
@@ -149,29 +149,23 @@ public class PersistentResourceList {
      * Add or update an installable resource.
      * @param input The installable resource
      */
-    public void addOrUpdate(final InternalResource input) {
-        boolean found = false;
+    public RegisteredResource addOrUpdate(final InternalResource input) {
         // 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 we found the resource we can immediately return
+                    return rr;
                 }
             }
-            if ( found ) {
-                break;
-            }
-        }
-        // if we found the resource we can immediately return
-        if ( found ) {
-            return;
         }
         try {
             final TaskResource registeredResource = RegisteredResourceImpl.create(input);
             this.checkInstallable(registeredResource);
+            return registeredResource;
         } catch (final IOException ioe) {
             logger.warn("Ignoring resource. Error during processing of " + input.getURL(), ioe);
+            return null;
         }
     }
 

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=1075697&r1=1075696&r2=1075697&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 Tue Mar  1 08:16:24 2011
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
 import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -55,7 +56,7 @@ public class RegisteredResourceImpl
 	private final String urlScheme;
 
 	/** The digest for the resource. */
-	private final String digest;
+	private String digest;
 
 	/** The entity id. */
 	private String entity;
@@ -68,7 +69,7 @@ public class RegisteredResourceImpl
 
 	private File dataFile;
 
-	private final int priority;
+	private int priority;
 
     private String resourceType;
 
@@ -502,4 +503,25 @@ public class RegisteredResourceImpl
 
         return rr;
     }
+
+    public void update(final File file,
+            final Dictionary<String, Object> dict,
+            final String digest,
+            final int priority) {
+        this.removeDataFile();
+        if ( file != null ) {
+            this.dataFile = file;
+        } else {
+            while ( !this.dictionary.isEmpty() ) {
+                this.dictionary.remove(this.dictionary.keys().nextElement());
+            }
+            final Enumeration<String> keys = dict.keys();
+            while ( keys.hasMoreElements() ) {
+                final String key = keys.nextElement();
+                this.dictionary.put(key, dict.get(key));
+            }
+        }
+        this.digest = digest;
+        this.priority = priority;
+    }
 }
\ No newline at end of file

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/ResourceData.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/ResourceData.java?rev=1075697&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/ResourceData.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/ResourceData.java Tue Mar  1 08:16:24 2011
@@ -0,0 +1,103 @@
+/*
+ * 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.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * ResourceData just contains the data of a resource
+ * - input stream
+ * - dictionary
+ *
+ */
+public class ResourceData {
+
+    /**
+     * Create an internal resource.
+     * @throws IOException if something is wrong
+     */
+    public static ResourceData create(
+            final InputStream stream,
+            final Dictionary<String, Object> props)
+    throws IOException {
+        if ( stream == null ) {
+            final Dictionary<String, Object> result = new Hashtable<String, Object>();
+            final Enumeration<String> e = props.keys();
+            while (e.hasMoreElements()) {
+                final String key = e.nextElement();
+                result.put(key, props.get(key));
+            }
+            return new ResourceData(result, null);
+
+        }
+        final File dataFile = FileDataStore.SHARED.createNewDataFile(stream,
+                null, null, null);
+        return new ResourceData(null, dataFile);
+    }
+
+    private final Dictionary<String, Object> dictionary;
+
+    /** The data file (if copied) */
+    private final File dataFile;
+
+    private ResourceData(final Dictionary<String, Object> dict,
+            final File dataFile) {
+        this.dictionary = dict;
+        this.dataFile = dataFile;
+    }
+
+    /**
+     * Copy given Dictionary
+     */
+    public Dictionary<String, Object> getDictionary() {
+        return this.dictionary;
+    }
+
+    /**
+     * Return the file
+     */
+    public InputStream getInputStream() throws IOException {
+        if ( this.dataFile != null ) {
+            return new FileInputStream(this.dataFile);
+        }
+        return null;
+    }
+
+    public String getDigest(final String url, String digest) throws IOException {
+        if ( this.dictionary != null ) {
+            return digest != null ? digest : FileDataStore.computeDigest(this.dictionary);
+        }
+        if ( digest == null ) {
+            digest = FileDataStore.computeDigest(this.dataFile);
+        }
+        FileDataStore.SHARED.updateDigestCache(url, digest);
+        return digest;
+
+    }
+
+    public File getDataFile() {
+        return this.dataFile;
+    }
+}
\ No newline at end of file

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

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

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

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java Tue Mar  1 08:16:24 2011
@@ -80,8 +80,10 @@ public class SortingServiceTracker<T>
     public Object addingService(ServiceReference reference) {
         this.sortedServiceCache = null;
         this.sortedReferences = null;
-        // new factory or resource transformer has been added, wake up main thread
-        this.listener.wakeUp();
+        if ( listener != null ) {
+            // new factory or resource transformer has been added, wake up main thread
+            this.listener.wakeUp();
+        }
         return context.getService(reference);
     }
 

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/AbstractConfigTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/AbstractConfigTask.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/AbstractConfigTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/AbstractConfigTask.java Tue Mar  1 08:16:24 2011
@@ -21,9 +21,7 @@ package org.apache.sling.installer.core.
 import java.io.IOException;
 import java.util.Dictionary;
 import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.Hashtable;
-import java.util.Set;
 
 import org.apache.sling.installer.api.tasks.TaskResourceGroup;
 import org.apache.sling.installer.core.impl.AbstractInstallTask;
@@ -38,14 +36,6 @@ import org.osgi.util.tracker.ServiceTrac
  */
 abstract class AbstractConfigTask extends AbstractInstallTask {
 
-    /** Configuration properties to ignore when comparing configs */
-    protected static final Set<String> ignoredProperties = new HashSet<String>();
-    static {
-        ignoredProperties.add(Constants.SERVICE_PID);
-        ignoredProperties.add(ConfigTaskCreator.CONFIG_PATH_KEY);
-        ignoredProperties.add(ConfigTaskCreator.ALIAS_KEY);
-    }
-
     /** Configuration PID */
     protected final String configPid;
 
@@ -98,63 +88,6 @@ abstract class AbstractConfigTask extend
     protected Configuration getConfiguration(final ConfigurationAdmin ca,
                                              final boolean createIfNeeded)
     throws IOException, InvalidSyntaxException {
-        Configuration result = null;
-
-        if (this.factoryPid == null) {
-            if ( createIfNeeded ) {
-                result = ca.getConfiguration(this.configPid, null);
-            } else {
-                String filter = "(" + Constants.SERVICE_PID + "=" + this.configPid + ")";
-                Configuration[] configs = ca.listConfigurations( filter );
-                if ( configs != null && configs.length > 0 ) {
-                    result = configs[0];
-                }
-            }
-        } else {
-            Configuration configs[] = ca.listConfigurations(
-                "(&(" + ConfigurationAdmin.SERVICE_FACTORYPID
-                + "=" + this.factoryPid + ")(" + ConfigTaskCreator.ALIAS_KEY + "=" + configPid
-                + "))");
-
-            if (configs == null || configs.length == 0) {
-                if (createIfNeeded) {
-                    result = ca.createFactoryConfiguration(this.factoryPid, null);
-                }
-            } else {
-                result = configs[0];
-            }
-        }
-
-        return result;
-    }
-
-    private Set<String> collectKeys(final Dictionary<String, Object>a) {
-        final Set<String> keys = new HashSet<String>();
-        final Enumeration<String> aI = a.keys();
-        while (aI.hasMoreElements() ) {
-            final String key = aI.nextElement();
-            if ( !ignoredProperties.contains(key) ) {
-                keys.add(key);
-            }
-        }
-        return keys;
-    }
-
-    /** True if a and b represent the same config data, ignoring "non-configuration" keys in the dictionaries */
-    protected boolean isSameData(Dictionary<String, Object>a, Dictionary<String, Object>b) {
-        boolean result = false;
-        if (a != null && b != null) {
-            final Set<String> keysA = collectKeys(a);
-            final Set<String> keysB = collectKeys(b);
-            if ( keysA.size() == keysB.size() && keysA.containsAll(keysB) ) {
-                for(final String key : keysA ) {
-                    if ( !a.get(key).equals(b.get(key)) ) {
-                        return result;
-                    }
-                }
-                result = true;
-            }
-        }
-        return result;
+        return ConfigUtil.getConfiguration(ca, this.factoryPid, this.configPid, createIfNeeded, true);
     }
 }

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigInstallTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigInstallTask.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigInstallTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigInstallTask.java Tue Mar  1 08:16:24 2011
@@ -59,7 +59,7 @@ public class ConfigInstallTask extends A
                 created = true;
                 config = getConfiguration(ca, true);
             } else {
-    			if (isSameData(config.getProperties(), getResource().getDictionary())) {
+    			if (ConfigUtil.isSameData(config.getProperties(), getResource().getDictionary())) {
     			    this.getLogger().debug("Configuration {} already installed with same data, update request ignored: {}",
     	                        config.getPid(), getResource());
     				config = null;

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigRemoveTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigRemoveTask.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigRemoveTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigRemoveTask.java Tue Mar  1 08:16:24 2011
@@ -60,7 +60,7 @@ public class ConfigRemoveTask extends Ab
                 if ( cfg.getProperties().get(ConfigTaskCreator.CONFIG_PATH_KEY) == null ) {
                     this.getLogger().debug("Configuration has not been installed by this resource. Not removing!");
                     this.setFinishedState(ResourceState.IGNORED);
-                } else if ( !isSameData(cfg.getProperties(), this.getResource().getDictionary()) ) {
+                } else if ( !ConfigUtil.isSameData(cfg.getProperties(), this.getResource().getDictionary()) ) {
                     this.getLogger().debug("Configuration has changed after it has been installed. Not removing!");
                     this.setFinishedState(ResourceState.IGNORED);
                 } else {

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=1075697&r1=1075696&r2=1075697&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 Tue Mar  1 08:16:24 2011
@@ -18,7 +18,10 @@
  */
 package org.apache.sling.installer.core.impl.config;
 
+import java.util.Dictionary;
+
 import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.ResourceChangeListener;
 import org.apache.sling.installer.api.tasks.InstallTask;
 import org.apache.sling.installer.api.tasks.InstallTaskFactory;
 import org.apache.sling.installer.api.tasks.ResourceState;
@@ -26,13 +29,18 @@ import org.apache.sling.installer.api.ta
 import org.apache.sling.installer.api.tasks.TaskResourceGroup;
 import org.apache.sling.installer.core.impl.InternalService;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
 import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * Task creator for configurations.
  */
-public class ConfigTaskCreator implements InternalService, InstallTaskFactory {
+public class ConfigTaskCreator
+    implements InternalService, InstallTaskFactory, ConfigurationListener {
 
     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";
@@ -44,12 +52,23 @@ public class ConfigTaskCreator implement
     /** Service tracker for the configuration admin. */
     private ServiceTracker configAdminServiceTracker;
 
+    /** Resource change listener. */
+    private ResourceChangeListener changeListener;
+
+    /** Service registration. */
+    private ServiceRegistration listenerReg;
+
+    private BundleContext bundleContext;
+
     /**
-     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext)
+     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener)
      */
-    public void init(final BundleContext bc) {
+    public void init(final BundleContext bc, final ResourceChangeListener listener) {
+        this.changeListener = listener;
         this.configAdminServiceTracker = new ServiceTracker(bc, CONFIG_ADMIN_SERVICE_NAME, null);
         this.configAdminServiceTracker.open();
+        listenerReg = bc.registerService(ConfigurationListener.class.getName(), this, null);
+        this.bundleContext = bc;
     }
 
     /**
@@ -60,9 +79,15 @@ public class ConfigTaskCreator implement
             this.configAdminServiceTracker.close();
             this.configAdminServiceTracker = null;
         }
+        if ( this.listenerReg != null ) {
+            this.listenerReg.unregister();
+            this.listenerReg = null;
+        }
+        this.changeListener = null;
+        this.bundleContext = null;
     }
 
-    /**
+    /**dann
      * @see org.apache.sling.installer.core.impl.InternalService#getDescription()
      */
     public String getDescription() {
@@ -91,4 +116,31 @@ public class ConfigTaskCreator implement
 		}
 		return result;
 	}
+
+    /**
+     * @see org.osgi.service.cm.ConfigurationListener#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
+     */
+    @SuppressWarnings("unchecked")
+    public void configurationEvent(final ConfigurationEvent event) {
+        final String id = (event.getFactoryPid() == null ? "" : event.getFactoryPid() + ".") + event.getPid();
+        if ( event.getType() == ConfigurationEvent.CM_DELETED ) {
+            this.changeListener.resourceRemoved(InstallableResource.TYPE_CONFIG, id);
+        } else {
+            final ConfigurationAdmin configAdmin = (ConfigurationAdmin) this.bundleContext.getService(event.getReference());
+            if ( configAdmin != null ) {
+                try {
+                    final Configuration config = ConfigUtil.getConfiguration(configAdmin,
+                            event.getFactoryPid(),
+                            event.getPid(),
+                            false, false);
+                    if ( config != null ) {
+                        final Dictionary<String, Object> dict = ConfigUtil.cleanConfiguration(config.getProperties());
+                        this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG, id, null, dict);
+                    }
+                } catch ( final Exception ignore) {
+                    // ignore for now (TODO)
+                }
+            }
+        }
+    }
 }

Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigUtil.java?rev=1075697&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigUtil.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/config/ConfigUtil.java Tue Mar  1 08:16:24 2011
@@ -0,0 +1,128 @@
+/*
+ * 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.config;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Utilities for configuration handling
+ */
+abstract class ConfigUtil {
+
+    /** Configuration properties to ignore when comparing configs */
+    private static final Set<String> IGNORED_PROPERTIES = new HashSet<String>();
+    static {
+        IGNORED_PROPERTIES.add(Constants.SERVICE_PID);
+        IGNORED_PROPERTIES.add(ConfigTaskCreator.CONFIG_PATH_KEY);
+        IGNORED_PROPERTIES.add(ConfigTaskCreator.ALIAS_KEY);
+    }
+
+    private static Set<String> collectKeys(final Dictionary<String, Object>a) {
+        final Set<String> keys = new HashSet<String>();
+        final Enumeration<String> aI = a.keys();
+        while (aI.hasMoreElements() ) {
+            final String key = aI.nextElement();
+            if ( !IGNORED_PROPERTIES.contains(key) ) {
+                keys.add(key);
+            }
+        }
+        return keys;
+    }
+
+    /** True if a and b represent the same config data, ignoring "non-configuration" keys in the dictionaries */
+    public static boolean isSameData(Dictionary<String, Object>a, Dictionary<String, Object>b) {
+        boolean result = false;
+        if (a != null && b != null) {
+            final Set<String> keysA = collectKeys(a);
+            final Set<String> keysB = collectKeys(b);
+            if ( keysA.size() == keysB.size() && keysA.containsAll(keysB) ) {
+                for(final String key : keysA ) {
+                    if ( !a.get(key).equals(b.get(key)) ) {
+                        return result;
+                    }
+                }
+                result = true;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Remove all ignored properties
+     */
+    public static Dictionary<String, Object> cleanConfiguration(final Dictionary<String, Object> config) {
+        final Dictionary<String, Object> cleanedConfig = new Hashtable<String, Object>();
+        final Enumeration<String> e = config.keys();
+        while(e.hasMoreElements()) {
+            final String key = e.nextElement();
+            if ( !IGNORED_PROPERTIES.contains(key) ) {
+                cleanedConfig.put(key, config.get(key));
+            }
+        }
+
+        return cleanedConfig;
+    }
+
+    public static Configuration getConfiguration(final ConfigurationAdmin ca,
+            final String factoryPid,
+            final String configPid,
+            final boolean createIfNeeded,
+            final boolean useAliasForFactory)
+    throws IOException, InvalidSyntaxException {
+        Configuration result = null;
+
+        if (factoryPid == null) {
+            if (createIfNeeded) {
+                result = ca.getConfiguration(configPid, null);
+            } else {
+                String filter = "(" + Constants.SERVICE_PID + "=" + configPid
+                        + ")";
+                Configuration[] configs = ca.listConfigurations(filter);
+                if (configs != null && configs.length > 0) {
+                    result = configs[0];
+                }
+            }
+        } else {
+            Configuration configs[] = ca.listConfigurations("(&("
+                    + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + factoryPid
+                    + ")(" + (useAliasForFactory ? ConfigTaskCreator.ALIAS_KEY : Constants.SERVICE_PID) + "=" + configPid
+                    + "))");
+
+            if (configs == null || configs.length == 0) {
+                if (createIfNeeded) {
+                    result = ca.createFactoryConfiguration(factoryPid, null);
+                }
+            } else {
+                result = configs[0];
+            }
+        }
+
+        return result;
+    }
+}

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

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

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

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/console/OsgiInstallerWebConsolePlugin.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/console/OsgiInstallerWebConsolePlugin.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/console/OsgiInstallerWebConsolePlugin.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/console/OsgiInstallerWebConsolePlugin.java Tue Mar  1 08:16:24 2011
@@ -125,8 +125,10 @@ public class OsgiInstallerWebConsolePlug
                 state.installedResources.add(group);
             }
         }
+
         Collections.sort(state.activeResources, COMPARATOR);
         Collections.sort(state.installedResources, COMPARATOR);
+
         state.untransformedResources.addAll(this.installer.getPersistentResourceList().getUntransformedResources());
 
         return state;

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java Tue Mar  1 08:16:24 2011
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.ResourceChangeListener;
 import org.apache.sling.installer.api.tasks.InstallTask;
 import org.apache.sling.installer.api.tasks.InstallTaskFactory;
 import org.apache.sling.installer.api.tasks.ResourceState;
@@ -67,9 +68,9 @@ public class BundleTaskCreator implement
     private BundleContext bundleContext;
 
     /**
-     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext)
+     * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener)
      */
-    public void init(final BundleContext bc) {
+    public void init(final BundleContext bc, final ResourceChangeListener listener) {
         this.bundleContext = bc;
         // create and start tracker
         this.packageAdminTracker = new ServiceTracker(bc, PACKAGE_ADMIN_NAME, null);

Modified: sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java?rev=1075697&r1=1075696&r2=1075697&view=diff
==============================================================================
--- sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java (original)
+++ sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java Tue Mar  1 08:16:24 2011
@@ -31,7 +31,7 @@ class MockBundleTaskCreator extends Bund
     private final Map<String, BundleInfo> fakeBundleInfo = new HashMap<String, BundleInfo>();
 
     public MockBundleTaskCreator() throws IOException {
-        this.init(new MockBundleContext());
+        this.init(new MockBundleContext(), null);
     }
 
     void addBundleInfo(String symbolicName, String version, int state) {



Mime
View raw message