Author: bdelacretaz
Date: Wed Sep 10 02:58:25 2008
New Revision: 693761

URL: http://svn.apache.org/viewvc?rev=693761&view=rev
Log:
SLING-646 - work in progress, ResourceDetectionTest implemented

Added:
    
incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FileDataProvider.java
   (with props)
    
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java
   (with props)
    
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java
   (with props)
    
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MiscHelper.java
   (with props)
    
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.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

Added: 
incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FileDataProvider.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FileDataProvider.java?rev=693761&view=auto
==============================================================================
--- 
incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FileDataProvider.java
 (added)
+++ 
incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/FileDataProvider.java
 Wed Sep 10 02:58:25 2008
@@ -0,0 +1,67 @@
+/*
+ * 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.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/** Provides data (InputStream, last modified data) about
+ *     JCR nodes which are files.
+ *     TODO: Yes, this should be a generic JCR utility.
+ */
+class FileDataProvider {
+    /**
+     * The relative path of the data and last modified date of an nt:file node
+     */
+    public static final String JCR_CONTENT = "jcr:content";
+    public static final String JCR_CONTENT_DATA = JCR_CONTENT + "/jcr:data";
+    public static final String JCR_LAST_MODIFIED = "jcr:lastModified";
+    public static final String JCR_CONTENT_LAST_MODIFIED = JCR_CONTENT + "/" + 
JCR_LAST_MODIFIED;
+    
+    private final InputStream inputStream;
+    private final long lastModified;
+    
+       FileDataProvider(Node n) throws RepositoryException {
+        if (n.hasProperty(JCR_CONTENT_LAST_MODIFIED)) {
+               lastModified = 
n.getProperty(JCR_CONTENT_LAST_MODIFIED).getDate().getTimeInMillis();
+        } else {
+               lastModified = -1;
+           }
+           
+        if(n.hasProperty(JCR_CONTENT_DATA)) {
+               inputStream = n.getProperty(JCR_CONTENT_DATA).getStream();
+        } else {
+               inputStream = null;
+        }
+       }
+       
+       boolean isFile() {
+               return inputStream != null && lastModified != -1;
+       }
+
+       InputStream getInputStream() {
+               return inputStream;
+       }
+
+       long getLastModified() {
+               return lastModified;
+       }
+}

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

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

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=693761&r1=693760&r2=693761&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
 Wed Sep 10 02:58:25 2008
@@ -63,6 +63,9 @@
     /** Default regexp for watched folders */
     public static final String DEFAULT_FOLDER_NAME_REGEXP = ".*/install$";
     
+    /** Scan delay for watched folders */
+    private final long scanDelayMsec = 1000L;
+    
     protected static final Logger log = 
