You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2011/11/15 17:47:00 UTC

svn commit: r1202297 - in /sling/trunk/bundles: api/src/main/java/org/apache/sling/api/SlingConstants.java jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java

Author: cziegeler
Date: Tue Nov 15 16:46:59 2011
New Revision: 1202297

URL: http://svn.apache.org/viewvc?rev=1202297&view=rev
Log:
SLING-2277 : JCR EventAdmin bridge (JcrResourceListener) is loosing event information

Modified:
    sling/trunk/bundles/api/src/main/java/org/apache/sling/api/SlingConstants.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java

Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/SlingConstants.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/SlingConstants.java?rev=1202297&r1=1202296&r2=1202297&view=diff
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/SlingConstants.java (original)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/SlingConstants.java Tue Nov 15 16:46:59 2011
@@ -280,6 +280,9 @@ public class SlingConstants {
      * in the resource tree.
      * The event contains at least the {@link #PROPERTY_PATH}, {@link #PROPERTY_RESOURCE_SUPER_TYPE}
      * and {@link #PROPERTY_RESOURCE_TYPE} poperties.
+     * Since 2.2.0 the event might contain these properties {@link #PROPERTY_ADDED_ATTRIBUTES},
+     * {@link #PROPERTY_REMOVED_ATTRIBUTES}, {@link #PROPERTY_CHANGED_ATTRIBUTES}. All of them are
+     * optional.
      * @since 2.0.6
      */
     public static final String TOPIC_RESOURCE_CHANGED = "org/apache/sling/api/resource/Resource/CHANGED";
@@ -331,6 +334,30 @@ public class SlingConstants {
     public static final String PROPERTY_RESOURCE_SUPER_TYPE = "resourceSuperType";
 
     /**
+     * The name of the event property holding the changed attribute names
+     * of a resource for an {@link #TOPIC_RESOURCE_CHANGED} event.
+     * The value of the property is a string array.
+     * @since 2.2.0
+     */
+    public static final String PROPERTY_CHANGED_ATTRIBUTES = "resourceChangedAttributes";
+
+    /**
+     * The name of the event property holding the added attribute names
+     * of a resource for an {@link #TOPIC_RESOURCE_CHANGED} event.
+     * The value of the property is a string array.
+     * @since 2.2.0
+     */
+    public static final String PROPERTY_ADDED_ATTRIBUTES = "resourceAddedAttributes";
+
+    /**
+     * The name of the event property holding the removed attribute names
+     * of a resource for an {@link #TOPIC_RESOURCE_CHANGED} event.
+     * The value of the property is a string array.
+     * @since 2.2.0
+     */
+    public static final String PROPERTY_REMOVED_ATTRIBUTES = "resourceRemovedAttributes";
+
+    /**
      * The topic for the OSGi event which is sent when an adapter factory has been added.
      * The event contains at least the {@link #PROPERTY_ADAPTABLE_CLASSES},
      * and {@link #PROPERTY_ADAPTER_CLASSES} poperties.

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java?rev=1202297&r1=1202296&r2=1202297&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java Tue Nov 15 16:46:59 2011
@@ -20,9 +20,11 @@ package org.apache.sling.jcr.resource.in
 
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -136,7 +138,7 @@ public class JcrResourceListener impleme
             return;
         }
         final Map<String, Event> addedEvents = new HashMap<String, Event>();
-        final Map<String, Event> changedEvents = new HashMap<String, Event>();
+        final Map<String, ChangedAttributes> changedEvents = new HashMap<String, ChangedAttributes>();
         final Map<String, Event> removedEvents = new HashMap<String, Event>();
         while ( events.hasNext() ) {
             final Event event = events.nextEvent();
@@ -151,19 +153,27 @@ public class JcrResourceListener impleme
                      || event.getType() == Event.PROPERTY_REMOVED
                      || event.getType() == Event.PROPERTY_CHANGED ) {
                     final int lastSlash = eventPath.lastIndexOf('/');
-                    changedEvents.put(eventPath.substring(0, lastSlash), event);
+                    final String nodePath = eventPath.substring(0, lastSlash);
+                    final String propName = eventPath.substring(lastSlash + 1);
+                    if ( !addedEvents.containsKey(nodePath) ) {
+                        this.updateChangedEvent(changedEvents, nodePath, event, propName);
+                    }
                 } else if ( event.getType() == Event.NODE_ADDED ) {
                     // check if this is a remove/add operation
-                    if ( removedEvents.containsKey(eventPath) ) {
-                        changedEvents.put(eventPath, event);
+                    if ( removedEvents.remove(eventPath) != null ) {
+                        this.updateChangedEvent(changedEvents, eventPath, event, null);
                     } else {
+                        changedEvents.remove(eventPath);
                         addedEvents.put(eventPath, event);
                     }
+
                 } else if ( event.getType() == Event.NODE_REMOVED) {
-                    // check if this is a add/remove operation
-                    if ( !addedEvents.containsKey(eventPath) ) {
-                        removedEvents.put(eventPath, event);
-                    }
+                    // remove is the strongest operation, therefore remove all removed
+                    // paths from changed and added
+                    addedEvents.remove(eventPath);
+                    changedEvents.remove(eventPath);
+
+                    removedEvents.put(eventPath, event);
                 }
             } catch (final RepositoryException e) {
                 logger.error("Error during modification: {}", e.getMessage());
@@ -171,11 +181,6 @@ public class JcrResourceListener impleme
         }
 
         for (final Entry<String, Event> e : removedEvents.entrySet()) {
-            // remove is the strongest operation, therefore remove all removed
-            // paths from changed and added
-            addedEvents.remove(e.getKey());
-            changedEvents.remove(e.getKey());
-
             // Launch an OSGi event
             final Dictionary<String, String> properties = new Hashtable<String, String>();
             properties.put(SlingConstants.PROPERTY_PATH, createWorkspacePath(e.getKey()));
@@ -186,21 +191,78 @@ public class JcrResourceListener impleme
             localEA.postEvent(new org.osgi.service.event.Event(SlingConstants.TOPIC_RESOURCE_REMOVED, properties));
         }
 
-        // add is stronger than changed
         for (final Entry<String, Event> e : addedEvents.entrySet()) {
-            changedEvents.remove(e.getKey());
-
             // Launch an OSGi event.
-            sendOsgiEvent(e.getKey(), e.getValue(), SlingConstants.TOPIC_RESOURCE_ADDED, localEA);
+            sendOsgiEvent(e.getKey(), e.getValue(), SlingConstants.TOPIC_RESOURCE_ADDED, localEA, null);
         }
 
         // Send the changed events.
-        for (final Entry<String, Event> e : changedEvents.entrySet()) {
+        for (final Entry<String, ChangedAttributes> e : changedEvents.entrySet()) {
             // Launch an OSGi event.
-            sendOsgiEvent(e.getKey(), e.getValue(), SlingConstants.TOPIC_RESOURCE_CHANGED, localEA);
+            sendOsgiEvent(e.getKey(), e.getValue().firstEvent, SlingConstants.TOPIC_RESOURCE_CHANGED, localEA, e.getValue());
+        }
+    }
+
+    private static final class ChangedAttributes {
+
+        private final Event firstEvent;
+
+        public ChangedAttributes(final Event event) {
+            this.firstEvent = event;
+        }
+
+        public Set<String> addedAttributes, changedAttributes, removedAttributes;
+
+        public void addEvent(final Event event, final String propName) {
+            if ( event.getType() == Event.PROPERTY_ADDED ) {
+                if ( removedAttributes != null ) {
+                    removedAttributes.remove(propName);
+                }
+                if ( addedAttributes == null ) {
+                    addedAttributes = new HashSet<String>();
+                }
+                addedAttributes.add(propName);
+            } else if ( event.getType() == Event.PROPERTY_REMOVED ) {
+                if ( addedAttributes != null ) {
+                    addedAttributes.remove(propName);
+                }
+                if ( removedAttributes == null ) {
+                    removedAttributes = new HashSet<String>();
+                }
+                removedAttributes.add(propName);
+            } else if ( event.getType() == Event.PROPERTY_CHANGED ) {
+                if ( changedAttributes == null ) {
+                    changedAttributes = new HashSet<String>();
+                }
+                changedAttributes.add(propName);
+            }
+        }
+
+        public void addProperties(final Dictionary<String, Object> properties) {
+            // we're not using the Constants from SlingConstants here to avoid the requirement of the latest
+            // SLING API to be available!!
+            if ( addedAttributes != null )  {
+                properties.put("resourceAddedAttributes", addedAttributes.toArray(new String[addedAttributes.size()]));
+            }
+            if ( changedAttributes != null )  {
+                properties.put("resourceChangedAttributes", changedAttributes.toArray(new String[changedAttributes.size()]));
+            }
+            if ( removedAttributes != null )  {
+                properties.put("resourceRemovedAttributes", removedAttributes.toArray(new String[removedAttributes.size()]));
+            }
         }
     }
 
+    private void updateChangedEvent(final Map<String, ChangedAttributes> changedEvents, final String path,
+            final Event event, final String propName) {
+        ChangedAttributes storedEvent = changedEvents.get(path);
+        if ( storedEvent == null ) {
+            storedEvent = new ChangedAttributes(event);
+            changedEvents.put(path, storedEvent);
+        }
+        storedEvent.addEvent(event, propName);
+    }
+
     /**
      * Send an OSGi event based on a JCR Observation Event.
      * @param path The path too the node where the event occurred.
@@ -208,7 +270,8 @@ public class JcrResourceListener impleme
      * @param topic The topic that should be used for the OSGi event.
      * @param localEA The OSGi Event Admin that can be used to post events.
      */
-    private void sendOsgiEvent(String path, final Event event, final String topic, final EventAdmin localEA) {
+    private void sendOsgiEvent(String path, final Event event, final String topic, final EventAdmin localEA,
+            final ChangedAttributes changedAttributes) {
         path = createWorkspacePath(path);
         Resource resource = this.resolver.getResource(path);
         if ( resource != null ) {
@@ -228,7 +291,7 @@ public class JcrResourceListener impleme
                     }
                 }
             }
-            final Dictionary<String, String> properties = new Hashtable<String, String>();
+            final Dictionary<String, Object> properties = new Hashtable<String, Object>();
             properties.put(SlingConstants.PROPERTY_PATH, resource.getPath());
             properties.put(SlingConstants.PROPERTY_USERID, event.getUserID());
             final String resourceType = resource.getResourceType();
@@ -242,6 +305,9 @@ public class JcrResourceListener impleme
             if ( this.isExternal(event) ) {
                 properties.put("event.application", "unknown");
             }
+            if ( changedAttributes != null ) {
+                changedAttributes.addProperties(properties);
+            }
             localEA.postEvent(new org.osgi.service.event.Event(topic, properties));
         }
     }