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 2009/08/25 16:06:38 UTC

svn commit: r807639 - in /sling/trunk/installer/jcr/jcrinstall/src: main/java/org/apache/sling/jcr/jcrinstall/impl/ test/java/org/apache/sling/jcr/jcrinstall/impl/ test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/

Author: bdelacretaz
Date: Tue Aug 25 14:06:37 2009
New Revision: 807639

URL: http://svn.apache.org/viewvc?rev=807639&view=rev
Log:
SLING-1078 - FindPathsToWatchTest and support classes added

Added:
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java
      - copied, changed from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/EventHelper.java
      - copied, changed from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java
      - copied, changed from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java   (with props)
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockInstallableResource.java
      - copied, changed from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockInstallableData.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java   (with props)
Removed:
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockInstallableData.java
Modified:
    sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
    sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java
    sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java

Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java?rev=807639&r1=807638&r2=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java Tue Aug 25 14:06:37 2009
@@ -18,20 +18,20 @@
  */
 package org.apache.sling.jcr.jcrinstall.impl;
 
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 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 org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
 import org.apache.sling.osgi.installer.InstallableResource;
 import org.apache.sling.osgi.installer.OsgiInstaller;
 import org.apache.sling.runmode.RunMode;
@@ -56,7 +56,7 @@
  *      name="service.vendor"
  *      value="The Apache Software Foundation"
  */
-public class JcrInstaller implements Serializable {
+public class JcrInstaller implements Runnable {
 	private static final long serialVersionUID = 1L;
 	public static final String URL_SCHEME = "jcrinstall";
 
@@ -110,6 +110,12 @@
     /** Session shared by all WatchedFolder */
     private Session session;
     
+    /** Count cycles of our run() method, used in testing */
+    private int cyclesCount;
+    
+    /** Used to stop background thread when deactivated */
+    private int deactivationCounter = 1;
+    
     /** Convert Nodes to InstallableResources */
     static interface NodeConverter {
     	InstallableResource convertNode(String urlScheme, Node n) throws Exception;
@@ -118,6 +124,9 @@
     /** Our NodeConverters*/
     private final Collection <NodeConverter> converters = new ArrayList<NodeConverter>();
     
+    /** Detect newly created folders that we must watch */
+    private final List<WatchedFolderCreationListener> listeners = new LinkedList<WatchedFolderCreationListener>();
+    
     protected void activate(ComponentContext context) throws Exception {
     	
     	session = repository.loginAdministrative(repository.getDefaultWorkspace());
@@ -156,8 +165,13 @@
             log.info("Using default folder name regexp '{}', not provided by {}", folderNameRegexp, FOLDER_NAME_REGEXP_PROPERTY);
     	}
     	
+    	// Setup folder filtering and watching
+        folderNameFilter = new FolderNameFilter(roots, folderNameRegexp, runMode);
+        for (String path : roots) {
+            listeners.add(new WatchedFolderCreationListener(session, folderNameFilter, path));
+        }
+        
     	// Find paths to watch and create WatchedFolders to manage them
-    	folderNameFilter = new FolderNameFilter(roots, folderNameRegexp, runMode);
     	watchedFolders = new LinkedList<WatchedFolder>();
     	for(String root : roots) {
     		findPathsToWatch(root, watchedFolders);
@@ -173,16 +187,29 @@
     	
     	log.info("Registering {} resources with OSGi installer", resources.size());
     	installer.registerResources(resources, URL_SCHEME);
+    	
+    	final Thread t = new Thread(this, getClass().getSimpleName() + "." + deactivationCounter);
+    	t.setDaemon(true);
+    	t.start();
     }
     
     protected void deactivate(ComponentContext context) {
-    	folderNameFilter = null;
-    	watchedFolders = null;
-    	converters.clear();
-    	if(session != null) {
-    		session.logout();
-    		session = null;
-    	}
+        try {
+            deactivationCounter++;
+            listeners.clear();
+            folderNameFilter = null;
+            watchedFolders = null;
+            converters.clear();
+            if(session != null) {
+                for(WatchedFolderCreationListener wfc : listeners) {
+                    wfc.cleanup(session);
+                }
+                session.logout();
+                session = null;
+            }
+        } catch(Exception e) {
+            log.warn("Exception in deactivate()", e);
+        }
     }
     
     /** Get a property value from the component context or bundle context */
@@ -206,7 +233,7 @@
             } else {
                 log.debug("Bundles root node {} found, looking for bundle folders inside it", rootPath);
                 final Node n = s.getRootNode().getNode(relPath(rootPath));
-                findAndAddPaths(n, result);
+                findPathsUnderNode(n, result);
             }
         } finally {
             if (s != null) {
@@ -219,7 +246,7 @@
      * Add n to result if it is a folder that we must watch, and recurse into its children
      * to do the same.
      */
-    void findAndAddPaths(Node n, List<WatchedFolder> result) throws RepositoryException
+    void findPathsUnderNode(Node n, List<WatchedFolder> result) throws RepositoryException
     {
         final String path = n.getPath();
         final int priority = folderNameFilter.getPriority(path); 
@@ -233,7 +260,7 @@
         } else {
             final NodeIterator it = n.getNodes();
             while (it.hasNext()) {
-                findAndAddPaths(it.nextNode(), result);
+                findPathsUnderNode(it.nextNode(), result);
             }
         }
     }
@@ -247,5 +274,64 @@
         }
         return path;
     }
