You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2017/11/06 16:04:28 UTC

[sling-org-apache-sling-fsresource] branch release/1.x created (now 4abf59c)

This is an automated email from the ASF dual-hosted git repository.

sseifert pushed a change to branch release/1.x
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-fsresource.git.


      at 4abf59c  import branch for 1.x from svn

This branch includes the following new commits:

     new 4abf59c  import branch for 1.x from svn

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-fsresource] 01/01: import branch for 1.x from svn

Posted by ss...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sseifert pushed a commit to branch release/1.x
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-fsresource.git

commit 4abf59cf41b40366ceffe3e455296f822ec39db7
Author: sseifert <ss...@pro-vision.de>
AuthorDate: Mon Nov 6 17:03:26 2017 +0100

    import branch for 1.x from svn
---
 pom.xml                                            |  22 ++--
 .../sling/fsprovider/internal/FileMonitor.java     |  95 +++++++++-------
 .../apache/sling/fsprovider/internal/FsMode.java   |   2 +-
 .../fsprovider/internal/FsResourceProvider.java    | 125 ++++++---------------
 .../internal/mapper/ContentFileResource.java       |   5 +-
 .../fsprovider/internal/mapper/FileResource.java   |  24 ++--
 .../internal/mapper/FileResourceMapper.java        |  11 +-
 .../internal/mapper/FileVaultResourceMapper.java   |   5 +-
 .../internal/parser/ContentElementImpl.java        |   2 +-
 .../sling/fsprovider/internal/FileMonitorTest.java |  53 +++++----
 .../fsprovider/internal/FileVaultContentTest.java  |  14 +--
 .../internal/FileVaultFileMonitorTest.java         |  59 +++++-----
 .../fsprovider/internal/JcrXmlContentTest.java     |  15 ++-
 .../sling/fsprovider/internal/JsonContentTest.java |  19 ++--
 .../sling/fsprovider/internal/TestUtils.java       |  29 +++--
 15 files changed, 239 insertions(+), 241 deletions(-)

diff --git a/pom.xml b/pom.xml
index fc0b0d2..e1f065c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
 
     <artifactId>org.apache.sling.fsresource</artifactId>
     <packaging>bundle</packaging>
-    <version>2.1.9-SNAPSHOT</version>
+    <version>1.4.9-SNAPSHOT</version>
 
     <name>Apache Sling File System Resource Provider</name>
     <description>
@@ -87,12 +87,14 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.4</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.11.0</version>
+            <version>2.4.0</version>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
@@ -104,8 +106,8 @@
             <artifactId>osgi.core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.cmpn</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -157,13 +159,19 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.sling-mock</artifactId>
-            <version>2.2.6</version>
+            <version>1.9.6</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+            <version>2.2.4</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.logging-mock</artifactId>
-            <version>2.0.0</version>
+            <version>1.0.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java b/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
index a164d4f..88c9d6f 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
@@ -18,8 +18,17 @@
  */
 package org.apache.sling.fsprovider.internal;
 
+import static org.apache.sling.api.SlingConstants.PROPERTY_PATH;
+import static org.apache.sling.api.SlingConstants.PROPERTY_RESOURCE_TYPE;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_CHANGED;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_REMOVED;
+
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Timer;
@@ -27,13 +36,12 @@ import java.util.TimerTask;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
-import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
 import org.apache.sling.fsprovider.internal.mapper.ContentFile;
+import org.apache.sling.fsprovider.internal.mapper.FileResource;
 import org.apache.sling.fsprovider.internal.parser.ContentElement;
+import org.apache.sling.fsprovider.internal.parser.ContentElementImpl;
 import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