LoggerFactory.getLogger(WatchedFolder.class);
     
     /** Upon activation, find folders to watch under our roots, and observe 
those
@@ -118,12 +121,12 @@
     }
     
     /** Add WatchedFolders that have been discovered by our 
WatchedFolderCreationListeners, if any */
-    void addNewWatchedFolders() {
+    void addNewWatchedFolders() throws RepositoryException {
        for(WatchedFolderCreationListener w : listeners) {
                final Set<String> paths = w.getAndClearPaths();
                if(paths != null) {
                        for(String path : paths) {
-                               folders.add(new WatchedFolder(path, 
osgiController));
+                               folders.add(new WatchedFolder(repository, path, 
osgiController, scanDelayMsec));
                        }
                }
        }
@@ -160,7 +163,7 @@
     void findWatchedFolders(Node n, Set<WatchedFolder> setToUpdate) throws 
RepositoryException 
     {
         if (folderNameFilter.accept(n.getPath())) {
-            setToUpdate.add(new WatchedFolder(n.getPath(), osgiController));
+            setToUpdate.add(new WatchedFolder(repository, n.getPath(), 
osgiController, scanDelayMsec));
         }
         final NodeIterator it = n.getNodes();
         while (it.hasNext()) {
@@ -177,4 +180,11 @@
         }
         return path;
     }
+    
+    /** Let our WatchedFolders run their scanning cycles */ 
+    void runOneCycle() throws Exception {
+       for(WatchedFolder wf : folders) {
+               wf.scanIfNeeded();
+       }
+    }
 }

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=693761&r1=693760&r2=693761&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
 Wed Sep 10 02:58:25 2008
@@ -18,6 +18,20 @@
  */
 package org.apache.sling.jcr.jcrinstall.jcr.impl;
 
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+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.jcr.api.SlingRepository;
+import org.apache.sling.jcr.jcrinstall.osgi.JcrInstallException;
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiController;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -26,20 +40,43 @@
  *  to it (non-recursively) and sending the appropriate messages
  *  to the OsgiController service.
  */
-class WatchedFolder {
+class WatchedFolder implements EventListener {
     private final String path;
     private final OsgiController controller;
+    private long nextScan;
+    private final Session session;
     protected static final Logger log = 
LoggerFactory.getLogger(WatchedFolder.class);
     
-    WatchedFolder(String path, OsgiController ctrl) {
+    /**
+     * After receiving JCR events, we wait for this many msec before
+     * re-scanning the folder, as events often come in bursts.
+     */
+    private final long scanDelayMsec;
+
+    WatchedFolder(SlingRepository repository, String path, OsgiController 
ctrl, long scanDelayMsec) throws RepositoryException {
         this.path = path;
         this.controller = ctrl;
+        this.scanDelayMsec = scanDelayMsec;
+        session = 
repository.loginAdministrative(repository.getDefaultWorkspace());
+        
+        // observe any changes in our folder, but not recursively
+        final int eventTypes = Event.NODE_ADDED | Event.NODE_REMOVED
+                | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | 
Event.PROPERTY_REMOVED;
+        final boolean isDeep = false;
+        final boolean noLocal = true;
+        session.getWorkspace().getObservationManager().addEventListener(this, 
eventTypes, path,
+                isDeep, null, null, noLocal);
         
         log.info("Watching folder " + path);
     }
     
     void cleanup() {
-       // TODO stop listening to events
+       try {
+               
session.getWorkspace().getObservationManager().removeEventListener(this);
+               session.logout();
+       } catch(RepositoryException re) {
+               log.warn("RepositoryException in cleanup()", re);
+       }
     }
     
     @Override
@@ -65,4 +102,68 @@
     String getPath() {
         return path;
     }
+    
+    /** Set our timer whenever an event occurs, to wait
+     *         a bit before processing event bursts.
+     */
+    public void onEvent(EventIterator it) {
+        nextScan = System.currentTimeMillis() + scanDelayMsec;
+    }
+    
+    /**
+     *         If our timer allows it, scan our folder Node for updates
+     *         and deletes.
+     */
+    void scanIfNeeded() throws Exception {
+        if (nextScan != -1 && System.currentTimeMillis() > nextScan) {
+            nextScan = -1;
+        }
+        scan();
+    }
+    
+    /** Scan our folder and inform OsgiController of any changes */
+    protected void scan() throws Exception {
+        log.debug("Scanning {}", path);
+        
+        Node folder = null;
+        if(session.itemExists(path)) {
+               Item i = session.getItem(path);
+               if(i.isNode()) {
+                       folder = (Node)i;
+               }
+        }
+        
+        if(folder == null) {
+               log.info("Folder {} does not exist (or not anymore), cannot 
scan", path);
+               return;
+        }
+               
+        
+        // TODO: check deletions
+        
+        // Check adds and updates, for all child nodes that are files
+        final NodeIterator it = folder.getNodes();
+        while(it.hasNext()) {
+               final Node n = it.nextNode();
+               final FileDataProvider dp = new FileDataProvider(n);
+               if(!dp.isFile()) {
+                       log.debug("Node {} does not seem to be a file, 
ignored", n.getPath());
+               }
+               installOrUpdate(n.getPath(), dp.getInputStream(), 
dp.getLastModified());
+        }
+    }
+    
+    /** Install or update the given resource, as needed */ 
+    protected void installOrUpdate(String path, InputStream data, Long 
lastModified) throws IOException, JcrInstallException {
+       final long currentLastModified = controller.getLastModified(path);
+       if(currentLastModified == -1) {
+               log.info("Resource {} was not installed yet, installing in 
OsgiController", path);
+               controller.installOrUpdate(path, lastModified, data);
+       } else if(currentLastModified < lastModified) {
+               log.info("Resource {} has been updated, updating in 
OsgiController", path);
+               controller.installOrUpdate(path, lastModified, data);
+       } else {
+               log.info("Resource {} not modified, ignoring", path);
+       }
+    }
 }

Added: 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java?rev=693761&view=auto
==============================================================================
--- 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java
 (added)
+++ 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ContentHelper.java
 Wed Sep 10 02:58:25 2008
@@ -0,0 +1,105 @@
+/*
+ * 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.io.InputStream;
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+class ContentHelper {
+    public static final String NT_FOLDER = "nt:folder";
+    public static final String NT_FILE = "nt:file";
+    public static final String NT_RESOURCE = "nt:resource";
+    public static final String JCR_CONTENT = "jcr:content";
+    public static final String JCR_LASTMODIFIED = "jcr:lastModified";
+    public static final String JCR_MIMETYPE = "jcr:mimeType";
+    public static final String JCR_ENCODING = "jcr:encoding";
+    public static final String JCR_DATA = "jcr:data";
+    
+    final String [] WATCHED_FOLDERS = {
+        "libs/foo/bar/install",
+        "libs/foo/wii/install",
+        "apps/install"
+    };
+
+    final String [] IGNORED_FOLDERS = {
+        "libs/foo/bar/installed",
+        "apps/noninstall"
+    };
+    
+    private final Session session;
+    
+    ContentHelper(Session s) {
+       session = s;
+    }
+
+    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 : IGNORED_FOLDERS) {
+            createFolder(folder);
+        }
+    }
+    
+    void createFolder(String path) throws Exception {
+        final String [] parts = path.split("/");
+        Node n = session.getRootNode();
+        for(String part : parts) {
+            if(n.hasNode(part)) {
+                n = n.getNode(part);
+            } else {
+                n = n.addNode(part);
+            }
+        }
+        session.save();
+    }
+    
+    void createOrUpdateFile(String path, InputStream data, long lastModified) 
throws RepositoryException {
+        final String relPath = path.substring(1);
+        Node f = null;
+        Node res = null;
+        if(session.getRootNode().hasNode(relPath)) {
+            f = session.getRootNode().getNode(relPath);
+            res = f.getNode(JCR_CONTENT);
+        } else {
+            f = session.getRootNode().addNode(relPath);
+            res = f.addNode(JCR_CONTENT);
+        }
+        
+        final Calendar c = Calendar.getInstance();
+        c.setTimeInMillis(lastModified);
+        res.setProperty(JCR_LASTMODIFIED, c);
+        res.setProperty(JCR_DATA, data);
+        f.getParent().save();
+    }
+}
\ No newline at end of file

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

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

Added: 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java?rev=693761&view=auto
==============================================================================
--- 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java
 (added)
+++ 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.java
 Wed Sep 10 02:58:25 2008
@@ -0,0 +1,85 @@
+/*
+ * 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 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;
+
+/** Used by tests to wait until JCR notification events
+ *     have been delivered.
+ */
+class EventHelper implements EventListener {
+       private final Session session;
+       private int eventCount;
+       public static final String WAIT_NODE_FOLDER = "WAIT_NODE";
+       public static final String WAIT_NODE_NODE = 
EventHelper.class.getSimpleName();
+       private final Node waitNodeFolder;
+       
+       EventHelper(Session s) throws RepositoryException {
+               session = s;
+               
+        final int eventTypes = Event.NODE_ADDED | Event.NODE_REMOVED;
+        final boolean isDeep = true;
+        final boolean noLocal = false;
+        session.getWorkspace().getObservationManager().addEventListener(
+                       this, eventTypes, "/" + WAIT_NODE_FOLDER, isDeep, null, 
null, noLocal);
+        
+        if(session.getRootNode().hasNode(WAIT_NODE_FOLDER)) {
+               waitNodeFolder = 
session.getRootNode().getNode(WAIT_NODE_FOLDER);
+        } else {
+               waitNodeFolder = 
session.getRootNode().addNode(WAIT_NODE_FOLDER, "nt:unstructured");
+        }
+        session.save();
+       }
+       
+    public void onEvent(EventIterator it) {
+       eventCount++;
+    }
+    
+    /** To make sure observation events have been delivered,
+     *         create or delete a a node and wait for the corresponding
+     *         events to be received.
+     */
+       void waitForEvents(long timeoutMsec) throws RepositoryException {
+               final int targetEventCount = eventCount + 1;
+               
+               if(waitNodeFolder.hasNode(WAIT_NODE_NODE)) {
+                       waitNodeFolder.getNode(WAIT_NODE_NODE).remove();
+               } else {
+                       waitNodeFolder.addNode(WAIT_NODE_NODE);
+               }
+               session.save();
+               
+       final long end = System.currentTimeMillis() + timeoutMsec;
+       while(eventCount < targetEventCount && System.currentTimeMillis() < 
end) {
+               try {
+                       Thread.sleep(100);
+               } catch(InterruptedException ignored) {
+               }
+       }
+       
+       if(eventCount < targetEventCount) {
+               throw new IllegalStateException("Event counter did not reach " 
+ targetEventCount + ", waited " + timeoutMsec + " msec");
+       }
+    }
+}

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

Propchange: 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/EventHelper.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=693761&r1=693760&r2=693761&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
 Wed Sep 10 02:58:25 2008
@@ -18,44 +18,28 @@
  */
 package org.apache.sling.jcr.jcrinstall.jcr.impl;
 
-import java.lang.reflect.Field;
 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 implements 
EventListener {
+public class FindWatchedFoldersTest extends RepositoryTestBase {
     
     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"
-    };
+    private EventHelper eventHelper; 
+    private ContentHelper contentHelper;
     
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
-        
session.getWorkspace().getObservationManager().removeEventListener(this);
-        cleanupContent();
+        contentHelper.cleanupContent();
         session.logout();
+        eventHelper = null;
+        contentHelper = null;
     }
 
     @Override
@@ -63,140 +47,42 @@
         super.setUp();
         repo = getRepository();
         session = repo.loginAdministrative(repo.getDefaultWorkspace());
-        cleanupContent();
-        
-        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 : IGNORED_FOLDERS) {
-            createFolder(folder);
-        }
+        eventHelper = new EventHelper(session);
+        contentHelper = new ContentHelper(session);
+        contentHelper.cleanupContent();
     }
     
-    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();
+       contentHelper.setupContent();
+        final RepositoryObserver ro = 
MiscHelper.createRepositoryObserver(repo, null);
         ro.activate(null);
         
-        final Set<WatchedFolder> wfSet = getWatchedFolders(ro);
-        assertEquals("activate() must find all watched folders", 
WATCHED_FOLDERS.length, wfSet.size());
+        final Set<WatchedFolder> wfSet = MiscHelper.getWatchedFolders(ro);
+        assertEquals("activate() must find all watched folders", 
contentHelper.WATCHED_FOLDERS.length, wfSet.size());
         
-        for(String folder : WATCHED_FOLDERS) {
+        for(String folder : contentHelper.WATCHED_FOLDERS) {
             assertTrue("Folder " + folder + " must be watched (watched=" + 
wfSet + ")", 
-                    folderIsWatched(ro, folder)); 
+                    MiscHelper.folderIsWatched(ro, folder)); 
         }
     }
     
     public void testNewWatchedFolderDetection() throws Exception {
-       setupContent();
-        final RepositoryObserver ro = createRepositoryObserver();
+       contentHelper.setupContent();
+        final RepositoryObserver ro = 
MiscHelper.createRepositoryObserver(repo, null);
         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));
+            assertFalse(newPath + " must not be watched before test", 
MiscHelper.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));
+            contentHelper.createFolder(newPath);
+            eventHelper.waitForEvents(5000L);
+            assertFalse(newPath + " must not be watched before calling 
addNewWatchedFolders()", MiscHelper.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();
-        for(String part : parts) {
-            if(n.hasNode(part)) {
-                n = n.getNode(part);
-            } else {
-                n = n.addNode(part);
-            }
+            assertTrue(newPath + " must be watched before calling 
addNewWatchedFolders()", MiscHelper.folderIsWatched(ro, newPath));
         }
-        session.save();
-    }
-    
-    RepositoryObserver createRepositoryObserver() throws Exception {
-        final RepositoryObserver result = new RepositoryObserver();
-        setField(result, "repository", repo);
-        return result;
-    }
-    
-    static void setField(Object target, String name, Object value) throws 
Exception, IllegalAccessException {
-        final Field f = target.getClass().getDeclaredField(name);
-        f.setAccessible(true);
-        f.set(target, value);
-
-    }
-}
+    }   
+}
\ No newline at end of file

