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 2012/08/24 11:54:34 UTC

svn commit: r1376876 - in /sling/trunk/bundles/jcr/resource/src: main/java/org/apache/sling/jcr/resource/internal/ main/java/org/apache/sling/jcr/resource/internal/helper/jcr/ test/java/org/apache/sling/jcr/resource/internal/

Author: cziegeler
Date: Fri Aug 24 09:54:34 2012
New Revision: 1376876

URL: http://svn.apache.org/viewvc?rev=1376876&view=rev
Log:
SLING-2573 : JcrResourceListener activation is failing with NPE

Modified:
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java

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=1376876&r1=1376875&r2=1376876&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 Fri Aug 24 09:54:34 2012
@@ -34,22 +34,18 @@ import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
 import javax.jcr.observation.EventListener;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Properties;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferencePolicy;
 import org.apache.jackrabbit.api.observation.JackrabbitEvent;
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.osgi.framework.Constants;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.service.event.EventConstants;
+import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,34 +54,26 @@ import org.slf4j.LoggerFactory;
  * events and creates resource events which are sent through the
  * OSGi event admin.
  */
-@Component(immediate = true)
-@Properties({
-    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling JcrResourceListener"),
-    @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation")
-
-})
 public class JcrResourceListener implements EventListener {
 
     /** Logger */
     private final Logger logger = LoggerFactory.getLogger(JcrResourceListener.class);
 
-    @Reference(policy=ReferencePolicy.DYNAMIC)
-    private EventAdmin eventAdmin;
+    private final ServiceTracker eventAdminTracker;
 
-    @Reference
-    private ResourceResolverFactory resourceResolverFactory;
+    private ServiceReference resourceResolverFactoryReference;
 
     /** The admin resource resolver. */
     private ResourceResolver resourceResolver;
 
     /** The session for observation. */
-    private Session session;
+    private final Session session;
 
     /** Everything below this path is observed. */
-    private String startPath;
+    private final String startPath;
 
     /** The repository is mounted under this path. */
-    private String mountPrefix;
+    private final String mountPrefix;
 
     /** Is the Jackrabbit event class available? */
     private final boolean hasJackrabbitEventClass;
@@ -96,7 +84,9 @@ public class JcrResourceListener impleme
      * waiting for actual dispatching to the OSGi Event Admin in
      * {@link #processOsgiEventQueue()}
      */
-    private LinkedBlockingQueue<Dictionary<String, Object>> osgiEventQueue;
+    private final LinkedBlockingQueue<Dictionary<String, Object>> osgiEventQueue;
+
+    private final BundleContext bundleContext;
 
     /**
      * Marker event for {@link #processOsgiEventQueue()} to be signaled to
@@ -104,7 +94,11 @@ public class JcrResourceListener impleme
      */
     private final Dictionary<String, Object> TERMINATE_PROCESSING = new Hashtable<String, Object>(1);
 
-    public JcrResourceListener() {
+    public JcrResourceListener(final String startPath,
+                    final String mountPrefix,
+                    final SlingRepository repository,
+                    final BundleContext bundleContext)
+    throws RepositoryException {
         boolean foundClass = false;
         try {
             this.getClass().getClassLoader().loadClass(JackrabbitEvent.class.getName());
@@ -113,58 +107,36 @@ public class JcrResourceListener impleme
             // we ignore this
         }
         this.hasJackrabbitEventClass = foundClass;
-    }
+        this.startPath = startPath;
+        this.mountPrefix = mountPrefix;
+        this.bundleContext = bundleContext;
 
-    @Activate
-    protected void activate() throws LoginException {
-        this.resourceResolver = this.resourceResolverFactory.getAdministrativeResourceResolver(null);
-        this.startPath = "/";
-        this.mountPrefix = null;
+        this.eventAdminTracker = new ServiceTracker(bundleContext, EventAdmin.class.getName(), null);
+        this.eventAdminTracker.open();
+
+        this.session = repository.loginAdministrative(null);
+        try {
+            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);
+        } catch (final RepositoryException re) {
+            session.logout();
+            throw re;
+        }
 
         this.osgiEventQueue = new LinkedBlockingQueue<Dictionary<String,Object>>();
         final Thread oeqt = new Thread(new Runnable() {
             public void run() {
-                init();
                 processOsgiEventQueue();
             }
-        }, "JCR Resource Event Queue Processor");
+        }, "Apche Sling JCR Resource Event Queue Processor for path '" + this.startPath + "'");
         oeqt.start();
-
-    }
-
-    private void init() {
-        // lazy polling
-        Session session = null;
-        ResourceResolver resolver = this.resourceResolver;
-        while ( resolver != null && session == null ) {
-            session = this.resourceResolver.adaptTo(Session.class);
-            if ( session == null ) {
-                try {
-                    Thread.sleep(100);
-                } catch (final InterruptedException ignore) {
-                    // we ignore this
-                }
-                resolver = this.resourceResolver;
-            }
-        }
-        if ( session != null ) {
-            try {
-                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);
-                this.session = session;
-            } catch (final RepositoryException re) {
-                logger.error("Unable to register event listener.", re);
-                this.deactivate();
-            }
-        }
     }
 
     /**
      * Dispose this listener.
      */
