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 2009/06/30 14:45:31 UTC
svn commit: r789697 - in
/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal:
JcrResourceListener.java JcrResourceResolverFactoryImpl.java
Author: cziegeler
Date: Tue Jun 30 12:45:31 2009
New Revision: 789697
URL: http://svn.apache.org/viewvc?rev=789697&view=rev
Log:
SLING-944 : Add resource listener that fires events for jcr resources, fire events for new resource providers and when they are removed.
Added:
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java (with props)
Modified:
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
Added: 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=789697&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java (added)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java Tue Jun 30 12:45:31 2009
@@ -0,0 +1,162 @@
+/*
+ * 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.jcr.resource.internal;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JcrResourceListener implements EventListener {
+
+ /** Logger */
+ private static final Logger LOGGER = LoggerFactory.getLogger(JcrResourceListener.class);
+
+ /** The session for observation. */
+ private final Session session;
+
+ /** Everything below this path is observed. */
+ private final String startPath;
+
+ /** The repository is mounted under this path. */
+ private final String mountPrefix;
+
+ /** The resource resolver. */
+ private final ResourceResolver resolver;
+
+ /** The event admin tracker. */
+ private ServiceTracker eventAdminTracker;
+
+ public JcrResourceListener(final SlingRepository repository,
+ final JcrResourceResolverFactory factory,
+ final String startPath,
+ final String mountPrefix,
+ final ServiceTracker eventAdminTracker)
+ throws RepositoryException {
+ this.session = repository.loginAdministrative(null);
+ this.resolver = factory.getResourceResolver(this.session);
+ this.startPath = startPath;
+ this.eventAdminTracker = eventAdminTracker;
+ this.mountPrefix = (mountPrefix.equals("/") ? null : mountPrefix);
+ this.session.getWorkspace().getObservationManager().addEventListener(this,
+ Event.NODE_ADDED|Event.NODE_REMOVED|Event.PROPERTY_ADDED|Event.PROPERTY_CHANGED|Event.PROPERTY_REMOVED,
+ this.startPath, true, null, null, false);
+ }
+
+ public void dispose() {
+ try {
+ this.session.getWorkspace().getObservationManager().removeEventListener(this);
+ } catch (RepositoryException e) {
+ LOGGER.warn("Unable to remove session listener: " + this, e);
+ }
+ this.session.logout();
+ }
+
+ /**
+ * @see javax.jcr.observation.EventListener#onEvent(javax.jcr.observation.EventIterator)
+ */
+ public void onEvent(EventIterator events) {
+ final EventAdmin localEA = (EventAdmin) this.eventAdminTracker.getService();
+ if ( localEA == null ) {
+ return;
+ }
+ final Set<String>addedPaths = new HashSet<String>();
+ final Set<String>removedPaths = new HashSet<String>();
+ final Set<String>changedPaths = new HashSet<String>();
+ while ( events.hasNext() ) {
+ final Event event = events.nextEvent();
+ try {
+ Set<String> set = null;
+ String nodePath = event.getPath();
+ if ( event.getType() == Event.PROPERTY_ADDED
+ || event.getType() == Event.PROPERTY_REMOVED
+ || event.getType() == Event.PROPERTY_CHANGED ) {
+ final int lastSlash = nodePath.lastIndexOf('/');
+ nodePath = nodePath.substring(0, lastSlash);
+ set = changedPaths;
+ } else if ( event.getType() == Event.NODE_ADDED ) {
+ set = addedPaths;
+ } else if ( event.getType() == Event.NODE_REMOVED) {
+ set = removedPaths;
+ }
+ if ( set != null ) {
+ if ( this.mountPrefix != null ) {
+ set.add(this.mountPrefix + nodePath);
+ } else {
+ set.add(nodePath);
+ }
+ }
+ } catch (RepositoryException e) {
+ LOGGER.error("Error during modification: {}", e.getMessage());
+ }
+ }
+ // remove is the strongest oberation, therefore remove all removed
+ // paths from changed and added
+ addedPaths.removeAll(removedPaths);
+ changedPaths.removeAll(removedPaths);
+ // add is stronger than changed
+ changedPaths.removeAll(addedPaths);
+
+ // send events
+ for(final String path : addedPaths) {
+ final Resource resource = this.resolver.getResource(path);
+ if ( resource != null ) {
+ final Dictionary<String, String> properties = new Hashtable<String, String>();
+ properties.put(SlingConstants.PROPERTY_PATH, resource.getPath());
+ properties.put(SlingConstants.PROPERTY_RESOURCE_TYPE, resource.getResourceType());
+ properties.put(SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE, resource.getResourceSuperType());
+
+ localEA.postEvent(new org.osgi.service.event.Event(SlingConstants.TOPIC_RESOURCE_ADDED, properties));
+ }
+ }
+ for(final String path : changedPaths) {
+ final Resource resource = this.resolver.getResource(path);
+ if ( resource != null ) {
+ final Dictionary<String, String> properties = new Hashtable<String, String>();
+ properties.put(SlingConstants.PROPERTY_PATH, resource.getPath());
+ properties.put(SlingConstants.PROPERTY_RESOURCE_TYPE, resource.getResourceType());
+ properties.put(SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE, resource.getResourceSuperType());
+
+ localEA.postEvent(new org.osgi.service.event.Event(SlingConstants.TOPIC_RESOURCE_CHANGED, properties));
+ }
+ }
+ for(final String path : removedPaths) {
+ final Dictionary<String, String> properties = new Hashtable<String, String>();
+ properties.put(SlingConstants.PROPERTY_PATH, path);
+
+ localEA.postEvent(new org.osgi.service.event.Event(SlingConstants.TOPIC_RESOURCE_REMOVED, properties));
+ }
+ }
+}
Propchange: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java?rev=789697&r1=789696&r2=789697&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java Tue Jun 30 12:45:31 2009
@@ -22,6 +22,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.Dictionary;
+import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -31,6 +32,7 @@
import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.TreeBidiMap;
+import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.osgi.OsgiUtil;
@@ -45,6 +47,9 @@
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -193,6 +198,12 @@
// whether to mangle paths with namespaces or not
private boolean mangleNamespacePrefixes;
+ /** The resource listenr for the observation events. */
+ private JcrResourceListener resourceListener;
+
+ /** The service tracker for the event admin
+ */
+ private ServiceTracker eventAdminTracker;
public JcrResourceResolverFactoryImpl() {
this.rootProviderEntry = new ResourceProviderEntry("/", null, null);
@@ -270,6 +281,11 @@
/** Activates this component, called by SCR before registering as a service */
protected void activate(ComponentContext componentContext) {
+ // setup tracker first as this is used in the bind/unbind methods
+ this.eventAdminTracker = new ServiceTracker(componentContext.getBundleContext(),
+ EventAdmin.class.getName(), null);
+ this.eventAdminTracker.open();
+
this.componentContext = componentContext;
Dictionary<?, ?> properties = componentContext.getProperties();
@@ -339,6 +355,15 @@
"activate: Cannot access repository, failed setting up Mapping Support",
e);
}
+
+ // start observation listener
+ try {
+ this.resourceListener = new JcrResourceListener(this.repository, this, "/", "/", this.eventAdminTracker);
+ } catch (Exception e) {
+ log.error(
+ "activate: Cannot create resource listener; resource events for JCR resources will be disabled.",
+ e);
+ }
}
private JcrResourceResolverWebConsolePlugin plugin;
@@ -354,7 +379,14 @@
mapEntries.dispose();
mapEntries = MapEntries.EMPTY;
}
-
+ if ( this.eventAdminTracker != null ) {
+ this.eventAdminTracker.close();
+ this.eventAdminTracker = null;
+ }
+ if ( this.resourceListener != null ) {
+ this.resourceListener.dispose();
+ this.resourceListener = null;
+ }
this.componentContext = null;
}
@@ -418,6 +450,7 @@
String[] roots = OsgiUtil.toStringArray(reference.getProperty(ResourceProvider.ROOTS));
if (roots != null && roots.length > 0) {
+ final EventAdmin localEA = (EventAdmin) this.eventAdminTracker.getService();
ResourceProvider provider = (ResourceProvider) componentContext.locateService(
"ResourceProvider", reference);
@@ -444,6 +477,12 @@
new Object[] { provider, root,
rpee.getExisting().getResourceProvider() });
}
+ if ( localEA != null ) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_PATH, root);
+ localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED,
+ props));
+ }
}
}
}
@@ -461,6 +500,8 @@
String[] roots = OsgiUtil.toStringArray(reference.getProperty(ResourceProvider.ROOTS));
if (roots != null && roots.length > 0) {
+ final EventAdmin localEA = (EventAdmin) ( this.eventAdminTracker != null ? this.eventAdminTracker.getService() : null);
+
// synchronized insertion of new resource providers into
// the tree to not inadvertently loose an entry
synchronized (this) {
@@ -478,6 +519,12 @@
log.debug("unbindResourceProvider: root={} ({})", root,
serviceName);
+ if ( localEA != null ) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_PATH, root);
+ localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED,
+ props));
+ }
}
}
}