Added: 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MiscHelper.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MiscHelper.java?rev=693761&view=auto
==============================================================================
--- 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MiscHelper.java
 (added)
+++ 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MiscHelper.java
 Wed Sep 10 02:58:25 2008
@@ -0,0 +1,62 @@
+/*
+ * 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.lang.reflect.Field;
+import java.util.Set;
+
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.jcrinstall.osgi.OsgiController;
+
+/** Miscellaneous test helper functions */
+class MiscHelper {
+    static 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;
+    }
+    
+    @SuppressWarnings("unchecked")
+    static Set<WatchedFolder> getWatchedFolders(RepositoryObserver ro) throws 
Exception {
+        final Field f = ro.getClass().getDeclaredField("folders");
+        f.setAccessible(true);
+        return (Set<WatchedFolder>)f.get(ro);
+    }
+    
+    static RepositoryObserver createRepositoryObserver(SlingRepository repo, 
OsgiController c) throws Exception {
+        final RepositoryObserver result = new RepositoryObserver();
+        setField(result, "repository", repo);
+        setField(result, "osgiController", c);
+        return result;
+    }
+    
+    static void setField(Object target, String name, Object value) throws 
Exception, IllegalAccessException {
+        final Field f = target.getClass().getDeclaredField(name);
+        f.setAccessible(true);
+        f.set(target, value);
+
+    }
+
+}

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

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