+    
+    /** Add new folders to watch if any have been detected
+     *  @return true if any WatchedFolders have been removed 
+     */ 
+    private boolean addAndDeleteFolders() throws RepositoryException {
+        for(WatchedFolderCreationListener wfc : listeners) {
+            final Set<String> newPaths = wfc.getAndClearPaths();
+            if(newPaths != null && newPaths.size() > 0) {
+                log.info("Detected {} new folder(s to watch", newPaths.size());
+                for(String path : newPaths) {
+                    watchedFolders.add(
+                            new WatchedFolder(session, path, folderNameFilter.getPriority(path), URL_SCHEME, converters));
+                }
+            }
+        }
+        
+        boolean deleted = false;
+        final List<WatchedFolder> toRemove = new ArrayList<WatchedFolder>();
+        for(WatchedFolder wf : watchedFolders) {
+            if(!session.itemExists(wf.getPath())) {
+                deleted = true;
+                log.info("Deleting {}, path does not exist anymore", wf);
+                wf.cleanup();
+                toRemove.add(wf);
+            }
+        }
+        for(WatchedFolder wf : toRemove) {
+            watchedFolders.remove(wf);
+        }
+        
+        return deleted;
+    }
+    
+    /** Run periodic scans of our watched folders, and watch for folders creations/deletions */
+    public void run() {
+        log.info("Background thread {} starting", Thread.currentThread().getName());
+        final int savedCounter = deactivationCounter;
+        while(savedCounter == deactivationCounter) {
+            try {
+                // TODO rendezvous with installer if any folder has been deleted
+                addAndDeleteFolders();
+                cyclesCount++;
+
+                // TODO wait for events from our listeners, and/or WatchedFolder scan time
+                try {
+                    Thread.sleep(500L);
+                } catch(InterruptedException ignore) {
+                }
+                
+            } catch(Exception e) {
+                log.warn("Exception in run()", e);
+                try {
+                    Thread.sleep(1000L);
+                } catch(InterruptedException ignore) {
+                }
+            }
+        }
+        log.info("Background thread {} stopping", Thread.currentThread().getName());
+    }
 
 }
\ No newline at end of file

Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java?rev=807639&r1=807638&r2=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java Tue Aug 25 14:06:37 2009
@@ -70,7 +70,7 @@
         session.getWorkspace().getObservationManager().addEventListener(this, eventTypes, path,
                 isDeep, null, null, noLocal);
 
-        log.info("Watching folder " + path);
+        log.info("Watching folder {} (priority {})", path, priority);
     }
     
     void cleanup() {

Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java?rev=807639&r1=807638&r2=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java Tue Aug 25 14:06:37 2009
@@ -21,6 +21,9 @@
 import java.util.HashSet;
 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;
 
@@ -29,11 +32,25 @@
 
 /** Listen for JCR events to find out when new WatchedFolders
  * 	must be created.
- * 	TODO reactivate
  */
 class WatchedFolderCreationListener implements EventListener {
     protected final Logger log = LoggerFactory.getLogger(this.getClass());
     private Set<String> paths = new HashSet<String>();
+    private final FolderNameFilter folderNameFilter;
+    
+    WatchedFolderCreationListener(Session session, FolderNameFilter fnf, String path) throws RepositoryException {
+        folderNameFilter = fnf;
+        
+        int eventTypes = Event.NODE_ADDED;
+        boolean isDeep = true;
+        boolean noLocal = true;
+        session.getWorkspace().getObservationManager().addEventListener(this, eventTypes, path,
+                isDeep, null, null, noLocal);
+    }
+    
+    void cleanup(Session session) throws RepositoryException {
+        session.getWorkspace().getObservationManager().removeEventListener(this);
+    }
     
     /** Return our saved paths and clear the list
      * 	@return null if no paths have been saved 
@@ -52,11 +69,10 @@
     
     /** 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())) {
+                if(folderNameFilter.getPriority(e.getPath()) > 0) {
                     synchronized(paths) {
                         paths.add(e.getPath());
                     }
@@ -65,7 +81,5 @@
         } catch(RepositoryException re) {
             log.warn("RepositoryException in onEvent", re);
         }
-        */
     }
-
 }