-import org.apache.sling.spi.resource.provider.ObservationReporter;
-import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+import org.osgi.service.event.EventAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -126,8 +134,8 @@ public final class FileMonitor extends TimerTask {
         }
         synchronized ( this ) {
             try {
-                // if we don't have an observation reporter, we just skip the check
-                final ObservationReporter reporter = this.provider.getObservationReporter();
+                // if we don't have an event admin, we just skip the check
+                final EventAdmin reporter = this.provider.getEventAdmin();
                 if ( reporter != null ) {
                     this.check(this.root, reporter);
                 }
@@ -144,16 +152,16 @@ public final class FileMonitor extends TimerTask {
     /**
      * Check the monitorable
      * @param monitorable The monitorable to check
-     * @param reporter The ObservationReporter
+     * @param reporter The EventAdmin
      */
-    private void check(final Monitorable monitorable, final ObservationReporter reporter) {
+    private void check(final Monitorable monitorable, final EventAdmin reporter) {
         log.trace("Checking {}", monitorable.file);
         // if the file is non existing, check if it has been readded
         if ( monitorable.status instanceof NonExistingStatus ) {
             if ( monitorable.file.exists() ) {
                 // new file and reset status
                 createStatus(monitorable, contentFileExtensions, contentFileCache);
-                sendEvents(monitorable, ChangeType.ADDED, reporter);
+                sendEvents(monitorable, TOPIC_RESOURCE_ADDED, reporter);
                 final FileStatus fs = (FileStatus)monitorable.status;
                 if ( fs instanceof DirStatus ) {
                     final DirStatus ds = (DirStatus)fs;
@@ -166,7 +174,7 @@ public final class FileMonitor extends TimerTask {
             // check if the file has been removed
             if ( !monitorable.file.exists() ) {
                 // removed file and update status
-                sendEvents(monitorable, ChangeType.REMOVED, reporter);
+                sendEvents(monitorable, TOPIC_RESOURCE_REMOVED, reporter);
                 monitorable.status = NonExistingStatus.SINGLETON;
                 contentFileCache.remove(transformPath(monitorable.path));
             } else {
@@ -176,7 +184,7 @@ public final class FileMonitor extends TimerTask {
                 if ( fs.lastModified < monitorable.file.lastModified() ) {
                     fs.lastModified = monitorable.file.lastModified();
                     // changed
-                    sendEvents(monitorable, ChangeType.CHANGED, reporter);
+                    sendEvents(monitorable, TOPIC_RESOURCE_CHANGED, reporter);
                     changed = true;
                     contentFileCache.remove(transformPath(monitorable.path));
                 }
@@ -196,7 +204,7 @@ public final class FileMonitor extends TimerTask {
         }
     }
     
-    private void checkDirStatusChildren(final Monitorable dirMonitorable, final ObservationReporter reporter) {
+    private void checkDirStatusChildren(final Monitorable dirMonitorable, final EventAdmin reporter) {
         final DirStatus ds = (DirStatus)dirMonitorable.status;
         final File[] files = dirMonitorable.file.listFiles();
         if (files != null) {
@@ -225,27 +233,23 @@ public final class FileMonitor extends TimerTask {
     /**
      * Send the event async via the event admin.
      */
-    private void sendEvents(final Monitorable monitorable, final ChangeType changeType, final ObservationReporter reporter) {
+    private void sendEvents(final Monitorable monitorable, final String changeType, final EventAdmin reporter) {
         if (log.isDebugEnabled()) {
             log.debug("Detected change for resource {} : {}", transformPath(monitorable.path), changeType);
         }
 
-        List<ResourceChange> changes = null;
-        for (final ObserverConfiguration config : reporter.getObserverConfigurations()) {
-            if (config.matches(transformPath(monitorable.path))) {
-                if (changes == null) {
-                    changes = collectResourceChanges(monitorable, changeType);
-                }
-                if (log.isTraceEnabled()) {
-                    for (ResourceChange change : changes) {
-                        log.debug("Send change for resource {}: {} to {}", change.getPath(), change.getType(), config);
-                    }
-                }
+        List<ResourceChange> changes = collectResourceChanges(monitorable, changeType);
+        for (ResourceChange change : changes) {
+            if (log.isTraceEnabled()) {
+                log.debug("Send change for resource {}: {}", transformPath(change.path), change.topic);
             }
-        }
-        if (changes != null) {
-            reporter.reportChanges(changes, false);
-        }
+            final Dictionary<String, String> properties = new Hashtable<>();
+            properties.put(PROPERTY_PATH, transformPath(change.path));
+            if (change.resourceType != null) {
+                properties.put(PROPERTY_RESOURCE_TYPE, change.resourceType);
+            }
+            reporter.postEvent(new org.osgi.service.event.Event(change.topic, properties));
+        }        
     }
     
     /**
@@ -262,29 +266,33 @@ public final class FileMonitor extends TimerTask {
         }
     }
     
-    private List<ResourceChange> collectResourceChanges(final Monitorable monitorable, final ChangeType changeType) {
+    private List<ResourceChange> collectResourceChanges(final Monitorable monitorable, final String changeType) {
         List<ResourceChange> changes = new ArrayList<>();
         if (monitorable.status instanceof ContentFileStatus) {
             ContentFile contentFile = ((ContentFileStatus)monitorable.status).contentFile;
-            if (changeType == ChangeType.CHANGED) {
+            if (StringUtils.equals(changeType, TOPIC_RESOURCE_CHANGED)) {
                 ContentElement content = contentFile.getContent();
                 // we cannot easily report the diff of resource changes between two content files
                 // so we simulate a removal of the toplevel node and then add all nodes contained in the current content file again.
-                changes.add(buildContentResourceChange(ChangeType.REMOVED,  transformPath(monitorable.path)));
-                addContentResourceChanges(changes, ChangeType.ADDED, content, transformPath(monitorable.path));
+                changes.add(buildContentResourceChange(TOPIC_RESOURCE_REMOVED, content, transformPath(monitorable.path)));
+                addContentResourceChanges(changes, TOPIC_RESOURCE_ADDED, content, transformPath(monitorable.path));
             }
             else {
                 addContentResourceChanges(changes, changeType, contentFile.getContent(), transformPath(monitorable.path));
             }
         }
         else {
-            changes.add(buildContentResourceChange(changeType, transformPath(monitorable.path)));
+            Map<String,Object> props = new HashMap<>();
+            props.put("sling:resourceType", monitorable.status instanceof FileStatus ?
+                    FileResource.RESOURCE_TYPE_FILE : FileResource.RESOURCE_TYPE_FOLDER);
+            ContentElement content = new ContentElementImpl(null, props);
+            changes.add(buildContentResourceChange(changeType, content, transformPath(monitorable.path)));
         }
         return changes;
     }
-    private void addContentResourceChanges(final List<ResourceChange> changes, final ChangeType changeType,
+    private void addContentResourceChanges(final List<ResourceChange> changes, final String changeType,
             final ContentElement content, final String path) {
-        changes.add(buildContentResourceChange(changeType,  path));
+        changes.add(buildContentResourceChange(changeType, content, path));
         if (content != null) {
             for (Map.Entry<String,ContentElement> entry : content.getChildren().entrySet()) {
                 String childPath = path + "/" + entry.getKey();
@@ -292,8 +300,12 @@ public final class FileMonitor extends TimerTask {
             }
         }
     }
-    private ResourceChange buildContentResourceChange(final ChangeType changeType, final String path) {
-        return new ResourceChange(changeType, path, false, null, null, null);
+    private ResourceChange buildContentResourceChange(final String changeType, final ContentElement content, final String path) {
+        ResourceChange change = new ResourceChange();
+        change.path = path;
+        change.resourceType = content != null ? (String)content.getProperties().get("sling:resourceType") : null;
+        change.topic = changeType;
+        return change;
     }
 
     /**
@@ -373,4 +385,11 @@ public final class FileMonitor extends TimerTask {
     private static final class NonExistingStatus {
         public static NonExistingStatus SINGLETON = new NonExistingStatus();
     }
-}
\ No newline at end of file
+
+    static class ResourceChange {
+        public String path;
+        public String resourceType;
+        public String topic;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/FsMode.java b/src/main/java/org/apache/sling/fsprovider/internal/FsMode.java
index 722a4e5..b255bb2 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/FsMode.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/FsMode.java
@@ -29,7 +29,7 @@ public enum FsMode {
     FILES_FOLDERS,
 
     /**
-     * Sling-Initial-Content file system layout, supports file and folders ant content files in JSON, xml and jcr.xml format.
+     * Sling-Initial-Content file system layout, supports file and folders ant content files in JSON and jcr.xml format.
      */
     INITIAL_CONTENT,
     
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java b/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
index 62446d5..58babc8 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
@@ -27,10 +27,13 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.commons.collections.IteratorUtils;
 import org.apache.commons.collections.Predicate;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.fsprovider.internal.mapper.ContentFileResourceMapper;
 import org.apache.sling.fsprovider.internal.mapper.FileResourceMapper;
@@ -38,17 +41,16 @@ import org.apache.sling.fsprovider.internal.mapper.FileVaultResourceMapper;
 import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
 import org.apache.sling.fsprovider.internal.parser.ContentFileTypes;
 import org.apache.sling.jcr.contentparser.ContentType;
-import org.apache.sling.spi.resource.provider.ObservationReporter;
-import org.apache.sling.spi.resource.provider.ProviderContext;
-import org.apache.sling.spi.resource.provider.ResolveContext;
-import org.apache.sling.spi.resource.provider.ResourceContext;
-import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.ConfigurationPolicy;
 import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.event.EventAdmin;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.Designate;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@@ -73,7 +75,7 @@ import org.osgi.service.metatype.annotations.Option;
                    Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
            })
 @Designate(ocd=FsResourceProvider.Config.class, factory=true)
-public final class FsResourceProvider extends ResourceProvider<Object> {
+public final class FsResourceProvider implements ResourceProvider {
     
     /**
      * Resource metadata property set by {@link org.apache.sling.fsprovider.internal.mapper.FileResource}
@@ -96,8 +98,8 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
 
         @AttributeDefinition(name = "Provider Root",
                 description = "Location in the virtual resource tree where the " +
-                "file system resources are mapped in. This property must not be an empty string.")
-        String provider_root();
+                "file system resources are mapped in. This property must not be an empty string. Only one path is supported.")
+        String[] provider_roots();
         
         @AttributeDefinition(name = "File system layout",
                 description = "File system layout mode for files, folders and content.",
@@ -105,7 +107,7 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
                         @Option(value="FILES_FOLDERS", label="FILES_FOLDERS - "
                                 + "Support only files and folders (classic mode)"),
                         @Option(value="INITIAL_CONTENT", label="INITIAL_CONTENT - "
-                                + "Sling-Initial-Content file system layout, supports file and folders ant content files in JSON, xml and jcr.xml format"),
+                                + "Sling-Initial-Content file system layout, supports file and folders ant content files in JSON and jcr.xml format"),
                         @Option(value="FILEVAULT_XML", label="FILEVAULT_XML - "
                                 + "FileVault XML format (expanded content package)"),
                 })
@@ -131,7 +133,7 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
         int provider_cache_size() default 10000;
 
         // Internal Name hint for web console.
-        String webconsole_configurationFactory_nameHint() default "{provider.fs.mode}: {" + ResourceProvider.PROPERTY_ROOT + "}";
+        String webconsole_configurationFactory_nameHint() default "{provider.fs.mode}: {" + ResourceProvider.ROOTS + "}";
     }
 
     // The location in the resource tree where the resources are mapped
@@ -149,12 +151,17 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
     private FsResourceMapper contentFileMapper;
     private FileVaultResourceMapper fileVaultMapper;
     
-    // if true resources from file system are only "overlayed" to JCR resources, serving JCR as fallback within the same path
-    private boolean overlayParentResourceProvider;
-    
     // cache for parsed content files
     private ContentFileCache contentFileCache;
 
+    @Reference(cardinality=ReferenceCardinality.OPTIONAL, policy=ReferencePolicy.DYNAMIC)
+    private volatile EventAdmin eventAdmin;
+    
+    @Override
+    public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
+        return getResource(resourceResolver, path);
+    }
+
     /**
      * Returns a resource wrapping a file system file or folder for the given
      * path. If the <code>path</code> is equal to the configured resource tree
@@ -164,54 +171,26 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
      * to access the file or folder. If no such file or folder exists, this
      * method returns <code>null</code>.
      */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-	@Override
-    public Resource getResource(final ResolveContext<Object> ctx,
-            final String path,
-            final ResourceContext resourceContext,
-            final Resource parent) {
-        
-        ResourceResolver resolver = ctx.getResourceResolver();
+    @SuppressWarnings("rawtypes")
+    @Override
+    public Resource getResource(ResourceResolver resolver, String path) {
         
-        boolean askParentResourceProvider;
         Resource rsrc = null;
 
         if (fsMode == FsMode.FILEVAULT_XML) {
             // filevault: check if path matches, if not fallback to parent resource provider
             if (fileVaultMapper.pathMatches(path)) {
-                askParentResourceProvider = false;
                 rsrc = fileVaultMapper.getResource(resolver, path);
             }
-            else {
-                askParentResourceProvider = true;
-            }
         }
         else {
             // Sling-Initial-Content: mount folder/files an content files
-            askParentResourceProvider = this.overlayParentResourceProvider;
             rsrc = fileMapper.getResource(resolver, path);
             if (rsrc == null) {
                 rsrc = contentFileMapper.getResource(resolver, path);
             }
         }
         
-        if (askParentResourceProvider) {
-            // make sure directory resources from parent resource provider have higher precedence than from this provider
-            // this allows properties like sling:resourceSuperType to take effect
-            if ( rsrc == null || rsrc.getResourceMetadata().containsKey(RESOURCE_METADATA_FILE_DIRECTORY) ) {
-            	// get resource from shadowed provider
-            	final ResourceProvider rp = ctx.getParentResourceProvider();
-            	if ( rp != null ) {
-            	    Resource resourceFromParentResourceProvider = rp.getResource((ResolveContext)ctx.getParentResolveContext(), 
-    	            		path, 
-    	            		resourceContext, parent);
-            	    if (resourceFromParentResourceProvider != null) {
-            	        rsrc = resourceFromParentResourceProvider;
-            	    }
-            	}        	
-            }
-        }
-        
         return rsrc;
     }
 
@@ -219,17 +198,14 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
      * Returns an iterator of resources.
      */
     @SuppressWarnings("unchecked")
-    @Override
-    public Iterator<Resource> listChildren(final ResolveContext<Object> ctx, final Resource parent) {
-        ResourceResolver resolver = ctx.getResourceResolver();
+    public Iterator<Resource> listChildren(Resource parent) {
+        ResourceResolver resolver = parent.getResourceResolver();
         
         List<Iterator<Resource>> allChildren = new ArrayList<>();
         Iterator<Resource> children;
-        boolean askParentResourceProvider;
         
         if (fsMode == FsMode.FILEVAULT_XML) {
             // filevault: always ask provider, it checks itself if children matches the filters
-            askParentResourceProvider = true;
             children = fileVaultMapper.getChildren(resolver, parent);
             if (children != null) {
                 allChildren.add(children);
@@ -237,7 +213,6 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
         }
         else {
             // Sling-Initial-Content: get all matching folders/files and content files
-            askParentResourceProvider = this.overlayParentResourceProvider;
             children = contentFileMapper.getChildren(resolver, parent);
             if (children != null) {
                 allChildren.add(children);
@@ -248,29 +223,6 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
             }
         }
         
-    	// get children from from shadowed provider
-        if (askParentResourceProvider) {
-        	final ResourceProvider parentResourceProvider = ctx.getParentResourceProvider();
-        	if (parentResourceProvider != null) {
-        		children = parentResourceProvider.listChildren(ctx.getParentResolveContext(), parent);
-                if (children != null) {
-                    if (fsMode == FsMode.FILEVAULT_XML) {
-                        // filevault: include all children from parent resource provider that do not match the filters
-                        allChildren.add(IteratorUtils.filteredIterator(children, new Predicate() {
-                            @Override
-                            public boolean evaluate(Object object) {
-                                Resource child = (Resource)object;
-                                return !fileVaultMapper.pathMatches(child.getPath());
-                            }
-                        }));
-                    }
-                    else {
-                        allChildren.add(children);
-                    }
-                }
-        	}
-        }
-
     	if (allChildren.isEmpty()) {
     	    return null;
     	}
@@ -294,10 +246,11 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
     @Activate
     protected void activate(BundleContext bundleContext, final Config config) {
         fsMode = config.provider_fs_mode();
-        String providerRoot = config.provider_root();
-        if (StringUtils.isBlank(providerRoot)) {
-            throw new IllegalArgumentException("provider.root property must be set");
+        String[] providerRoots = config.provider_roots();
+        if (providerRoots == null || providerRoots.length != 1 || StringUtils.isBlank(providerRoots[0])) {
+            throw new IllegalArgumentException("provider.roots property must be set to exactly one entry.");
         }
+        String providerRoot = config.provider_roots()[0];
 
         String providerFileName = config.provider_file();
         if (StringUtils.isBlank(providerFileName)) {
@@ -306,7 +259,6 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
 
         this.providerRoot = providerRoot;
         this.providerFile = getProviderFile(providerFileName, bundleContext);
-        this.overlayParentResourceProvider = false;
         
         InitialContentImportOptions options = new InitialContentImportOptions(config.provider_initial_content_import_options());
         File filterXmlFile = null;
@@ -319,11 +271,7 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
                 filterXmlFile = new File(config.provider_filevault_filterxml_path());
             }
         }
-        else if (fsMode == FsMode.FILES_FOLDERS) {
-            overlayParentResourceProvider = true;
-        }
         else if (fsMode == FsMode.INITIAL_CONTENT) {
-            overlayParentResourceProvider = !options.isOverwrite();
             if (!options.getIgnoreImportProviders().contains(ContentType.JSON.getExtension())) {
                 contentFileSuffixes.add(ContentFileTypes.JSON_SUFFIX);
             }
@@ -341,7 +289,7 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
             this.fileVaultMapper = new FileVaultResourceMapper(this.providerFile, filterXmlFile, this.contentFileCache);
         }
         else {
-            this.fileMapper = new FileResourceMapper(this.providerRoot, this.providerFile, contentFileExtensions, this.contentFileCache);
+            this.fileMapper = new FileResourceMapper(this.providerRoot, this.providerFile, contentFileExtensions, this.contentFileCache, this.fsMode);
             this.contentFileMapper = new ContentFileResourceMapper(this.providerRoot, this.providerFile,
                     contentFileExtensions, this.contentFileCache);
         }
@@ -361,7 +309,6 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
         }
         this.providerRoot = null;
         this.providerFile = null;
-        this.overlayParentResourceProvider = false;
         this.fileMapper = null;
         this.contentFileMapper = null;
         this.fileVaultMapper = null;
@@ -372,6 +319,10 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
         this.fsMode = null;
     }
 
+    EventAdmin getEventAdmin() {
+        return this.eventAdmin;
+    }
+
     File getRootFile() {
         return this.providerFile;
     }
@@ -409,12 +360,4 @@ public final class FsResourceProvider extends ResourceProvider<Object> {
         return providerFile;
     }
 
-    public ObservationReporter getObservationReporter() {
-        final ProviderContext ctx = this.getProviderContext();
-        if (ctx != null) {
-            return ctx.getObservationReporter();
-        }
-        return null;
-    }
-
 }
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
index 40549c5..f65422d 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
@@ -25,6 +25,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.sling.api.resource.AbstractResource;
 import org.apache.sling.api.resource.ResourceMetadata;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.fsprovider.internal.mapper.jcr.FsNode;
 
@@ -80,14 +81,14 @@ public final class ContentFileResource extends AbstractResource {
 
     public String getResourceSuperType() {
         if (resourceSuperType == null) {
-            resourceSuperType = getValueMap().get("sling:resourceSuperType", String.class);
+            resourceSuperType = ResourceUtil.getValueMap(this).get("sling:resourceSuperType", String.class);
         }
         return resourceSuperType;
     }
 
     public String getResourceType() {
         if (resourceType == null) {
-            ValueMap props = getValueMap();
+            ValueMap props = ResourceUtil.getValueMap(this);
             resourceType = props.get("sling:resourceType", String.class);
             if (resourceType == null) {
                 // fallback to jcr:primaryType when resource type not set
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResource.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResource.java
index 873aba8..83516c9 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResource.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResource.java
@@ -41,7 +41,7 @@ import org.apache.sling.api.resource.ResourceMetadata;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.fsprovider.internal.ContentFileExtensions;
-import org.apache.sling.fsprovider.internal.FsResourceProvider;
+import org.apache.sling.fsprovider.internal.FsMode;
 import org.apache.sling.fsprovider.internal.mapper.jcr.FsNode;
 import org.apache.sling.fsprovider.internal.mapper.valuemap.ValueMapDecorator;
 import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
@@ -61,15 +61,15 @@ public final class FileResource extends AbstractResource {
 
     /**
      * The resource type for file system files mapped into the resource tree by
-     * the {@link FsResourceProvider} (value is "nt:file").
+     * the {@link org.apache.sling.fsprovider.internal.FsResourceProvider} (value is "nt:file").
      */
-    static final String RESOURCE_TYPE_FILE = "nt:file";
+    public static final String RESOURCE_TYPE_FILE = "nt:file";
 
     /**
      * The resource type for file system folders mapped into the resource tree
-     * by the {@link FsResourceProvider} (value is "nt:folder").
+     * by the {@link org.apache.sling.fsprovider.internal.FsResourceProvider} (value is "nt:folder").
      */
-    static final String RESOURCE_TYPE_FOLDER = "nt:folder";
+    public static final String RESOURCE_TYPE_FOLDER = "nt:folder";
 
     // the owning resource resolver
     private final ResourceResolver resolver;
@@ -92,6 +92,7 @@ public final class FileResource extends AbstractResource {
 
     private final ContentFileExtensions contentFileExtensions;
     private final ContentFileCache contentFileCache;
+    private final FsMode fsMode;
 
     private static final Logger log = LoggerFactory.getLogger(FileResource.class);
     
@@ -102,17 +103,19 @@ public final class FileResource extends AbstractResource {
      * @param resourcePath The resource path in the resource tree
      * @param file The wrapped file
      */
-    FileResource(ResourceResolver resolver, String resourcePath, File file) {
-        this(resolver, resourcePath, file, null, null);
+    FileResource(ResourceResolver resolver, String resourcePath, File file, FsMode fsMode) {
+        this(resolver, resourcePath, file, null, null, fsMode);
     }
     
     FileResource(ResourceResolver resolver, String resourcePath, File file,
-            ContentFileExtensions contentFileExtensions, ContentFileCache contentFileCache) {
+            ContentFileExtensions contentFileExtensions, ContentFileCache contentFileCache,
+            FsMode fsMode) {
         this.resolver = resolver;
         this.resourcePath = resourcePath;
         this.file = file;
         this.contentFileExtensions = contentFileExtensions;
         this.contentFileCache = contentFileCache;
+        this.fsMode = fsMode;
     }
 
     /**
@@ -133,8 +136,8 @@ public final class FileResource extends AbstractResource {
             metaData.setContentLength(file.length());
             metaData.setModificationTime(file.lastModified());
             metaData.setResolutionPath(resourcePath);
-            if ( this.file.isDirectory() ) {
-                metaData.put(FsResourceProvider.RESOURCE_METADATA_FILE_DIRECTORY, Boolean.TRUE);
+            if (fsMode == FsMode.FILES_FOLDERS && this.file.isDirectory()) {
+                metaData.put(ResourceMetadata.INTERNAL_CONTINUE_RESOLVING, Boolean.TRUE);
             }
         }
         return metaData;
@@ -221,7 +224,6 @@ public final class FileResource extends AbstractResource {
                 .build();
     }
 
-    @Override
     public ValueMap getValueMap() {
         if (valueMap == null) {
             // this resource simulates nt:file/nt:folder behavior by returning it as resource type
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResourceMapper.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResourceMapper.java
index e0a1429..e29b408 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResourceMapper.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResourceMapper.java
@@ -28,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.fsprovider.internal.ContentFileExtensions;
+import org.apache.sling.fsprovider.internal.FsMode;
 import org.apache.sling.fsprovider.internal.FsResourceMapper;
 import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
 
@@ -44,21 +45,23 @@ public final class FileResourceMapper implements FsResourceMapper {
     
     private final ContentFileExtensions contentFileExtensions;
     private final ContentFileCache contentFileCache;
+    private final FsMode fsMode;
     
     public FileResourceMapper(String providerRoot, File providerFile,
-            ContentFileExtensions contentFileExtensions, ContentFileCache contentFileCache) {
+            ContentFileExtensions contentFileExtensions, ContentFileCache contentFileCache, FsMode fsMode) {
         this.providerRoot = providerRoot;
         this.providerRootPrefix = providerRoot.concat("/");
         this.providerFile = providerFile;
         this.contentFileExtensions = contentFileExtensions;
         this.contentFileCache = contentFileCache;
+        this.fsMode = fsMode;
     }
     
     @Override
     public Resource getResource(final ResourceResolver resolver, final String resourcePath) {
         File file = getFile(resourcePath);
         if (file != null) {
-            return new FileResource(resolver, resourcePath, file, contentFileExtensions, contentFileCache);
+            return new FileResource(resolver, resourcePath, file, contentFileExtensions, contentFileCache, fsMode);
         }
         else {
             return null;
@@ -88,7 +91,7 @@ public final class FileResourceMapper implements FsResourceMapper {
                     if (providerRoot.startsWith(parentPathPrefix)) {
                         String relPath = providerRoot.substring(parentPathPrefix.length());
                         if (relPath.indexOf('/') < 0) {
-                            Resource res = new FileResource(resolver, providerRoot, providerFile, contentFileExtensions, contentFileCache);
+                            Resource res = new FileResource(resolver, providerRoot, providerFile, contentFileExtensions, contentFileCache, fsMode);
                             return IteratorUtils.singletonIterator(res);
                         }
                     }
@@ -119,7 +122,7 @@ public final class FileResourceMapper implements FsResourceMapper {
             public Object transform(Object input) {
                 File file = (File)input;
                 String path = parentPath + "/" + Escape.fileToResourceName(file.getName());
-                return new FileResource(resolver, path, file, contentFileExtensions, contentFileCache);
+                return new FileResource(resolver, path, file, contentFileExtensions, contentFileCache, fsMode);
             }
         });
     }
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileVaultResourceMapper.java b/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileVaultResourceMapper.java
index 77c5554..6665f55 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileVaultResourceMapper.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileVaultResourceMapper.java
@@ -38,6 +38,7 @@ import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.fsprovider.internal.FsMode;
 import org.apache.sling.fsprovider.internal.FsResourceMapper;
 import org.apache.sling.fsprovider.internal.parser.ContentElement;
 import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
@@ -71,7 +72,7 @@ public final class FileVaultResourceMapper implements FsResourceMapper {
         // direct file
         File file = getFile(resourcePath);
         if (file != null && file.isFile()) {
-            return new FileResource(resolver, resourcePath, file);
+            return new FileResource(resolver, resourcePath, file, FsMode.FILEVAULT_XML);
         }
         
         // content file
@@ -82,7 +83,7 @@ public final class FileVaultResourceMapper implements FsResourceMapper {
         
         // fallback to directory resource if folder was found but nothing else
         if (file != null && file.isDirectory()) {
-            return new FileResource(resolver, resourcePath, file);
+            return new FileResource(resolver, resourcePath, file, FsMode.FILEVAULT_XML);
         }
         
         return null;
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentElementImpl.java b/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentElementImpl.java
index e7d6dd3..5205c6e 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentElementImpl.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentElementImpl.java
@@ -23,7 +23,7 @@ import java.util.Map;
 
 import org.apache.commons.lang3.StringUtils;
 
-final class ContentElementImpl implements ContentElement {
+public final class ContentElementImpl implements ContentElement {
     
     private final String name;
     private final Map<String, Object> properties;
diff --git a/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java b/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
index d2b1143..978419b 100644
--- a/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
+++ b/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
@@ -18,6 +18,9 @@
  */
 package org.apache.sling.fsprovider.internal;
 
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_CHANGED;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_REMOVED;
 import static org.apache.sling.fsprovider.internal.TestUtils.assertChange;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -27,9 +30,7 @@ import java.nio.file.Files;
 import java.util.List;
 
 import org.apache.commons.io.FileUtils;
-import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
-import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.apache.sling.fsprovider.internal.FileMonitor.ResourceChange;
 import org.apache.sling.fsprovider.internal.TestUtils.ResourceListener;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -37,6 +38,8 @@ import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
 import org.apache.sling.testing.mock.sling.junit.SlingContextCallback;
 import org.junit.Rule;
 import org.junit.Test;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
 
 /**
  * Test events when changing file system content (Sling-Initial-Content).
@@ -66,14 +69,18 @@ public class FileMonitorTest {
                 // mount temp. directory
                 context.registerInjectActivateService(new FsResourceProvider(),
                         "provider.file", tempDir.getPath(),
-                        "provider.root", "/fs-test",
+                        "provider.roots", "/fs-test",
                         "provider.checkinterval", CHECK_INTERVAL,
                         "provider.fs.mode", FsMode.INITIAL_CONTENT.name(),
                         "provider.initial.content.import.options", "overwrite:=true;ignoreImportProviders:=jcr.xml");
                 
                 // register resource change listener
-                context.registerService(ResourceChangeListener.class, resourceListener,
-                        ResourceChangeListener.PATHS, new String[] { "/fs-test" });
+                context.registerService(EventHandler.class, resourceListener,
+                        EventConstants.EVENT_TOPIC, new String[] {
+                                TOPIC_RESOURCE_ADDED, 
+                                TOPIC_RESOURCE_CHANGED,
+                                TOPIC_RESOURCE_REMOVED
+                        });
             }
         })
         .afterTearDown(new SlingContextCallback() {
@@ -96,7 +103,7 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(1, changes.size());
-        assertChange(changes, "/fs-test/folder1/file1a.txt", ChangeType.CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1a.txt", TOPIC_RESOURCE_CHANGED);
     }
     
     @Test
@@ -110,8 +117,8 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/fs-test/folder1", ChangeType.CHANGED);
-        assertChange(changes, "/fs-test/folder1/file1c.txt", ChangeType.ADDED);
+        assertChange(changes, "/fs-test/folder1", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1c.txt", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -125,8 +132,8 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/fs-test/folder1", ChangeType.CHANGED);
-        assertChange(changes, "/fs-test/folder1/file1a.txt", ChangeType.REMOVED);
+        assertChange(changes, "/fs-test/folder1", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1a.txt", TOPIC_RESOURCE_REMOVED);
     }
     
     @Test
@@ -140,8 +147,8 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/fs-test", ChangeType.CHANGED);
-        assertChange(changes, "/fs-test/folder99", ChangeType.ADDED);
+        assertChange(changes, "/fs-test", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder99", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -155,8 +162,8 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/fs-test", ChangeType.CHANGED);
-        assertChange(changes, "/fs-test/folder1", ChangeType.REMOVED);
+        assertChange(changes, "/fs-test", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1", TOPIC_RESOURCE_REMOVED);
     }
 
     @Test
@@ -169,9 +176,9 @@ public class FileMonitorTest {
         
         Thread.sleep(WAIT_INTERVAL);
 
-        assertChange(changes, "/fs-test/folder2/content", ChangeType.REMOVED);
-        assertChange(changes, "/fs-test/folder2/content", ChangeType.ADDED);
-        assertChange(changes, "/fs-test/folder2/content/jcr:content", ChangeType.ADDED);
+        assertChange(changes, "/fs-test/folder2/content", TOPIC_RESOURCE_REMOVED);
+        assertChange(changes, "/fs-test/folder2/content", TOPIC_RESOURCE_ADDED);
+        assertChange(changes, "/fs-test/folder2/content/jcr:content", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -185,9 +192,9 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(3, changes.size());
-        assertChange(changes, "/fs-test/folder1", ChangeType.CHANGED);
-        assertChange(changes, "/fs-test/folder1/file1c", ChangeType.ADDED);
-        assertChange(changes, "/fs-test/folder1/file1c/child1", ChangeType.ADDED);
+        assertChange(changes, "/fs-test/folder1", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1c", TOPIC_RESOURCE_ADDED);
+        assertChange(changes, "/fs-test/folder1/file1c/child1", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -201,8 +208,8 @@ public class FileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/fs-test/folder2", ChangeType.CHANGED);
-        assertChange(changes, "/fs-test/folder2/content", ChangeType.REMOVED);
+        assertChange(changes, "/fs-test/folder2", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder2/content", TOPIC_RESOURCE_REMOVED);
     }
     
 }
diff --git a/src/test/java/org/apache/sling/fsprovider/internal/FileVaultContentTest.java b/src/test/java/org/apache/sling/fsprovider/internal/FileVaultContentTest.java
index 35b51d1..7eadfbc 100644
--- a/src/test/java/org/apache/sling/fsprovider/internal/FileVaultContentTest.java
+++ b/src/test/java/org/apache/sling/fsprovider/internal/FileVaultContentTest.java
@@ -23,7 +23,6 @@ import static org.apache.sling.fsprovider.internal.TestUtils.assertFolder;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 
 import java.util.List;
@@ -33,6 +32,7 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
 import org.apache.sling.hamcrest.ResourceMatchers;
@@ -59,13 +59,13 @@ public class FileVaultContentTest {
                 "provider.fs.mode", FsMode.FILEVAULT_XML.name(),
                 "provider.file", "src/test/resources/vaultfs-test/jcr_root",
                 "provider.filevault.filterxml.path", "src/test/resources/vaultfs-test/META-INF/vault/filter.xml",
-                "provider.root", "/content/dam/talk.png"
+                "provider.roots", "/content/dam/talk.png"
                 ))
         .plugin(new RegisterFsResourcePlugin(
                 "provider.fs.mode", FsMode.FILEVAULT_XML.name(),
                 "provider.file", "src/test/resources/vaultfs-test/jcr_root",
                 "provider.filevault.filterxml.path", "src/test/resources/vaultfs-test/META-INF/vault/filter.xml",
-                "provider.root", "/content/samples"
+                "provider.roots", "/content/samples"
                 ))
         .build();
 
@@ -86,7 +86,7 @@ public class FileVaultContentTest {
         
         Resource metadata = content.getChild("metadata");
         assertNotNull(metadata);
-        ValueMap props = metadata.getValueMap();
+        ValueMap props = ResourceUtil.getValueMap(metadata);
         assertEquals((Integer)4, props.get("app:Bitsperpixel", Integer.class));
         
         assertFolder(content, "renditions");
@@ -100,7 +100,7 @@ public class FileVaultContentTest {
         assertEquals("sling:OrderedFolder", sampleContent.getResourceType());
 
         Resource enContent = sampleContent.getChild("en/jcr:content");
-        assertArrayEquals(new String[] { "/etc/mobile/groups/responsive" }, enContent.getValueMap().get("app:deviceGroups", String[].class));
+        assertArrayEquals(new String[] { "/etc/mobile/groups/responsive" }, ResourceUtil.getValueMap(enContent).get("app:deviceGroups", String[].class));
     }
 
     @Test
@@ -139,10 +139,6 @@ public class FileVaultContentTest {
         assertNotNull(sampleContent.getChild("en/conference"));
         assertNotNull(context.resourceResolver().getResource("/content/samples/en/conference/page2"));
         assertNotNull(sampleContent.getChild("en/conference/page2"));
-        
-        // hidden because overlayed by resource provider
-        assertNull(context.resourceResolver().getResource("/content/samples/it"));
-        assertNull(sampleContent.getChild("it"));
 
         // list children with mixed content
         Resource enResource = sampleContent.getChild("en");
diff --git a/src/test/java/org/apache/sling/fsprovider/internal/FileVaultFileMonitorTest.java b/src/test/java/org/apache/sling/fsprovider/internal/FileVaultFileMonitorTest.java
index 76e0525..0475f77 100644
--- a/src/test/java/org/apache/sling/fsprovider/internal/FileVaultFileMonitorTest.java
+++ b/src/test/java/org/apache/sling/fsprovider/internal/FileVaultFileMonitorTest.java
@@ -18,6 +18,9 @@
  */
 package org.apache.sling.fsprovider.internal;
 
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_CHANGED;
+import static org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_REMOVED;
 import static org.apache.sling.fsprovider.internal.TestUtils.assertChange;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -27,9 +30,7 @@ import java.nio.file.Files;
 import java.util.List;
 
 import org.apache.commons.io.FileUtils;
-import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
-import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.apache.sling.fsprovider.internal.FileMonitor.ResourceChange;
 import org.apache.sling.fsprovider.internal.TestUtils.ResourceListener;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -37,6 +38,8 @@ import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
 import org.apache.sling.testing.mock.sling.junit.SlingContextCallback;
 import org.junit.Rule;
 import org.junit.Test;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
 
 /**
  * Test events when changing file system content (FileVault XML).
@@ -67,19 +70,23 @@ public class FileVaultFileMonitorTest {
                 context.registerInjectActivateService(new FsResourceProvider(),
                         "provider.file", tempDir.getPath() + "/jcr_root",
                         "provider.filevault.filterxml.path", tempDir.getPath() + "/META-INF/vault/filter.xml",
-                        "provider.root", "/content/dam/talk.png",
+                        "provider.roots", "/content/dam/talk.png",
                         "provider.checkinterval", CHECK_INTERVAL,
                         "provider.fs.mode", FsMode.FILEVAULT_XML.name());
                 context.registerInjectActivateService(new FsResourceProvider(),
                         "provider.file", tempDir.getPath() + "/jcr_root",
                         "provider.filevault.filterxml.path", tempDir.getPath() + "/META-INF/vault/filter.xml",
-                        "provider.root", "/content/samples",
+                        "provider.roots", "/content/samples",
                         "provider.checkinterval", CHECK_INTERVAL,
                         "provider.fs.mode", FsMode.FILEVAULT_XML.name());
                 
                 // register resource change listener
-                context.registerService(ResourceChangeListener.class, resourceListener,
-                        ResourceChangeListener.PATHS, new String[] { "/content/dam/talk.png", "/content/samples" });
+                context.registerService(EventHandler.class, resourceListener,
+                        EventConstants.EVENT_TOPIC, new String[] {
+                                TOPIC_RESOURCE_ADDED, 
+                                TOPIC_RESOURCE_CHANGED,
+                                TOPIC_RESOURCE_REMOVED
+                        });
             }
         })
         .afterTearDown(new SlingContextCallback() {
@@ -102,7 +109,7 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(1, changes.size());
-        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions/web.1280.1280.png", ChangeType.CHANGED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions/web.1280.1280.png", TOPIC_RESOURCE_CHANGED);
     }
     
     @Test
@@ -116,8 +123,8 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions", ChangeType.CHANGED);
-        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions/text.txt", ChangeType.ADDED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions/text.txt", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -131,8 +138,8 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions", ChangeType.CHANGED);
-        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions/web.1280.1280.png", ChangeType.REMOVED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions/web.1280.1280.png", TOPIC_RESOURCE_REMOVED);
     }
     
     @Test
@@ -146,8 +153,8 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/content/dam/talk.png/jcr:content", ChangeType.CHANGED);
-        assertChange(changes, "/content/dam/talk.png/jcr:content/newfolder", ChangeType.ADDED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/newfolder", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -161,8 +168,8 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/content/dam/talk.png/jcr:content", ChangeType.CHANGED);
-        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions", ChangeType.REMOVED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/content/dam/talk.png/jcr:content/renditions", TOPIC_RESOURCE_REMOVED);
     }
 
     @Test
@@ -175,9 +182,9 @@ public class FileVaultFileMonitorTest {
         
         Thread.sleep(WAIT_INTERVAL);
 
-        assertChange(changes, "/content/samples/en", ChangeType.REMOVED);
-        assertChange(changes, "/content/samples/en", ChangeType.ADDED);
-        assertChange(changes, "/content/samples/en/jcr:content", ChangeType.ADDED);
+        assertChange(changes, "/content/samples/en", TOPIC_RESOURCE_REMOVED);
+        assertChange(changes, "/content/samples/en", TOPIC_RESOURCE_ADDED);
+        assertChange(changes, "/content/samples/en/jcr:content", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -195,9 +202,9 @@ public class FileVaultFileMonitorTest {
         
         Thread.sleep(WAIT_INTERVAL);
 
-        assertChange(changes, "/content/samples", ChangeType.CHANGED);
-        assertChange(changes, "/content/samples/fr", ChangeType.ADDED);
-        assertChange(changes, "/content/samples/fr/jcr:content", ChangeType.ADDED);
+        assertChange(changes, "/content/samples", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/content/samples/fr", TOPIC_RESOURCE_ADDED);
+        assertChange(changes, "/content/samples/fr/jcr:content", TOPIC_RESOURCE_ADDED);
     }
     
     @Test
@@ -211,8 +218,8 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/content/samples", ChangeType.CHANGED);
-        assertChange(changes, "/content/samples/en", ChangeType.REMOVED);
+        assertChange(changes, "/content/samples", TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/content/samples/en", TOPIC_RESOURCE_REMOVED);
     }
     
     @Test
@@ -226,9 +233,9 @@ public class FileVaultFileMonitorTest {
         Thread.sleep(WAIT_INTERVAL);
 
         assertEquals(2, changes.size());
-        assertChange(changes, "/content/samples/en", ChangeType.CHANGED);
+        assertChange(changes, "/content/samples/en", TOPIC_RESOURCE_CHANGED);
         // this second event is not fully correct, but this is a quite special case, accept it for now 
-        assertChange(changes, "/content/samples/en", ChangeType.REMOVED);
+        assertChange(changes, "/content/samples/en", TOPIC_RESOURCE_REMOVED);
     }
     
 }
diff --git a/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java b/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
index 1b8e2a9..45ec86f 100644
--- a/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
+++ b/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
@@ -34,6 +34,7 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
 import org.apache.sling.hamcrest.ResourceMatchers;
@@ -41,6 +42,7 @@ import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -97,7 +99,7 @@ public class JcrXmlContentTest {
     public void testContent_Root() {
         Resource underTest = fsroot.getChild("folder3/content");
         assertNotNull(underTest);
-        assertEquals("app:Page", underTest.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("app:Page", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
         assertEquals("app:Page", underTest.getResourceType());
         assertThat(underTest, ResourceMatchers.hasChildren("jcr:content"));
     }
@@ -106,7 +108,7 @@ public class JcrXmlContentTest {
     public void testContent_Level1() {
         Resource underTest = fsroot.getChild("folder3/content/jcr:content");
         assertNotNull(underTest);
-        assertEquals("app:PageContent", underTest.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("app:PageContent", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
         assertEquals("samples/sample-app/components/content/page/homepage", underTest.getResourceType());
         assertThat(underTest, ResourceMatchers.hasChildren("teaserbar", "aside", "content"));
     }
@@ -115,7 +117,7 @@ public class JcrXmlContentTest {
     public void testContent_Level3() {
         Resource underTest = fsroot.getChild("folder3/content/jcr:content/content/contentheadline");
         assertNotNull(underTest);
-        assertEquals("nt:unstructured", underTest.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("nt:unstructured", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
         assertEquals("samples/sample-app/components/content/common/contentHeadline", underTest.getResourceType());
         assertFalse(underTest.listChildren().hasNext());
     }
@@ -123,7 +125,7 @@ public class JcrXmlContentTest {
     @Test
     public void testContent_Datatypes() {
         Resource underTest = fsroot.getChild("folder3/content/jcr:content");
-        ValueMap props = underTest.getValueMap();
+        ValueMap props = ResourceUtil.getValueMap(underTest);
         
         assertEquals("en", props.get("jcr:title", String.class));
         assertEquals(true, props.get("includeAside", false));
@@ -141,6 +143,7 @@ public class JcrXmlContentTest {
     }
 
     @Test
+    @Ignore  // jcr overlay is always active with the old sling resource provider API
     public void testJcrMixedContent() throws RepositoryException {
         // prepare mixed JCR content
         Node node = root.adaptTo(Node.class);
@@ -160,11 +163,11 @@ public class JcrXmlContentTest {
         Resource child1 = children.get(0);
         assertEquals("content", child1.getName());
         assertEquals("app:Page", child1.getResourceType());
-        assertEquals("app:Page", child1.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("app:Page", ResourceUtil.getValueMap(child1).get("jcr:primaryType", String.class));
 
         Resource child2 = children.get(1);
         assertEquals("folder31", child2.getName());
-        assertEquals("nt:folder", child2.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("nt:folder", ResourceUtil.getValueMap(child2).get("jcr:primaryType", String.class));
     }
 
 }
diff --git a/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java b/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
index eb4276e..02298c2 100644
--- a/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
+++ b/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
@@ -43,6 +43,7 @@ import javax.jcr.Value;
 import javax.jcr.nodetype.NodeType;
 
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
 import org.apache.sling.hamcrest.ResourceMatchers;
@@ -51,6 +52,7 @@ import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -108,7 +110,7 @@ public class JsonContentTest {
     public void testContent_Root() {
         Resource underTest = fsroot.getChild("folder2/content");
         assertNotNull(underTest);
-        assertEquals("app:Page", underTest.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("app:Page", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
         assertEquals("app:Page", underTest.getResourceType());
         assertThat(underTest, ResourceMatchers.hasChildren("jcr:content"));
     }
@@ -117,7 +119,7 @@ public class JsonContentTest {
     public void testContent_Level1() {
         Resource underTest = fsroot.getChild("folder2/content/jcr:content");
         assertNotNull(underTest);
-        assertEquals("app:PageContent", underTest.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("app:PageContent", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
         assertEquals("sample/components/homepage", underTest.getResourceType());
         assertEquals("sample/components/supertype", underTest.getResourceSuperType());
         assertThat(underTest, ResourceMatchers.hasChildren("par", "header", "newslist", "lead", "image", "carousel", "rightpar"));
@@ -127,14 +129,14 @@ public class JsonContentTest {
     public void testContent_Level5() {
         Resource underTest = fsroot.getChild("folder2/content/jcr:content/par/image/file/jcr:content");
         assertNotNull(underTest);
-        assertEquals("nt:resource", underTest.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("nt:resource", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
         assertFalse(underTest.listChildren().hasNext());
     }
 
     @Test
     public void testContent_Datatypes() {
         Resource underTest = fsroot.getChild("folder2/content/toolbar/profiles/jcr:content");
-        ValueMap props = underTest.getValueMap();
+        ValueMap props = ResourceUtil.getValueMap(underTest);
         
         assertEquals("Profiles", props.get("jcr:title", String.class));
         assertEquals(true, props.get("booleanProp", false));
@@ -149,7 +151,7 @@ public class JsonContentTest {
     @Test
     public void testContent_Datatypes_JCR() throws RepositoryException {
         Resource underTest = fsroot.getChild("folder2/content/toolbar/profiles/jcr:content");
-        ValueMap props = underTest.getValueMap();
+        ValueMap props = ResourceUtil.getValueMap(underTest);
         Node node = underTest.adaptTo(Node.class);
         
         assertEquals("/fs-test/folder2/content/toolbar/profiles/jcr:content", node.getPath());
@@ -236,6 +238,7 @@ public class JsonContentTest {
     }
 
     @Test
+    @Ignore  // jcr overlay is always active with the old sling resource provider API
     public void testJcrMixedContent() throws RepositoryException {
         // prepare mixed JCR content
         Node node = root.adaptTo(Node.class);
@@ -255,11 +258,11 @@ public class JsonContentTest {
         Resource child1 = children.get(0);
         assertEquals("content", child1.getName());
         assertEquals("app:Page", child1.getResourceType());
-        assertEquals("app:Page", child1.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("app:Page", ResourceUtil.getValueMap(child1).get("jcr:primaryType", String.class));
 
         Resource child2 = children.get(1);
         assertEquals("folder21", child2.getName());
-        assertEquals("sling:OrderedFolder", child2.getValueMap().get("jcr:primaryType", String.class));
+        assertEquals("sling:OrderedFolder", ResourceUtil.getValueMap(child2).get("jcr:primaryType", String.class));
     }
 
     @Test
@@ -268,7 +271,7 @@ public class JsonContentTest {
         assertEquals("nt:file", file21a.getResourceType());
         assertEquals("/my/super/type", file21a.getResourceSuperType());
         
-        ValueMap props = file21a.getValueMap();
+        ValueMap props = ResourceUtil.getValueMap(file21a);
         assertEquals("nt:file", props.get("jcr:primaryType", String.class));
         assertEquals("/my/super/type", props.get("sling:resourceSuperType", String.class));
         assertEquals("en", props.get("jcr:language", String.class));
diff --git a/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java b/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
index 5539a40..05a5524 100644
--- a/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
+++ b/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
@@ -36,15 +36,16 @@ import java.util.Map;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.CharEncoding;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
-import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.apache.sling.fsprovider.internal.FileMonitor.ResourceChange;
 import org.apache.sling.fsprovider.internal.mapper.Escape;
 import org.apache.sling.hamcrest.ResourceMatchers;
 import org.apache.sling.testing.mock.osgi.MapUtil;
 import org.apache.sling.testing.mock.osgi.context.AbstractContextPlugin;
 import org.apache.sling.testing.mock.sling.context.SlingContextImpl;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
 
 class TestUtils {
 
@@ -57,7 +58,7 @@ class TestUtils {
         public void beforeSetUp(SlingContextImpl context) throws Exception {
             Map<String,Object> config = new HashMap<>();
             config.put("provider.file", "src/test/resources/fs-test");
-            config.put("provider.root", "/fs-test");
+            config.put("provider.roots", "/fs-test");
             config.put("provider.checkinterval", 0);
             config.put("provider.fs.mode", FsMode.FILES_FOLDERS.name());
             config.putAll(props);
@@ -100,26 +101,30 @@ class TestUtils {
         }
     }    
 
-    public static void assertChange(List<ResourceChange> changes, String path, ChangeType changeType) {
+    public static void assertChange(List<ResourceChange> changes, String path, String topic) {
         boolean found = false;
         for (ResourceChange change : changes) {
-            if (StringUtils.equals(change.getPath(), path) && change.getType() == changeType) {
+            if (StringUtils.equals(change.path, path) && StringUtils.equals(change.topic,  topic)) {
                 found = true;
                 break;
             }
         }
-        assertTrue("Change with path=" + path + ", changeType=" + changeType + " expected", found);
+        assertTrue("Change with path=" + path + ", topic=" + topic + " expected", found);
     }
     
-    public static class ResourceListener implements ResourceChangeListener {
+    public static class ResourceListener implements EventHandler {
         private final List<ResourceChange> allChanges = new ArrayList<>();
-        @Override
-        public void onChange(List<ResourceChange> changes) {
-            allChanges.addAll(changes);
-        }
         public List<ResourceChange> getChanges() {
             return allChanges;
         }
+        @Override
+        public void handleEvent(Event event) {
+            ResourceChange change = new ResourceChange();
+            change.path = (String)event.getProperty(SlingConstants.PROPERTY_PATH);
+            change.resourceType = (String)event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE);
+            change.topic = event.getTopic();
+            allChanges.add(change);
+        }
     }
 
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.