Added: 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java?rev=693761&view=auto
==============================================================================
--- 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java
 (added)
+++ 
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java
 Wed Sep 10 02:58:25 2008
@@ -0,0 +1,163 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import javax.jcr.Session;
+
+import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.jcrinstall.osgi.OsgiController;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.Sequence;
+
+/** Test that added/updated/removed resources are
+ *     correctly translated to OsgiController calls.
+ */
+public class ResourceDetectionTest extends RepositoryTestBase {
+    SlingRepository repo;
+    Session session;
+    private EventHelper eventHelper; 
+    private ContentHelper contentHelper;
+    private Mockery mockery;
+    private Sequence sequence;
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        contentHelper.cleanupContent();
+        session.logout();
+        eventHelper = null;
+        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();
+        sequence = mockery.sequence(getClass().getSimpleName());
+    }
+    
+    protected String getOsgiResourceLocation(String uri) {
+        return "jcrinstall://" + uri;
+    }
+    
+    /** Add, update and remove resources from the repository
+     *  and verify that the OsgiController receives the
+     *  correct messages
+     */
+    public void testSingleResourceDetection() throws Exception {
+        contentHelper.setupContent();
+        
+        final String dummyJar = "/libs/foo/bar/install/dummy.jar";
+        final InputStream data = new ByteArrayInputStream(dummyJar.getBytes());
+        final long lastModifiedA = System.currentTimeMillis();
+        final long lastModifiedB = lastModifiedA + 1;
+        
+        final OsgiController c = mockery.mock(OsgiController.class);
+        final RepositoryObserver ro = 
MiscHelper.createRepositoryObserver(repo, c);
+        ro.activate(null);
+        
+        // Define the whole sequence of calls to OsgiController,
+        // Using getLastModified calls to mark the test phases
+        mockery.checking(new Expectations() {{
+            one(c).getLastModified("phase1"); 
+            inSequence(sequence);
+            one(c).getLastModified(dummyJar); will(returnValue(-1L));
+            inSequence(sequence);
+            one(c).installOrUpdate(with(equal(dummyJar)), 
with(equal(lastModifiedA)), with(any(InputStream.class)));
+            inSequence(sequence);
+            
+            one(c).getLastModified("phase2"); 
+            inSequence(sequence);
+            one(c).getLastModified(dummyJar); will(returnValue(lastModifiedA));
+            inSequence(sequence);
+            
+            one(c).getLastModified("phase3"); 
+            inSequence(sequence);
+            one(c).getLastModified(dummyJar); will(returnValue(lastModifiedA));
+            inSequence(sequence);
+            one(c).installOrUpdate(with(equal(dummyJar)), 
with(equal(lastModifiedB)), with(any(InputStream.class)));
+            inSequence(sequence);
+        }});
+        
+        // Add two files, run one cycle must install the bundles
+        c.getLastModified("phase1");
+        contentHelper.createOrUpdateFile(dummyJar, data, lastModifiedA);
+        eventHelper.waitForEvents(5000L);
+        ro.runOneCycle();
+        
+        // Updating with the same timestamp must not call install again
+        c.getLastModified("phase2");
+        contentHelper.createOrUpdateFile(dummyJar, data, lastModifiedA);
+        eventHelper.waitForEvents(5000L);
+        ro.runOneCycle();
+        
+        // Updating with a new timestamp must call install again
+        c.getLastModified("phase3");
+        contentHelper.createOrUpdateFile(dummyJar, data, lastModifiedB);
+        eventHelper.waitForEvents(5000L);
+        ro.runOneCycle();
+        
+        mockery.assertIsSatisfied();
+    }
+    
+    public void testMultipleResourceDetection() throws Exception {
+        contentHelper.setupContent();
+        
+        final String [] resources = {
+                "/libs/foo/bar/install/dummy.jar",
+                "/libs/foo/bar/install/dummy.cfg",
+                "/libs/foo/bar/install/dummy.dp"
+        };
+        final InputStream data = new ByteArrayInputStream("hello".getBytes());
+        final long lastModifiedA = System.currentTimeMillis();
+        
+        final OsgiController c = mockery.mock(OsgiController.class);
+        final RepositoryObserver ro = 
MiscHelper.createRepositoryObserver(repo, c);
+        ro.activate(null);
+        
+        // Define the whole sequence of calls to OsgiController,
+        // Using getLastModified calls to mark the test phases
+        mockery.checking(new Expectations() {{
+            allowing(c).getLastModified(with(any(String.class))); 
will(returnValue(-1L)); 
+            one(c).installOrUpdate(with(equal(resources[0])), 
with(equal(lastModifiedA)), with(any(InputStream.class)));
+            one(c).installOrUpdate(with(equal(resources[1])), 
with(equal(lastModifiedA)), with(any(InputStream.class)));
+            one(c).installOrUpdate(with(equal(resources[2])), 
with(equal(lastModifiedA)), with(any(InputStream.class)));
+        }});
+        
+        // Add two files, run one cycle must install the bundles
+        for(String file : resources) {
+            contentHelper.createOrUpdateFile(file, data, lastModifiedA);
+        }
+        eventHelper.waitForEvents(5000L);
+        ro.runOneCycle();
+        
+        mockery.assertIsSatisfied();
+    }
+}

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

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


Reply via email to