Author: bdelacretaz
Date: Tue Sep 16 06:28:40 2008
New Revision: 695873
URL: http://svn.apache.org/viewvc?rev=695873&view=rev
Log:
SLING-658 - Resources were not uninstalled when their folder is deleted
Modified:
incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/jcr/impl/RepositoryObserver.java
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockRepositoryObserver.java
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.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=695873&r1=695872&r2=695873&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 16 06:28:40 2008
@@ -18,9 +18,16 @@
*/
package org.apache.sling.jcr.jcrinstall.jcr.impl;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Properties;
import java.util.Set;
import javax.jcr.Node;
@@ -30,6 +37,7 @@
import javax.jcr.observation.Event;
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.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
@@ -78,6 +86,9 @@
/** ComponentContext property that overrides the folder name regepx */
public static final String FOLDER_NAME_REGEXP_PROPERTY =
"sling.jcrinstall.folder.name.regexp";
+ public static final String DATA_FILE = "service.properties";
+ public static final String DATA_LAST_FOLDER_REGEXP = "folder.regexp";
+
/** Scan delay for watched folders */
protected long scanDelayMsec = 1000L;
@@ -92,14 +103,35 @@
final String [] roots = DEFAULT_ROOTS;
filenameFilter = new RegexpFilter(DEFAULT_FILENAME_REGEXP);
- String regexp = getPropertyValue(context, FOLDER_NAME_REGEXP_PROPERTY);
- if(regexp != null) {
- log.info("Using folder name regexp '{}' from context property
'{}'", regexp, FOLDER_NAME_REGEXP_PROPERTY);
- folderNameFilter = new RegexpFilter(regexp);
- } else {
+ String folderNameRegexp = getPropertyValue(context,
FOLDER_NAME_REGEXP_PROPERTY);
+ if(folderNameRegexp == null) {
+ folderNameRegexp = DEFAULT_FOLDER_NAME_REGEXP;
log.info("Using default folder name regexp '{}'",
DEFAULT_FOLDER_NAME_REGEXP);
- folderNameFilter = new RegexpFilter(DEFAULT_FOLDER_NAME_REGEXP);
+ } else {
+ log.info("Using folder name regexp '{}' from context property
'{}'", folderNameRegexp, FOLDER_NAME_REGEXP_PROPERTY);
}
+ folderNameFilter = new RegexpFilter(folderNameRegexp);
+
+ // If regexp has changed, uninstall everything - it's a bit hard
+ // to know what might have changed otherwise
+ // (null context happens during testing only)
+ if(context != null) {
+ final File f = context.getBundleContext().getDataFile(DATA_FILE);
+ final Properties props = loadProperties(f);
+ final String oldRegexp =
props.getProperty(DATA_LAST_FOLDER_REGEXP);
+ if(oldRegexp != null && !oldRegexp.equals(folderNameRegexp)) {
+ log.info("Folder name regexp has changed, uninstalling all
resources ({} -> {}", oldRegexp, folderNameRegexp);
+ for(String uri : osgiController.getInstalledUris()) {
+ try {
+ osgiController.uninstall(uri);
+ } catch (JcrInstallException e) {
+ log.warn("Exception during 'uninstall all'", e);
+ }
+ }
+ }
+ props.setProperty(DATA_LAST_FOLDER_REGEXP, folderNameRegexp);
+ saveProperties(props, f);
+ }
// Listen for any new WatchedFolders created after activation
session =
repository.loginAdministrative(repository.getDefaultWorkspace());
@@ -112,23 +144,24 @@
session.getWorkspace().getObservationManager().addEventListener(w,
eventTypes, path,
isDeep, null, null, noLocal);
}
+
+ // Check if any deletions happened while this
+ // service was inactive: create a fake WatchFolder
+ // on / and use it to check for any deletions, even
+ // if the corresponding WatchFolders are gone
+ try {
+ final WatchedFolder rootWf = new WatchedFolder(repository, "/",
osgiController, filenameFilter, 0L);
+ rootWf.checkDeletions(osgiController.getInstalledUris());
+ } catch(Exception e) {
+ log.warn("Exception in root WatchFolder.checkDeletions call", e);
+ }
+ // Find folders to watch
folders = new HashSet<WatchedFolder>();
-
for(String root : roots) {
folders.addAll(findWatchedFolders(root));
}
- // Check if any deletions happened while this
- // service was inactive
- for(WatchedFolder wf : folders) {
- try {
- wf.checkDeletions(osgiController.getInstalledUris());
- } catch(Exception e) {
- log.warn("Exception in activate() / checkDeletions", e);
- }
- }
-
// start queue processing
running = true;
final Thread t = new Thread(this, getClass().getSimpleName() + "_" +
System.currentTimeMillis());
@@ -266,4 +299,44 @@
wf.scanIfNeeded();
}
}
+
+ Properties loadProperties(File f) {
+ final Properties props = new Properties();
+ if(f.exists()) {
+ InputStream is = null;
+ try {
+ is = new FileInputStream(f);
+ props.load(is);
+ } catch(IOException ioe) {
+ log.warn("Error reading " + f.getName(), ioe);
+ } finally {
+ if(is!=null) {
+ try {
+ is.close();
+ } catch(IOException ignore) {
+
+ }
+ }
+ }
+ }
+ return props;
+ }
+
+ void saveProperties(Properties props, File f) {
+ OutputStream os = null;
+ try {
+ os = new FileOutputStream(f);
+ props.store(os, getClass().getSimpleName());
+ } catch(IOException ioe) {
+ log.warn("Error saving " + f.getName(), ioe);
+ } finally {
+ if(os!=null) {
+ try {
+ os.close();
+ } catch(IOException ignore) {
+
+ }
+ }
+ }
+ }
}
\ No newline at end of file
Modified:
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockRepositoryObserver.java
URL:
http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockRepositoryObserver.java?rev=695873&r1=695872&r2=695873&view=diff
==============================================================================
---
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockRepositoryObserver.java
(original)
+++
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/MockRepositoryObserver.java
Tue Sep 16 06:28:40 2008
@@ -18,6 +18,7 @@
*/
package org.apache.sling.jcr.jcrinstall.jcr.impl;
+import java.util.Properties;
import java.util.Set;
import org.apache.sling.jcr.api.SlingRepository;
@@ -28,6 +29,8 @@
* used for testing.
*/
public class MockRepositoryObserver extends RepositoryObserver {
+ private Properties props;
+
MockRepositoryObserver(SlingRepository repo, final OsgiController c) {
repository = repo;
osgiController = c;
@@ -53,7 +56,11 @@
return result;
}
+ public void setProperties(Properties p) {
+ props = p;
+ }
+
protected String getPropertyValue(ComponentContext ctx, String name) {
- return null;
+ return (props == null ? null : props.getProperty(name));
}
}
Modified:
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=695873&r1=695872&r2=695873&view=diff
==============================================================================
---
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java
(original)
+++
incubator/sling/trunk/extensions/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java
Tue Sep 16 06:28:40 2008
@@ -19,8 +19,10 @@
package org.apache.sling.jcr.jcrinstall.jcr.impl;
import java.io.ByteArrayInputStream;
+import java.io.File;
import java.io.InputStream;
import java.util.HashSet;
+import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -34,6 +36,8 @@
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.Sequence;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
/** Test that added/updated/removed resources are
* correctly translated to OsgiController calls.
@@ -220,6 +224,7 @@
final Set<String> installedUri = new HashSet<String>();
installedUri.add("/libs/foo/bar/install/dummy.jar");
installedUri.add("/libs/foo/bar/install/dummy.cfg");
+ installedUri.add("/libs/watchfolder-is-gone/install/gone.cfg");
final OsgiController c = mockery.mock(OsgiController.class);
final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
@@ -229,6 +234,7 @@
allowing(c).getLastModified(with(any(String.class)));
will(returnValue(-1L));
one(c).uninstall("/libs/foo/bar/install/dummy.jar");
one(c).uninstall("/libs/foo/bar/install/dummy.cfg");
+ one(c).uninstall("/libs/watchfolder-is-gone/install/gone.cfg");
}});
// Activating with installed resources that are not in
@@ -301,4 +307,71 @@
mockery.assertIsSatisfied();
}
+
+ /** Verify that resources are correctly uninstalled if the folder name
regexp changes */
+ public void testFolderRegexpChange() throws Exception {
+ contentHelper.setupContent();
+
+ final String [] resources = {
+ "/libs/foo/bar/install/dummy.jar",
+ "/libs/foo/wii/install/dummy.cfg",
+ "/libs/foo/bar/install/dummy.dp",
+ "/libs/foo/wii/install/more.cfg",
+ };
+
+ final InputStream data = new ByteArrayInputStream("hello".getBytes());
+ final long lastModifiedA = System.currentTimeMillis();
+
+ for(String file : resources) {
+ contentHelper.createOrUpdateFile(file, data, lastModifiedA);
+ }
+
+ final Set<String> installedUri = new HashSet<String>();
+ final OsgiController c = mockery.mock(OsgiController.class);
+ final Properties props = new Properties();
+ final ComponentContext ctx = mockery.mock(ComponentContext.class);
+ final BundleContext bc = mockery.mock(BundleContext.class);
+ final File f = File.createTempFile(getClass().getSimpleName(),
"properties");
+ f.deleteOnExit();
+
+ // Test with first regexp
+ mockery.checking(new Expectations() {{
+ allowing(ctx).getBundleContext(); will(returnValue(bc));
+ allowing(bc).getDataFile("service.properties");
will(returnValue(f));
+ allowing(c).getInstalledUris(); will(returnValue(installedUri));
+ 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[2])),
with(equal(lastModifiedA)), with(any(InputStream.class)));
+ }});
+
+ final MockRepositoryObserver ro = new MockRepositoryObserver(repo, c);
+ ro.setProperties(props);
+ props.setProperty(RepositoryObserver.FOLDER_NAME_REGEXP_PROPERTY,
".*foo/bar/install$");
+ ro.activate(ctx);
+ for(String file : resources) {
+ contentHelper.createOrUpdateFile(file, data, lastModifiedA);
+ }
+ eventHelper.waitForEvents(5000L);
+ ro.runOneCycle();
+ mockery.assertIsSatisfied();
+
+ // Test with a different regexp, install.A resources must be
uninstalled
+ mockery.checking(new Expectations() {{
+ allowing(ctx).getBundleContext(); will(returnValue(bc));
+ allowing(bc).getDataFile("service.properties");
will(returnValue(f));
+ allowing(c).getInstalledUris(); will(returnValue(installedUri));
+ allowing(c).getLastModified(with(any(String.class)));
will(returnValue(-1L));
+ one(c).installOrUpdate(with(equal(resources[1])),
with(equal(lastModifiedA)), with(any(InputStream.class)));
+ one(c).installOrUpdate(with(equal(resources[3])),
with(equal(lastModifiedA)), with(any(InputStream.class)));
+ }});
+
+ props.setProperty(RepositoryObserver.FOLDER_NAME_REGEXP_PROPERTY,
".*foo/wii/install$");
+ ro.activate(ctx);
+ for(String file : resources) {
+ contentHelper.createOrUpdateFile(file, data, lastModifiedA);
+ }
+ eventHelper.waitForEvents(5000L);
+ ro.runOneCycle();
+ mockery.assertIsSatisfied();
+ }
}
\ No newline at end of file