-    @Deactivate
-    protected void deactivate() {
+    public void deactivate() {
         // unregister from observations
         if ( this.session != null ) {
             try {
@@ -178,9 +150,17 @@ public class JcrResourceListener impleme
             this.resourceResolver = null;
         }
 
+        if ( this.resourceResolverFactoryReference != null ) {
+            this.bundleContext.ungetService(this.resourceResolverFactoryReference);
+        }
+
         // drop any remaining OSGi Events not processed yet
         this.osgiEventQueue.clear();
         this.osgiEventQueue.offer(TERMINATE_PROCESSING);
+
+        if ( this.eventAdminTracker != null ) {
+            this.eventAdminTracker.close();
+        }
     }
 
     /**
@@ -188,7 +168,7 @@ public class JcrResourceListener impleme
      */
     public void onEvent(final EventIterator events) {
         // if the event admin is currently not available, we just skip this
-        final EventAdmin localEA = this.eventAdmin;
+        final EventAdmin localEA = (EventAdmin) this.eventAdminTracker.getService();
         if ( localEA == null ) {
             return;
         }
@@ -338,6 +318,28 @@ public class JcrResourceListener impleme
     }
 
     /**
+     * Get a resource resolver.
+     * We don't need any syncing as this is called from the process osgi thread.
+     */
+    private ResourceResolver getResourceResolver() {
+        if ( this.resourceResolver == null ) {
+            final ServiceReference ref = this.bundleContext.getServiceReference(ResourceResolverFactory.class.getName());
+            if ( ref != null ) {
+                final ResourceResolverFactory factory = (ResourceResolverFactory) this.bundleContext.getService(ref);
+                if ( factory != null ) {
+                    try {
+                        this.resourceResolver = factory.getAdministrativeResourceResolver(null);
+                        this.resourceResolverFactoryReference = ref;
+                    } catch (final LoginException le) {
+                        logger.error("Unable to get administrative resource resolver.", le);
+                        this.bundleContext.ungetService(ref);
+                    }
+                }
+            }
+        }
+        return this.resourceResolver;
+    }
+    /**
      * Called by the Runnable.run method of the JCR Event Queue processor to
      * process the {@link #osgiEventQueue} until the
      * {@link #TERMINATE_PROCESSING} event is received.
@@ -357,11 +359,12 @@ public class JcrResourceListener impleme
             }
 
             try {
-                final EventAdmin localEa = this.eventAdmin;
-                if (localEa != null) {
+                final EventAdmin localEa = (EventAdmin) this.eventAdminTracker.getService();
+                final ResourceResolver resolver = this.getResourceResolver();
+                if (localEa != null && resolver != null ) {
                     final String topic = (String) event.remove(EventConstants.EVENT_TOPIC);
                     final String path = (String) event.get(SlingConstants.PROPERTY_PATH);
-                    Resource resource = this.resourceResolver.getResource(path);
+                    Resource resource = resolver.getResource(path);
                     boolean sendEvent = true;
                     if (!SlingConstants.TOPIC_RESOURCE_REMOVED.equals(topic)) {
                         if (resource != null) {

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java?rev=1376876&r1=1376875&r2=1376876&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java Fri Aug 24 09:54:34 2012
@@ -27,7 +27,9 @@ import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
 import javax.jcr.query.Query;
 
+import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
@@ -41,9 +43,12 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
+import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.jcr.resource.JcrResourceConstants;
+import org.apache.sling.jcr.resource.internal.JcrResourceListener;
 import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
 
 /**
  * The <code>JcrResourceProviderFactory</code> creates
@@ -67,6 +72,24 @@ public class JcrResourceProviderFactory 
     @Reference
     private SlingRepository repository;
 
+    /** The jcr resource listner. */
+    private JcrResourceListener listener;
+
+    @Activate
+    protected void activate(final ComponentContext context)
+    throws RepositoryException {
+        final String root = PropertiesUtil.toString(context.getProperties().get(ResourceProvider.ROOTS), "/");
+        this.listener = new JcrResourceListener(root, null, this.repository, context.getBundleContext());
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        if ( this.listener != null ) {
+            this.listener.deactivate();
+            this.listener = null;
+        }
+    }
+
     /** Get the dynamic class loader if available */
     ClassLoader getDynamicClassLoader() {
         final DynamicClassLoaderManager dclm = this.dynamicClassLoaderManager;

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java?rev=1376876&r1=1376875&r2=1376876&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java Fri Aug 24 09:54:34 2012
@@ -16,6 +16,10 @@
  */
 package org.apache.sling.jcr.resource.internal;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -36,8 +40,10 @@ import org.apache.sling.commons.testing.
 import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
 import org.apache.sling.commons.testing.jcr.RepositoryUtil;
 import org.apache.sling.jcr.resource.internal.helper.jcr.JcrNodeResource;
+import org.osgi.framework.BundleContext;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * Test of JcrResourceListener.
@@ -52,16 +58,16 @@ public class JcrResourceListenerTest ext
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
-        RepositoryUtil.startRepository();
-        final Session adminSession = RepositoryUtil.getRepository().loginAdministrative(null);
-        RepositoryUtil.registerSlingNodeTypes(adminSession);
-        adminSession.logout();
+        RepositoryUtil.stopRepository();
     }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        RepositoryUtil.stopRepository();
+        RepositoryUtil.startRepository();
+        final Session adminSession = RepositoryUtil.getRepository().loginAdministrative(null);
+        RepositoryUtil.registerSlingNodeTypes(adminSession);
+        adminSession.logout();
     }
 
     public void testDefaultWorkspace() throws Exception {
@@ -264,7 +270,16 @@ public class JcrResourceListenerTest ext
             }
         };
 