Copied: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java (from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java)
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java?p2=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java&p1=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java&r1=807539&r2=807639&rev=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java Tue Aug 25 14:06:37 2009
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.jcrinstall.jcr.impl;
+package org.apache.sling.jcr.jcrinstall.impl;
 
 import java.io.InputStream;
 import java.util.Calendar;
@@ -25,7 +25,7 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
-/** TODO adapt or remove */
+/** Utility class used to create test content */
 class ContentHelper {
     public static final String NT_FOLDER = "nt:folder";
     public static final String NT_FILE = "nt:file";
@@ -37,14 +37,14 @@
     public static final String JCR_DATA = "jcr:data";
     
     final String [] WATCHED_FOLDERS = {
-        "libs/foo/bar/install",
-        "libs/foo/wii/install",
-        "apps/install"
+        "/libs/foo/bar/install",
+        "/libs/foo/wii/install",
+        "/apps/install"
     };
 
     final String [] IGNORED_FOLDERS = {
-        "libs/foo/bar/installed",
-        "apps/noninstall"
+        "/libs/foo/bar/installed",
+        "/apps/noninstall"
     };
     
     private final Session session;
@@ -73,7 +73,7 @@
     }
     
     void createFolder(String path) throws Exception {
-        final String [] parts = path.split("/");
+        final String [] parts = relPath(path).split("/");
         Node n = session.getRootNode();
         for(String part : parts) {
             if(n.hasNode(part)) {
@@ -85,14 +85,17 @@
         session.save();
     }
     
-    void createOrUpdateFile(String path, MockInstallableData d) throws RepositoryException {
-    	/*
-    	createOrUpdateFile(path, d.adaptTo(InputStream.class), d.getLastModified());
-    	*/
+    void delete(String path) throws RepositoryException {
+        session.getItem(path).remove();
+        session.save();
+    }
+    
+    void createOrUpdateFile(String path, MockInstallableResource d) throws RepositoryException {
+    	createOrUpdateFile(path, d.getInputStream(), System.currentTimeMillis());
     }
     
     void createOrUpdateFile(String path, InputStream data, long lastModified) throws RepositoryException {
-        final String relPath = path.substring(1);
+        final String relPath = relPath(path);
         Node f = null;
         Node res = null;
         if(session.getRootNode().hasNode(relPath)) {
@@ -111,4 +114,11 @@
         
         f.getParent().save();
     }
+    
+    String relPath(String path) {
+        if(path.startsWith("/")) {
+            return path.substring(1);
+        }
+        return path;
+    }
 }
\ No newline at end of file

Copied: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/EventHelper.java (from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java)
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/EventHelper.java?p2=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/EventHelper.java&p1=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java&r1=807539&r2=807639&rev=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/EventHelper.java Tue Aug 25 14:06:37 2009
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.jcrinstall.jcr.impl;
+package org.apache.sling.jcr.jcrinstall.impl;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -28,7 +28,6 @@
 /** Used by tests to wait until JCR notification events
  * 	have been delivered.
  */
-/** TODO remove if not needed for new tests */
 class EventHelper implements EventListener {
 	private final Session session;
 	private int eventCount;

Copied: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java (from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java)
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java?p2=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java&p1=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java&r1=807539&r2=807639&rev=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FindWatchedFoldersTest.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java Tue Aug 25 14:06:37 2009
@@ -16,24 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.jcrinstall.jcr.impl;
+package org.apache.sling.jcr.jcrinstall.impl;
+
+import java.util.Collection;
+
+import javax.jcr.Session;
 
 import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
+import org.apache.sling.jcr.api.SlingRepository;
 
-/** Test the "find watched folders" feature of the RepositoryObserver 
- * 	TODO adapt or remove
- * */
-public class FindWatchedFoldersTest extends RepositoryTestBase {
+/** Verify that the JcrInstaller finds all folders that must
+ *  be watched, including those created after it starts  
+ */
+public class FindPathsToWatchTest extends RepositoryTestBase {
     
-	public void testNothing() {}
-	
-	/*
     SlingRepository repo;
     Session session;
     private EventHelper eventHelper; 
     private ContentHelper contentHelper;
-    private Mockery mockery;
-    private OsgiController osgiController;
+    private JcrInstaller installer;
+    private MockOsgiInstaller osgiInstaller;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        repo = getRepository();
+        session = repo.loginAdministrative(repo.getDefaultWorkspace());
+        eventHelper = new EventHelper(session);
+        contentHelper = new ContentHelper(session);
+        contentHelper.cleanupContent();
+        contentHelper.setupContent();
+        osgiInstaller = new MockOsgiInstaller();
+        installer = MiscUtil.getJcrInstaller(repo, osgiInstaller);
+    }
     
     @Override
     protected void tearDown() throws Exception {
@@ -44,56 +59,71 @@
         contentHelper = null;
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        repo = getRepository();
-        session = repo.loginAdministrative(repo.getDefaultWorkspace());
-        eventHelper = new EventHelper(session);
-        contentHelper = new ContentHelper(session);
-        contentHelper.cleanupContent();
-        mockery = new Mockery();
-        osgiController = mockery.mock(OsgiController.class);
-        final Set<String> installedUri = new HashSet<String>();
-        mockery.checking(new Expectations() {{
-            allowing(osgiController).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(osgiController).getInstalledUris(); will(returnValue(installedUri));
-            allowing(osgiController).executeScheduledOperations();
-        }});
+    private boolean isWatched(String path, Collection<WatchedFolder> wfList) {
+        for(WatchedFolder wf : wfList ) {
+            if(wf.getPath().equals(path)) {
+                return true;
+            }
+        }
+        return false;
     }
     
     public void testInitialFind() throws Exception {
-    	
-    	contentHelper.setupContent();
-        final MockRepositoryObserver ro = new MockRepositoryObserver(repo, osgiController);
-        ro.activate(null);
-        
-        final Set<WatchedFolder> wfSet = ro.getWatchedFolders();
-        assertEquals("activate() must find all watched folders", contentHelper.WATCHED_FOLDERS.length, wfSet.size());
+        final Collection<WatchedFolder> wf = MiscUtil.getWatchedFolders(installer);
+        assertEquals("activate() must find all watched folders", contentHelper.WATCHED_FOLDERS.length, wf.size());
         
         for(String folder : contentHelper.WATCHED_FOLDERS) {
-            assertTrue("Folder " + folder + " must be watched (watched=" + wfSet + ")", 
-                    ro.folderIsWatched(folder)); 
+            assertTrue("Folder " + folder + " must be watched (watched=" + wf + ")", 
+                    isWatched(folder, wf));
         }
     }
     
     public void testNewWatchedFolderDetection() throws Exception {
-    	contentHelper.setupContent();
-        final MockRepositoryObserver ro = new MockRepositoryObserver(repo, osgiController);
-        ro.activate(null);
-
-        final String newPaths [] = { "libs/tnwf/install", "apps/tnwf/install" };
+        final String newPaths [] = { 
+                "/libs/tnwf/install", 
+                "/libs/tnwf/install.dev", 
+                "/apps/tnwf/install", 
+                "/apps/tnwf/install.staging", 
+                "/apps/tnwf/install.staging.dev", 
+                "/NOT/foo/nothing"
+        };
         for(String newPath : newPaths) {
-            assertFalse(newPath + " must not be watched before test", ro.folderIsWatched(newPath));
+            assertFalse(newPath + " must not be watched before test", isWatched(newPath, 
+                    MiscUtil.getWatchedFolders(installer)));
             
             // Create folder, wait for observation event and check that
             // it is detected
             contentHelper.createFolder(newPath);
             eventHelper.waitForEvents(5000L);
-            assertFalse(newPath + " must not be watched before calling addNewWatchedFolders()", ro.folderIsWatched(newPath));
-            ro.addNewWatchedFolders();
-            assertTrue(newPath + " must be watched before calling addNewWatchedFolders()", ro.folderIsWatched(newPath));
+            MiscUtil.waitForCycles(installer, 2, 5000L);
+            
+            if(newPath.contains("NOT")) {
+                assertFalse(newPath + " must not be watched after test", isWatched(newPath, 
+                        MiscUtil.getWatchedFolders(installer)));
+            } else {
+                assertTrue(newPath + " must be watched after calling addNewWatchedFolders()", isWatched(newPath, 
+                        MiscUtil.getWatchedFolders(installer)));
+            }
         }
+        
+        // Delete a single folder and verify that it's gone
+        final String folder = newPaths[1];
+        final int nBefore = MiscUtil.getWatchedFolders(installer).size();
+        contentHelper.delete(folder);
+        eventHelper.waitForEvents(5000L);
+        MiscUtil.waitForCycles(installer, 2, 5000L);
+        assertFalse(folder + " must not be watched anymore after deleting", isWatched(folder, 
+                MiscUtil.getWatchedFolders(installer)));
+       assertEquals("Expecting only one WatchedFolder to be deleted", nBefore - 1,
+               MiscUtil.getWatchedFolders(installer).size());
+    }
+    
+    public void testDeleteWatchedFolders() throws Exception {
+        final Collection<WatchedFolder> wf = MiscUtil.getWatchedFolders(installer);
+        assertEquals("activate() must find all watched folders", contentHelper.WATCHED_FOLDERS.length, wf.size());
+        contentHelper.cleanupContent();
+        eventHelper.waitForEvents(5000L);
+        MiscUtil.waitForCycles(installer, 2, 5000L);
+        assertEquals("After deleting content, no more folders must be watched", 0, wf.size());
     }
-    */   
 }
\ No newline at end of file

Added: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java?rev=807639&view=auto
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java (added)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java Tue Aug 25 14:06:37 2009
@@ -0,0 +1,152 @@
+/*
+ * 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.impl;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.jcr.Session;
+import javax.servlet.http.HttpServletRequest;
+
+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.apache.sling.osgi.installer.OsgiInstaller;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+/** JcrInstall test utilities */
+class MiscUtil {
+
+    public static String SEARCH_PATHS [] = { "/libs/", "/apps/" };
+    public static String RUN_MODES [] = { "dev", "staging" };
+    
+    static class MockResourceResolver implements ResourceResolver {
+
+        public Iterator<Resource> findResources(String arg0, String arg1) {
+            return null;
+        }
+
+        public Resource getResource(Resource arg0, String arg1) {
+            return null;
+        }
+
+        public Resource getResource(String arg0) {
+            return null;
+        }
+
+        public String[] getSearchPath() {
+            return SEARCH_PATHS;
+        }
+
+        public Iterator<Resource> listChildren(Resource arg0) {
+            return null;
+        }
+
+        public String map(String arg0) {
+            return null;
+        }
+
+        public Iterator<Map<String, Object>> queryResources(String arg0,
+                String arg1) {
+            return null;
+        }
+
+        public Resource resolve(HttpServletRequest arg0) {
+            return null;
+        }
+
+        public Resource resolve(String arg0) {
+            return null;
+        }
+
+        public <AdapterType> AdapterType adaptTo(Class<AdapterType> arg0) {
+            return null;
+        }
+    }
+    
+    static class MockJcrResourceResolverFactory implements JcrResourceResolverFactory {
+
+        public ResourceResolver getResourceResolver(Session arg0) {
+            return new MockResourceResolver();
+        }
+    }
+    
+    /** Set a non-public Field */
+    static void setField(Object target, String fieldName, Object value) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
+        final Field f = target.getClass().getDeclaredField(fieldName);
+        f.setAccessible(true);
+        f.set(target, value);
+    }
+    
+    /** Return a JcrInstaller setup for testing */ 
+    static JcrInstaller getJcrInstaller(SlingRepository repository, OsgiInstaller osgiInstaller) throws Exception {
+        // Setup fake ComponentContext to allow JcrInstaller to start
+        final Mockery m = new Mockery();
+        final ComponentContext cc = m.mock(ComponentContext.class);
+        final BundleContext bc = m.mock(BundleContext.class);
+        
+        final Dictionary<String, Object> emptyDict = new Hashtable<String, Object>();
+        m.checking(new Expectations() {{
+            allowing(cc).getProperties();
+            will(returnValue(emptyDict));
+            allowing(cc).getBundleContext();
+            will(returnValue(bc));
+            allowing(bc).getProperty(with(any(String.class)));
+            will(returnValue(null));
+        }});
+        
+        final JcrInstaller installer = new JcrInstaller();
+        setField(installer, "repository", repository);
+        setField(installer, "resourceResolverFactory", new MockJcrResourceResolverFactory());
+        setField(installer, "installer", osgiInstaller);
+        setField(installer, "runMode", new MockRunMode(RUN_MODES));
+
+        installer.activate(cc);
+        return installer;
+    }
+    
+    static void waitForCycles(JcrInstaller installer, int nCycles, long timeoutMsec) throws Exception {
+        final Field f = installer.getClass().getDeclaredField("cyclesCount");
+        f.setAccessible(true);
+        final int endCycles = ((Integer)f.get(installer)).intValue() + nCycles;
+        final long endTime = System.currentTimeMillis() + timeoutMsec;
+        while(System.currentTimeMillis() < endTime) {
+            if(((Integer)f.get(installer)).intValue() > endCycles) {
+                return;
+            }
+        }
+        throw new Exception("did not get " + nCycles + " installer cycles in " + timeoutMsec + " msec"); 
+    }
+    
+    /** Get the WatchedFolders of supplied JcrInstaller */
+    @SuppressWarnings({ "unchecked"})
+    static Collection<WatchedFolder> getWatchedFolders(JcrInstaller installer) throws Exception {
+        final Field f = installer.getClass().getDeclaredField("watchedFolders");
+        f.setAccessible(true);
+        return (Collection<WatchedFolder>)f.get(installer);
+    }
+}

Propchange: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Copied: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockInstallableResource.java (from r807539, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockInstallableData.java)
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockInstallableResource.java?p2=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockInstallableResource.java&p1=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockInstallableData.java&r1=807539&r2=807639&rev=807639&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockInstallableData.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockInstallableResource.java Tue Aug 25 14:06:37 2009
@@ -16,65 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.jcrinstall.jcr.impl;
+package org.apache.sling.jcr.jcrinstall.impl;
 
+import java.io.ByteArrayInputStream;
 
-/** TODO adapt or remove */
-public class MockInstallableData /* implements InstallableData */ {
+import org.apache.sling.osgi.installer.InstallableResource;
 
-	/*
-	private final InputStream inputStream;
-	private long lastModified;
-	private String digest;
-	private static int counter;
-	
-    public MockInstallableData(String uri) {
-        this(uri, uri);
+public class MockInstallableResource extends InstallableResource {
+
+    private static int counter;
+    
+    public MockInstallableResource(String uri) {
+        this(uri, "", null);
     }
     
-	public MockInstallableData(String uri, String data) {
-        inputStream = new ByteArrayInputStream(data.getBytes());
-        lastModified = System.currentTimeMillis() + counter;
-        counter++;
-        digest = String.valueOf(lastModified);
-	}
-	
-	@Override
-	public boolean equals(Object obj) {
-		if(obj instanceof MockInstallableData) {
-			final MockInstallableData other = (MockInstallableData)obj;
-			return digest.equals(other.digest);
-		}
-		return false;
-	}
-	
-	public long getLastModified() {
-		return lastModified;
-	}
-
-	@Override
-	public int hashCode() {
-		return digest.hashCode();
-	}
-
-	@SuppressWarnings("unchecked")
-	public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
-		if(type.equals(InputStream.class)) {
-			return (AdapterType)inputStream;
-		}
-		return null;
-	}
-
-	void setDigest(String d) {
-		digest = d;
-	}
-	
-	public String getDigest() {
-		return digest;
-	}
-
-    public int getBundleStartLevel() {
-        return 0;
+    public MockInstallableResource(String uri, String data, String digest) {
+        super(uri, new ByteArrayInputStream(data.getBytes()), getNextDigest(digest));
     }
-    */
+    
+    static String getNextDigest(String digest) {
+        if(digest != null) {
+            return digest;
+        }
+        synchronized (MockInstallableResource.class) {
+            return String.valueOf(System.currentTimeMillis() + (counter++));
+        }
+    }    
 }

Added: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java?rev=807639&view=auto
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java (added)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java Tue Aug 25 14:06:37 2009
@@ -0,0 +1,42 @@
+/*
+ * 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.impl;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.sling.osgi.installer.InstallableResource;
+import org.apache.sling.osgi.installer.OsgiInstaller;
+
+class MockOsgiInstaller implements OsgiInstaller {
+
+    public void addResource(InstallableResource d) throws IOException {
+    }
+
+    public long[] getCounters() {
+        return null;
+    }
+
+    public void registerResources(Collection<InstallableResource> data,
+            String urlScheme) throws IOException {
+    }
+
+    public void removeResource(InstallableResource d) throws IOException {
+    }
+}

Propchange: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL