You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2008/09/09 16:11:25 UTC

svn commit: r693467 - in /incubator/sling/trunk/extensions/jcrinstall/src: main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/

Author: bdelacretaz
Date: Tue Sep  9 07:11:23 2008
New Revision: 693467

URL: http://svn.apache.org/viewvc?rev=693467&view=rev
Log:
SLING-646 - work in progress, WatchedFolderCreationListener added and tested

Added:
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java   (with props)
Modified:
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/RepositoryObserver.java
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolder.java
    incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java

Modified: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/RepositoryObserver.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/RepositoryObserver.java?rev=693467&r1=693466&r2=693467&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/RepositoryObserver.java (original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/RepositoryObserver.java Tue Sep  9 07:11:23 2008
@@ -19,12 +19,15 @@
 package org.apache.sling.jcr.jcrinstall.jcr.impl;
 
 import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Set;
 
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.observation.Event;
 
 import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiController;
@@ -50,25 +53,81 @@
     /** @scr.reference */
     private SlingRepository repository;
     
+    private Session session;
+    
+    private List<WatchedFolderCreationListener> listeners = new LinkedList<WatchedFolderCreationListener>();
+    
     /** Default set of root folders to watch */
     public static String[] DEFAULT_ROOTS = {"/libs", "/apps"};
     
+    /** Default regexp for watched folders */
+    public static final String DEFAULT_FOLDER_NAME_REGEXP = ".*/install$";
+    
     protected static final Logger log = LoggerFactory.getLogger(WatchedFolder.class);
     
     /** Upon activation, find folders to watch under our roots, and observe those
      *  roots to detect new folders to watch.
      */
     protected void activate(ComponentContext context) throws RepositoryException {
+    	
+    	// TODO make this configurable
+    	final String [] roots = DEFAULT_ROOTS; 
+    	folderNameFilter = new FolderNameFilter(DEFAULT_FOLDER_NAME_REGEXP);
+    	
+        // Listen for any new WatchedFolders created after activation
+        session = repository.loginAdministrative(repository.getDefaultWorkspace());
+        final int eventTypes = Event.NODE_ADDED;
+        final boolean isDeep = true;
+        final boolean noLocal = true;
+        for (String path : roots) {
+            final WatchedFolderCreationListener w = new WatchedFolderCreationListener(folderNameFilter);
+            listeners.add(w);
+            session.getWorkspace().getObservationManager().addEventListener(w, eventTypes, path,
+                    isDeep, null, null, noLocal);
+        }
+
         folders = new HashSet<WatchedFolder>();
         
-        for(String root : DEFAULT_ROOTS) {
+        for(String root : roots) {
             folders.addAll(findWatchedFolders(root));
         }
+        
     }
     
     protected void deactivate(ComponentContext oldContext) {
+    	
+    	for(WatchedFolder f : folders) {
+    		f.cleanup();
+    	}
+    	
+    	if(session != null) {
+	    	for(WatchedFolderCreationListener w : listeners) {
+	    		try {
+		        	session.getWorkspace().getObservationManager().removeEventListener(w);
+	    		} catch(RepositoryException re) {
+	    			log.warn("RepositoryException in removeEventListener call", re);
+	    		}
+	    	}
+	    	
+	    	session.logout();
+	    	session = null;
+    	}
+    	
+    	listeners.clear();
         folders.clear();
     }
+    
+    /** Add WatchedFolders that have been discovered by our WatchedFolderCreationListeners, if any */
+    void addNewWatchedFolders() {
+    	for(WatchedFolderCreationListener w : listeners) {
+    		final Set<String> paths = w.getAndClearPaths();
+    		if(paths != null) {
+    			for(String path : paths) {
+    				folders.add(new WatchedFolder(path, osgiController));
+    			}
+    		}
+    	}
+    }
 
     /** Find all folders to watch under rootPath 
      * @throws RepositoryException */

Modified: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolder.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolder.java?rev=693467&r1=693466&r2=693467&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolder.java (original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolder.java Tue Sep  9 07:11:23 2008
@@ -38,6 +38,15 @@
         log.info("Watching folder " + path);
     }
     
+    void cleanup() {
+    	// TODO stop listening to events
+    }
+    
+    @Override
+    public String toString() {
+    	return getClass().getSimpleName() + ":" + path;
+    }
+    
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof WatchedFolder)) {

Added: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java?rev=693467&view=auto
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java (added)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java Tue Sep  9 07:11:23 2008
@@ -0,0 +1,75 @@
+/*
+ * 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.jcrinstall.jcr.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Listen for JCR events to find out when new WatchedFolders
+ * 	must be created.
+ */
+class WatchedFolderCreationListener implements EventListener {
+    protected final Logger log = LoggerFactory.getLogger(this.getClass());
+    private final FolderNameFilter folderNameFilter;
+    private Set<String> paths = new HashSet<String>();
+    
+    WatchedFolderCreationListener(FolderNameFilter fnf) {
+    	folderNameFilter = fnf;
+	}
+    
+    /** Return our saved paths and clear the list
+     * 	@return null if no paths have been saved 
+     */
+    Set<String> getAndClearPaths() {
+    	if(paths.isEmpty()) {
+    		return null;
+    	}
+    	
+        synchronized(paths) {
+            Set<String> result = paths; 
+            paths = new HashSet<String>();
+            return result;
+        }
+    }
+    
+    /** Store the paths of new WatchedFolders to create */
+    public void onEvent(EventIterator it) {
+        try {
+            while(it.hasNext()) {
+                final Event e = it.nextEvent();
+                if(folderNameFilter.accept(e.getPath())) {
+                    synchronized(paths) {
+                        paths.add(e.getPath());
+                    }
+                }
+            }
+        } catch(RepositoryException re) {
+            log.warn("RepositoryException in onEvent", re);
+        }
+    }
+
+}

Propchange: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/WatchedFolderCreationListener.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java?rev=693467&r1=693466&r2=693467&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java (original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java Tue Sep  9 07:11:23 2008
@@ -19,27 +19,42 @@
 package org.apache.sling.jcr.jcrinstall.jcr.impl;
 
 import java.lang.reflect.Field;
-import java.util.HashSet;
 import java.util.Set;
 
 import javax.jcr.Node;
+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.commons.testing.jcr.RepositoryTestBase;
 import org.apache.sling.jcr.api.SlingRepository;
 
 /** Test the "find watched folders" feature of the RepositoryObserver */
-public class FindWatchedFoldersTest extends RepositoryTestBase {
+public class FindWatchedFoldersTest extends RepositoryTestBase implements EventListener {
     
     SlingRepository repo;
     Session session;
+    String eventPathToWatch;
+    int eventCount;
+    
+    private static final String [] WATCHED_FOLDERS = {
+            "libs/foo/bar/install",
+            "libs/foo/wii/install",
+            "apps/install"
+    };
+    
+    private static final String [] IGNORED_FOLDERS = {
+            "libs/foo/bar/installed",
+            "apps/noninstall"
+    };
     
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
-        
-        session.getRootNode().getNode("libs").remove();
-        session.getRootNode().getNode("apps").remove();
+        session.getWorkspace().getObservationManager().removeEventListener(this);
+        cleanupContent();
         session.logout();
     }
 
@@ -48,46 +63,117 @@
         super.setUp();
         repo = getRepository();
         session = repo.loginAdministrative(repo.getDefaultWorkspace());
-    }
-
-    @SuppressWarnings("unchecked")
-    public void testInitialFind() throws Exception {
-        final String [] folders = {
-                "libs/foo/bar/install",
-                "libs/foo/wii/install",
-                "apps/install"
-        };
-        final String [] foldersToIgnore = {
-                "libs/foo/bar/installed",
-                "apps/noninstall"
-        };
+        cleanupContent();
         
-        for(String folder : folders) {
+        final int eventTypes = Event.NODE_ADDED;
+        final boolean isDeep = true;
+        final boolean noLocal = false;
+        session.getWorkspace().getObservationManager().addEventListener(
+        		this, eventTypes, "/", isDeep, null, null, noLocal);
+    }
+    
+    void cleanupContent() throws Exception {
+    	final String [] paths = { "libs", "apps" }; 
+    	for(String path : paths) {
+            if(session.getRootNode().hasNode(path)) {
+                session.getRootNode().getNode(path).remove();
+            }
+    	}
+    }
+    
+    void setupContent() throws Exception {
+    	cleanupContent();
+        for(String folder : WATCHED_FOLDERS) {
             createFolder(folder);
         }
-        for(String folder : foldersToIgnore) {
+        for(String folder : IGNORED_FOLDERS) {
             createFolder(folder);
         }
-        
-        final FolderNameFilter filter = new FolderNameFilter(".*/install$");
-        final RepositoryObserver ro = createRepositoryObserver(filter);
+    }
+    
+    public void onEvent(EventIterator it) {
+        try {
+            while(it.hasNext()) {
+                final Event e = it.nextEvent();
+                if(e.getPath().equals(eventPathToWatch)) {
+                	eventCount++;
+                }
+            }
+        } catch(RepositoryException ignored) {
+            // ignore
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testInitialFind() throws Exception {
+    	
+    	setupContent();
+        final RepositoryObserver ro = createRepositoryObserver();
         ro.activate(null);
         
-        final Field f = ro.getClass().getDeclaredField("folders");
-        f.setAccessible(true);
-        final Set<WatchedFolder> wfSet = (Set<WatchedFolder>)f.get(ro);
-        assertEquals("activate() must find all watched folders", folders.length, wfSet.size());
+        final Set<WatchedFolder> wfSet = getWatchedFolders(ro);
+        assertEquals("activate() must find all watched folders", WATCHED_FOLDERS.length, wfSet.size());
         
-        final Set<String> paths = new HashSet<String>();
-        for(WatchedFolder wf : wfSet) {
-            paths.add(wf.getPath());
-        }
-        for(String folder : folders) {
-            assertTrue("Folder " + folder + " must be watched (watched=" + paths + ")", 
-                    paths.contains("/" + folder)); 
+        for(String folder : WATCHED_FOLDERS) {
+            assertTrue("Folder " + folder + " must be watched (watched=" + wfSet + ")", 
+                    folderIsWatched(ro, folder)); 
+        }
+    }
+    
+    public void testNewWatchedFolderDetection() throws Exception {
+    	setupContent();
+        final RepositoryObserver ro = createRepositoryObserver();
+        ro.activate(null);
+
+        final String newPaths [] = { "libs/tnwf/install", "apps/tnwf/install" };
+        for(String newPath : newPaths) {
+            assertFalse(newPath + " must not be watched before test", folderIsWatched(ro, newPath));
+            
+            // Create folder, wait for observation event and check that
+            // it is detected
+            final int ec = eventCount;
+            eventPathToWatch = "/" + newPath;
+            createFolder(newPath);
+            waitForEventCount(ec + 1, 5000L);
+            assertFalse(newPath + " must not be watched before calling addNewWatchedFolders()", folderIsWatched(ro, newPath));
+            ro.addNewWatchedFolders();
+            assertTrue(newPath + " must be watched before calling addNewWatchedFolders()", folderIsWatched(ro, newPath));
         }
     }
     
+    void waitForEventCount(int count, long timeoutMsec) {
+    	final long end = System.currentTimeMillis() + timeoutMsec;
+    	while(eventCount < count && System.currentTimeMillis() < end) {
+    		try {
+    			Thread.sleep(100);
+    		} catch(InterruptedException ignored) {
+    		}
+    	}
+    	
+    	if(eventCount < count) {
+    		throw new IllegalStateException("Event counter did not reach " + count + ", waited " + timeoutMsec + " msec");
+    	}
+    }
+    
+    @SuppressWarnings("unchecked")
+	Set<WatchedFolder> getWatchedFolders(RepositoryObserver ro) throws Exception {
+        final Field f = ro.getClass().getDeclaredField("folders");
+        f.setAccessible(true);
+        return (Set<WatchedFolder>)f.get(ro);
+    }
+    
+    boolean folderIsWatched(RepositoryObserver ro, String path) throws Exception {
+    	boolean result = false;
+    	final Set<WatchedFolder> wfSet = getWatchedFolders(ro);
+    	for(WatchedFolder wf : wfSet) {
+    		if(wf.getPath().equals("/" + path)) {
+    			result = true;
+    			break;
+    		}
+    	}
+    	return result;
+    }
+    
     void createFolder(String path) throws Exception {
         final String [] parts = path.split("/");
         Node n = session.getRootNode();
@@ -101,10 +187,9 @@
         session.save();
     }
     
-    RepositoryObserver createRepositoryObserver(FolderNameFilter filter) throws Exception {
+    RepositoryObserver createRepositoryObserver() throws Exception {
         final RepositoryObserver result = new RepositoryObserver();
         setField(result, "repository", repo);
-        setField(result, "folderNameFilter", filter);
         return result;
     }