-        SynchronousJcrResourceListener listener = new SynchronousJcrResourceListener(factory, mockEA);
+        final ServiceTracker tracker = mock(ServiceTracker.class);
+        when(tracker.getService()).thenReturn(mockEA);
+
+        final BundleContext bundleContext = mock(BundleContext.class);
+        when(bundleContext.createFilter(any(String.class))).thenReturn(null);
+        when(bundleContext.getServiceReference(any(String.class))).thenReturn(null);
+        when(bundleContext.getService(null)).thenReturn(mockEA);
+
+        SynchronousJcrResourceListener listener = new SynchronousJcrResourceListener(factory, getRepository(),
+                        bundleContext, resolver, tracker);
 
         createdPath = createTestPath();
         createNode(session, createdPath);

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java?rev=1376876&r1=1376875&r2=1376876&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java Fri Aug 24 09:54:34 2012
@@ -22,8 +22,11 @@ import junitx.util.PrivateAccessor;
 
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.osgi.service.event.EventAdmin;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * This class is used to ensure that events are handled during the test.
@@ -35,11 +38,15 @@ import org.osgi.service.event.EventAdmin
 public class SynchronousJcrResourceListener extends JcrResourceListener implements SynchronousEventListener {
 
     public SynchronousJcrResourceListener(
-            ResourceResolverFactory factory, EventAdmin eventAdmin)
+            ResourceResolverFactory factory,
+            SlingRepository repo,
+            BundleContext bundleContext,
+            final ResourceResolver resolver,
+            final ServiceTracker tracker)
             throws LoginException, RepositoryException, NoSuchFieldException {
-        PrivateAccessor.setField(this, "resourceResolverFactory", factory);
-        PrivateAccessor.setField(this, "eventAdmin", eventAdmin);
-        this.activate();
+        super("/", null, repo, bundleContext);
+        PrivateAccessor.setField(this, "resourceResolver", resolver);
+        PrivateAccessor.setField(this, "eventAdminTracker", tracker);
     }
 
     public void dispose() {