You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2015/10/28 16:21:19 UTC
svn commit: r1711031 - in
/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl:
observation/ providers/ providers/tree/
Author: cziegeler
Date: Wed Oct 28 15:21:18 2015
New Revision: 1711031
URL: http://svn.apache.org/viewvc?rev=1711031&view=rev
Log:
SLING-5162 : Support for the new observation API in the resource resolver
Added:
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java (with props)
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java (with props)
Modified:
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerInfo.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java?rev=1711031&r1=1711030&r2=1711031&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java Wed Oct 28 15:21:18 2015
@@ -19,25 +19,98 @@
package org.apache.sling.resourceresolver.impl.observation;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Set;
import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.resourceresolver.impl.providers.tree.Path;
+import org.apache.sling.resourceresolver.impl.providers.tree.PathSet;
import org.apache.sling.spi.resource.provider.ObservationReporter;
import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+/**
+ * Implementation of the observation reporter.
+ * Each resource provider gets its on instance.
+ */
public class BasicObservationReporter implements ObservationReporter {
- private final Map<ResourceChangeListener, ObserverConfiguration> listeners;
private final List<ObserverConfiguration> configs;
- public BasicObservationReporter(Map<ResourceChangeListener, ObserverConfiguration> listeners) {
- this.listeners = new HashMap<ResourceChangeListener, ObserverConfiguration>(listeners);
- this.configs = new ArrayList<ObserverConfiguration>(listeners.values());
+ private final Map<ListenerConfig, List<ResourceChangeListenerInfo>> listeners = new HashMap<BasicObservationReporter.ListenerConfig, List<ResourceChangeListenerInfo>>();;
+
+ /**
+ * Create a reporter listening for resource provider changes
+ * @param infos The listeners map
+ */
+ public BasicObservationReporter(final Collection<ResourceChangeListenerInfo> infos) {
+ final Set<String> paths = new HashSet<String>();
+ for(final ResourceChangeListenerInfo info : infos) {
+ if ( !info.getProviderChangeTypes().isEmpty() ) {
+ for(final Path p : info.getPaths()) {
+ paths.add(p.getPath());
+ }
+ fillListeners(info, info.getResourceChangeTypes());
+ }
+ }
+ final ObserverConfiguration cfg = new BasicObserverConfiguration(paths);
+ this.configs = Collections.singletonList(cfg);
+ }
+
+ /**
+ * Create a reporter listening for a provider
+ * @param infos The listeners map
+ * @param providerPath The mount point of the provider
+ * @param excludePaths Excluded paths for that provider
+ */
+ public BasicObservationReporter(final Collection<ResourceChangeListenerInfo> infos,
+ final Path providerPath, final PathSet excludePaths) {
+ final Map<String, ObserverConfig> configMap = new HashMap<String, ObserverConfig>();
+ for(final ResourceChangeListenerInfo info : infos) {
+ if ( !info.getResourceChangeTypes().isEmpty() ) {
+ boolean add = false;
+ for(final Path p : info.getPaths()) {
+ if ( providerPath.matches(p.getPath()) && !excludePaths.matches(p.getPath()) ) {
+ ObserverConfig config = configMap.get(p);
+ if ( config == null ) {
+ config = new ObserverConfig();
+ configMap.put(p.getPath(), config);
+ }
+ config.types.addAll(info.getResourceChangeTypes());
+ if ( info.isExternal() ) {
+ config.isExternal = true;
+ }
+ add = true;
+ }
+ }
+ if ( add ) {
+ fillListeners(info, info.getResourceChangeTypes());
+ }
+ }
+ }
+ final List<ObserverConfiguration> result = new ArrayList<ObserverConfiguration>();
+ for(final Map.Entry<String, ObserverConfig> entry : configMap.entrySet()) {
+ final ObserverConfiguration cfg = new BasicObserverConfiguration(entry.getKey(), entry.getValue().types,
+ entry.getValue().isExternal, excludePaths);
+ result.add(cfg);
+ }
+ this.configs = Collections.unmodifiableList(result);
+ }
+
+ private void fillListeners(final ResourceChangeListenerInfo info, final Set<ChangeType> types) {
+ final ListenerConfig cfg = new ListenerConfig(info, types);
+ List<ResourceChangeListenerInfo> list = this.listeners.get(cfg);
+ if ( list == null ) {
+ list = new ArrayList<ResourceChangeListenerInfo>();
+ this.listeners.put(cfg, list);
+ }
+ list.add(info);
}
@Override
@@ -46,16 +119,31 @@ public class BasicObservationReporter im
}
@Override
- public void reportChanges(Iterable<ResourceChange> changes, boolean distribute) {
- for (Entry<ResourceChangeListener, ObserverConfiguration> e : listeners.entrySet()) {
- List<ResourceChange> filtered = filterChanges(changes, e.getValue());
- e.getKey().onChange(filtered);
+ public void reportChanges(final Iterable<ResourceChange> changes, final boolean distribute) {
+ final List<ResourceChange> changeList = new ArrayList<ResourceChange>();
+ for(final ResourceChange ch : changes) {
+ changeList.add(ch);
+ }
+ for (final Map.Entry<ListenerConfig, List<ResourceChangeListenerInfo>> entry : this.listeners.entrySet()) {
+ final List<ResourceChange> filtered = filterChanges(changeList, entry.getKey());
+ if ( !filtered.isEmpty() ) {
+ for(final ResourceChangeListenerInfo info : entry.getValue()) {
+ info.getListener().onChange(filtered);
+ }
+ }
}
+ // TODO implement distribute
}
- private List<ResourceChange> filterChanges(Iterable<ResourceChange> changes, ObserverConfiguration config) {
- List<ResourceChange> filtered = new ArrayList<ResourceChange>();
- for (ResourceChange c : changes) {
+ /**
+ * Filter the change list based on the configuration
+ * @param changes The list of changes
+ * @param config The configuration
+ * @return The filtered list.
+ */
+ private List<ResourceChange> filterChanges(final List<ResourceChange> changes, final ListenerConfig config) {
+ final List<ResourceChange> filtered = new ArrayList<ResourceChange>();
+ for (final ResourceChange c : changes) {
if (matches(c, config)) {
filtered.add(c);
}
@@ -63,28 +151,71 @@ public class BasicObservationReporter im
return filtered;
}
- private boolean matches(ResourceChange change, ObserverConfiguration config) {
- if (!config.getChangeTypes().contains(change.getType())) {
+ /**
+ * Match a change against the configuration
+ * @param change The change
+ * @param config The configuration
+ * @return {@code true} whether it matches
+ */
+ private boolean matches(final ResourceChange change, final ListenerConfig config) {
+ if (!config.types.contains(change.getType())) {
return false;
}
- if (!config.includeExternal() && change.isExternal()) {
+ if (!config.isExternal && change.isExternal()) {
return false;
}
- for (String excludedPath : config.getExcludedPaths()) {
- if (change.getPath().startsWith(excludedPath)) {
- return false;
- }
- }
- boolean included = false;
- for (String includedPath : config.getPaths()) {
- if (change.getPath().startsWith(includedPath)) {
- included = true;
- break;
- }
- }
- if (!included) {
+ if (!config.paths.matches(change.getPath())) {
return false;
}
return true;
}
+
+ private static final class ObserverConfig {
+ public final Set<ChangeType> types = new HashSet<ChangeType>();
+ public boolean isExternal;
+ }
+
+ private static final class ListenerConfig {
+
+ public final PathSet paths;
+
+ public final boolean isExternal;
+
+ public final Set<ChangeType> types;
+
+ public ListenerConfig(final ResourceChangeListenerInfo info, Set<ChangeType> types) {
+ this.paths = info.getPaths();
+ this.isExternal = info.isExternal();
+ this.types = types;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (isExternal ? 1231 : 1237);
+ result = prime * result + paths.hashCode();
+ result = prime * result + types.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ListenerConfig other = (ListenerConfig) obj;
+ if (isExternal != other.isExternal)
+ return false;
+ if (!paths.equals(other.paths))
+ return false;
+ if (!types.equals(other.types))
+ return false;
+ return true;
+ }
+
+ }
}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java?rev=1711031&r1=1711030&r2=1711031&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java Wed Oct 28 15:21:18 2015
@@ -18,20 +18,13 @@
*/
package org.apache.sling.resourceresolver.impl.observation;
-import static java.util.Arrays.asList;
-import static org.apache.sling.api.resource.observation.ResourceChangeListener.CHANGES;
-import static org.apache.sling.api.resource.observation.ResourceChangeListener.PATHS;
-import static org.apache.sling.commons.osgi.PropertiesUtil.toStringArray;
-
import java.util.Collections;
-import java.util.EnumSet;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.resourceresolver.impl.providers.tree.PathSet;
import org.apache.sling.spi.resource.provider.ObserverConfiguration;
-import org.osgi.framework.ServiceReference;
public class BasicObserverConfiguration implements ObserverConfiguration {
@@ -43,11 +36,22 @@ public class BasicObserverConfiguration
private final Set<ChangeType> changeTypes;
- private BasicObserverConfiguration(Builder builder) {
- this.includeExternal = builder.isIncludeExternal();
- this.paths = builder.getPaths();
- this.excludedPaths = builder.getExludedPaths();
- this.changeTypes = builder.getChangeTypes();
+ public BasicObserverConfiguration(final String path, final Set<ChangeType> types,
+ final boolean isExternal, final PathSet excludePaths) {
+ this.includeExternal = isExternal;
+ this.paths = Collections.singleton(path);
+ this.changeTypes = Collections.unmodifiableSet(types);
+ this.excludedPaths = excludePaths.getExcludes(path);
+ }
+
+ public BasicObserverConfiguration(final Set<String> paths) {
+ this.includeExternal = false;
+ this.paths = Collections.unmodifiableSet(paths);
+ final Set<ChangeType> types = new HashSet<ChangeType>();
+ types.add(ChangeType.PROVIDER_ADDED);
+ types.add(ChangeType.PROVIDER_REMOVED);
+ this.changeTypes = Collections.unmodifiableSet(types);
+ this.excludedPaths = Collections.emptySet();
}
@Override
@@ -70,115 +74,18 @@ public class BasicObserverConfiguration
return changeTypes;
}
- public static class Builder {
- private boolean includeExternal;
-
- private Set<String> paths = Collections.emptySet();
-
- private Set<String> excludedPaths = Collections.emptySet();
-
- private Set<ChangeType> changeTypes = Collections.emptySet();
-
- private String[] searchPaths = new String[0];
-
- public boolean isIncludeExternal() {
- return includeExternal;
- }
-
- public Builder setIncludeExternal(boolean includeExternal) {
- this.includeExternal = includeExternal;
- return this;
- }
-
- public Set<String> getPaths() {
- return normalizePaths(paths);
- }
-
- public Builder setPaths(Set<String> paths) {
- this.paths = paths;
- return this;
- }
-
- public Set<String> getExludedPaths() {
- return normalizePaths(excludedPaths);
- }
-
- public Builder setExcludedPaths(Set<String> excludedPaths) {
- this.excludedPaths = excludedPaths;
- return this;
- }
-
- public Set<ChangeType> getChangeTypes() {
- return changeTypes;
- }
-
- public Builder setChangeTypes(Set<ChangeType> changeTypes) {
- this.changeTypes = changeTypes;
- return this;
- }
-
- public Builder setFromServiceReference(final ServiceReference ref) {
- if (ref.getProperty(PATHS) != null ) {
- this.paths = new HashSet<String>(asList(toStringArray(ref.getProperty(PATHS))));
- } else {
- this.paths = Collections.emptySet();
- }
- if (ref.getProperty(CHANGES) != null ) {
- this.changeTypes = EnumSet.noneOf(ChangeType.class);
- for (String changeName : toStringArray(ref.getProperty(CHANGES))) {
- this.changeTypes.add(ChangeType.valueOf(changeName));
- }
- } else {
- this.changeTypes = EnumSet.allOf(ChangeType.class);
- }
- return this;
- }
-
- public Builder setSearchPaths(String[] searchPaths) {
- this.searchPaths = searchPaths;
- return this;
- }
-
- public ObserverConfiguration build() {
- return new BasicObserverConfiguration(this);
- }
-
- private Set<String> normalizePaths(Set<String> relativePaths) {
- Set<String> absolutePaths = getAbsolutePaths(relativePaths);
- removeSubPaths(absolutePaths);
- return absolutePaths;
- }
-
- private static void removeSubPaths(Set<String> absolutePaths) {
- Iterator<String> it = absolutePaths.iterator();
- while (it.hasNext()) {
- String currentPath = it.next();
- for (String p : absolutePaths) {
- if (!p.equals(currentPath) && currentPath.startsWith(p)) {
- it.remove();
- break;
- }
- }
- }
- }
-
- private Set<String> getAbsolutePaths(Set<String> relativePaths) {
- Set<String> absolutePaths = new HashSet<String>();
- if (relativePaths == null) {
- return absolutePaths;
- }
- for (String path : relativePaths) {
- if (path.startsWith("/")) {
- absolutePaths.add(path);
- } else if (".".equals(path)) {
- absolutePaths.add("/");
- } else {
- for (String searchPath : searchPaths) {
- absolutePaths.add(searchPath + path);
+ @Override
+ public boolean matches(final String path) {
+ for(final String observerPath : this.getPaths()) {
+ if ( observerPath.equals(path) || path.startsWith(observerPath.concat("/"))) {
+ for(final String excludePath : this.excludedPaths) {
+ if ( excludePath.equals(path) || path.startsWith(excludePath.concat("/")) ) {
+ return false;
}
}
+ return true;
}
- return absolutePaths;
}
+ return false;
}
}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java?rev=1711031&r1=1711030&r2=1711031&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java Wed Oct 28 15:21:18 2015
@@ -37,7 +37,7 @@ import org.apache.sling.api.resource.Log
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.api.resource.observation.ExternalResourceListener;
+import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
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;
@@ -50,7 +50,7 @@ import org.slf4j.LoggerFactory;
@Service(ResourceChangeListener.class)
@Properties({ @Property(name = ResourceChangeListener.CHANGES, value = { "ADDED", "CHANGED", "REMOVED" }),
@Property(name = ResourceChangeListener.PATHS, value = ".") })
-public class OsgiObservationBridge implements ResourceChangeListener, ExternalResourceListener {
+public class OsgiObservationBridge implements ResourceChangeListener, ExternalResourceChangeListener {
private static final Logger logger = LoggerFactory.getLogger(OsgiObservationBridge.class);
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerInfo.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerInfo.java?rev=1711031&r1=1711030&r2=1711031&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerInfo.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerInfo.java Wed Oct 28 15:21:18 2015
@@ -27,19 +27,26 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
+import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.apache.sling.resourceresolver.impl.providers.tree.PathSet;
import org.osgi.framework.ServiceReference;
public class ResourceChangeListenerInfo {
- private final Set<String> paths;
+ private final PathSet paths;
- private final Set<ChangeType> changeTypes;
+ private final Set<ChangeType> resourceChangeTypes;
+
+ private final Set<ChangeType> providerChangeTypes;
private final boolean valid;
private volatile boolean external = false;
+ private volatile ResourceChangeListener listener;
+
public ResourceChangeListenerInfo(final ServiceReference ref, final String[] searchPaths) {
boolean configValid = true;
final Set<String> pathsSet = new HashSet<String>();
@@ -80,12 +87,12 @@ public class ResourceChangeListenerInfo
}
}
}
- this.paths = Collections.unmodifiableSet(pathsSet);
+ this.paths = new PathSet(pathsSet);
final Set<ChangeType> typesSet = new HashSet<ChangeType>();
if (ref.getProperty(CHANGES) != null ) {
for (String changeName : toStringArray(ref.getProperty(CHANGES))) {
try {
- this.changeTypes.add(ChangeType.valueOf(changeName));
+ typesSet.add(ChangeType.valueOf(changeName));
} catch ( final IllegalArgumentException iae) {
configValid = false;
}
@@ -96,7 +103,27 @@ public class ResourceChangeListenerInfo
typesSet.add(ChangeType.CHANGED);
typesSet.add(ChangeType.REMOVED);
}
- this.changeTypes = Collections.unmodifiableSet(typesSet);
+ final Set<ChangeType> rts = new HashSet<ChangeType>();
+ if ( typesSet.contains(ChangeType.ADDED)) {
+ rts.add(ChangeType.ADDED);
+ }
+ if ( typesSet.contains(ChangeType.CHANGED)) {
+ rts.add(ChangeType.CHANGED);
+ }
+ if ( typesSet.contains(ChangeType.REMOVED)) {
+ rts.add(ChangeType.REMOVED);
+ }
+ this.resourceChangeTypes = Collections.unmodifiableSet(rts);
+
+ final Set<ChangeType> pts = new HashSet<ChangeType>();
+ if ( typesSet.contains(ChangeType.PROVIDER_ADDED)) {
+ pts.add(ChangeType.PROVIDER_ADDED);
+ }
+ if ( typesSet.contains(ChangeType.PROVIDER_REMOVED)) {
+ pts.add(ChangeType.PROVIDER_REMOVED);
+ }
+ this.providerChangeTypes = Collections.unmodifiableSet(pts);
+
this.valid = configValid;
}
@@ -104,19 +131,28 @@ public class ResourceChangeListenerInfo
return this.valid;
}
- public Set<ChangeType> getChangeTypes() {
- return this.changeTypes;
+ public Set<ChangeType> getResourceChangeTypes() {
+ return this.resourceChangeTypes;
}
- public Set<String> getPaths() {
- return this.paths;
+ public Set<ChangeType> getProviderChangeTypes() {
+ return this.providerChangeTypes;
}
- public void setExternal(final boolean flag) {
- this.external = flag;
+ public PathSet getPaths() {
+ return this.paths;
}
public boolean isExternal() {
return this.external;
}
+
+ public ResourceChangeListener getListener() {
+ return listener;
+ }
+
+ public void setListener(final ResourceChangeListener listener) {
+ this.listener = listener;
+ this.external = listener instanceof ExternalResourceChangeListener;
+ }
}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java?rev=1711031&r1=1711030&r2=1711031&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java Wed Oct 28 15:21:18 2015
@@ -19,12 +19,16 @@
package org.apache.sling.resourceresolver.impl.observation;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.sling.api.resource.observation.ExternalResourceListener;
+import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker.ObservationReporterGenerator;
+import org.apache.sling.resourceresolver.impl.providers.tree.Path;
+import org.apache.sling.resourceresolver.impl.providers.tree.PathSet;
import org.apache.sling.spi.resource.provider.ObservationReporter;
import org.apache.sling.spi.resource.provider.ObserverConfiguration;
import org.osgi.framework.BundleContext;
@@ -35,14 +39,10 @@ import org.osgi.util.tracker.ServiceTrac
/**
* Tracker component for the resource change listeners.
*/
-public class ResourceChangeListenerWhiteboard {
-
- private static final ObservationReporter EMPTY_REPORTER = new BasicObservationReporter(Collections.<ResourceChangeListener, ObserverConfiguration> emptyMap());
+public class ResourceChangeListenerWhiteboard implements ResourceProviderTracker.ObservationReporterGenerator {
private final Map<ServiceReference, ResourceChangeListenerInfo> listeners = new ConcurrentHashMap<ServiceReference, ResourceChangeListenerInfo>();
- private volatile String[] searchPaths;
-
private volatile ResourceProviderTracker resourceProviderTracker;
private volatile ServiceTracker tracker;
@@ -50,9 +50,8 @@ public class ResourceChangeListenerWhite
public void activate(final BundleContext bundleContext,
final ResourceProviderTracker resourceProviderTracker,
final String[] searchPaths) {
- this.searchPaths = searchPaths;
this.resourceProviderTracker = resourceProviderTracker;
- this.resourceProviderTracker.setObservationReporter(EMPTY_REPORTER);
+ this.resourceProviderTracker.setObservationReporterGenerator(this);
this.tracker = new ServiceTracker(bundleContext,
ResourceChangeListener.class.getName(),
new ServiceTrackerCustomizer() {
@@ -78,7 +77,7 @@ public class ResourceChangeListenerWhite
if ( info.isValid() ) {
final ResourceChangeListener listener = (ResourceChangeListener) bundleContext.getService(reference);
if ( listener != null ) {
- info.setExternal(listener instanceof ExternalResourceListener);
+ info.setListener(listener);
listeners.put(reference, info);
updateProviderTracker();
}
@@ -94,13 +93,47 @@ public class ResourceChangeListenerWhite
this.tracker.close();
this.tracker = null;
}
- this.searchPaths = null;
- this.resourceProviderTracker.setObservationReporter(EMPTY_REPORTER);
+ this.resourceProviderTracker.setObservationReporterGenerator(NOP_GENERATOR);
this.resourceProviderTracker = null;
}
private void updateProviderTracker() {
- // TODO
- this.resourceProviderTracker.setObservationReporter(EMPTY_REPORTER);
+ this.resourceProviderTracker.setObservationReporterGenerator(this);
+ }
+
+ @Override
+ public ObservationReporter create(final Path path, final PathSet excludes) {
+ return new BasicObservationReporter(this.listeners.values(), path, excludes);
}
+
+ @Override
+ public ObservationReporter createProviderReporter() {
+ return new BasicObservationReporter(this.listeners.values());
+ }
+
+ private static final ObservationReporter EMPTY_REPORTER = new ObservationReporter() {
+
+ @Override
+ public void reportChanges(Iterable<ResourceChange> changes, boolean distribute) {
+ // ignore
+ }
+
+ @Override
+ public List<ObserverConfiguration> getObserverConfigurations() {
+ return Collections.emptyList();
+ }
+ };
+
+ private static final ObservationReporterGenerator NOP_GENERATOR = new ObservationReporterGenerator() {
+
+ @Override
+ public ObservationReporter create(Path path, PathSet excludes) {
+ return EMPTY_REPORTER;
+ }
+
+ @Override
+ public ObservationReporter createProviderReporter() {
+ return EMPTY_REPORTER;
+ }
+ };
}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java?rev=1711031&r1=1711030&r2=1711031&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java Wed Oct 28 15:21:18 2015
@@ -38,6 +38,8 @@ import org.apache.sling.api.resource.run
import org.apache.sling.api.resource.runtime.dto.ResourceProviderFailureDTO;
import org.apache.sling.api.resource.runtime.dto.RuntimeDTO;
import org.apache.sling.resourceresolver.impl.legacy.LegacyResourceProviderWhiteboard;
+import org.apache.sling.resourceresolver.impl.providers.tree.Path;
+import org.apache.sling.resourceresolver.impl.providers.tree.PathSet;
import org.apache.sling.spi.resource.provider.ObservationReporter;
import org.apache.sling.spi.resource.provider.ProviderContext;
import org.apache.sling.spi.resource.provider.ResourceProvider;
@@ -56,6 +58,13 @@ import org.slf4j.LoggerFactory;
*/
public class ResourceProviderTracker {
+ public interface ObservationReporterGenerator {
+
+ ObservationReporter create(final Path path, final PathSet excludes);
+
+ ObservationReporter createProviderReporter();
+ }
+
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Map<ServiceReference, ResourceProviderInfo> infos = new ConcurrentHashMap<ServiceReference, ResourceProviderInfo>();
@@ -70,10 +79,12 @@ public class ResourceProviderTracker {
private volatile EventAdmin eventAdmin;
- private volatile ObservationReporter reporter;
+ private volatile ObservationReporterGenerator reporterGenerator;
private volatile ResourceProviderStorage storage;
+ private volatile ObservationReporter providerReporter;
+
public void activate(final BundleContext bundleContext, final EventAdmin eventAdmin) {
this.bundleContext = bundleContext;
this.eventAdmin = eventAdmin;
@@ -117,8 +128,9 @@ public class ResourceProviderTracker {
this.invalidProviders.clear();
}
- public void setObservationReporter(final ObservationReporter report) {
- this.reporter = report;
+ public void setObservationReporterGenerator(final ObservationReporterGenerator generator) {
+ this.reporterGenerator = generator;
+ this.providerReporter = generator.createProviderReporter();
}
/**
@@ -239,9 +251,14 @@ public class ResourceProviderTracker {
eventAdmin.postEvent(new Event(topic, eventProps));
}
+ /**
+ * Post a change event for a resource provider change
+ * @param type The change type
+ * @param info The resource provider
+ */
private void postResourceProviderChange(ChangeType type, final ResourceProviderInfo info) {
ResourceChange change = new ResourceChange(type, info.getPath(), false, null, null, null);
- this.reporter.reportChanges(Collections.singletonList(change), false);
+ this.providerReporter.reportChanges(Collections.singletonList(change), false);
}
/**
@@ -325,13 +342,12 @@ public class ResourceProviderTracker {
private ProviderContext createProviderContext(final ResourceProviderHandler handler) {
final Set<String> excludedPaths = new HashSet<String>();
- String path = handler.getInfo().getPath();
- for (String providerPath : handlers.keySet()) {
- if (providerPath.startsWith(path)) {
- excludedPaths.add(providerPath);
+ final Path handlerPath = new Path(handler.getPath());
+ for(final String otherPath : handlers.keySet()) {
+ if ( !handler.getPath().equals(otherPath) && handlerPath.matches(otherPath) ) {
+ excludedPaths.add(otherPath);
}
}
- excludedPaths.remove(path);
- return new ProviderContextImpl(reporter, excludedPaths);
+ return new ProviderContextImpl(reporterGenerator.create(handlerPath, new PathSet(excludedPaths)), excludedPaths);
}
}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java?rev=1711031&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java Wed Oct 28 15:21:18 2015
@@ -0,0 +1,45 @@
+/*
+ * 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.resourceresolver.impl.providers.tree;
+
+/**
+ * Simple helper class for path matching.
+ */
+public class Path {
+
+ private final String path;
+
+ private final String prefix;
+
+ public Path(final String path) {
+ this.path = path;
+ this.prefix = path.concat("/");
+ }
+
+ public boolean matches(final String otherPath) {
+ if ( this.path.equals(otherPath) || otherPath.startsWith(this.prefix) ) {
+ return true;
+ }
+ return false;
+ }
+
+ public String getPath() {
+ return this.path;
+ }
+}
\ No newline at end of file
Propchange: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Path.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java?rev=1711031&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java Wed Oct 28 15:21:18 2015
@@ -0,0 +1,91 @@
+/*
+ * 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.resourceresolver.impl.providers.tree;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Simple helper class for path matching against a set of paths.
+ */
+public class PathSet implements Iterable<Path> {
+
+ private final Set<Path> paths;
+
+ public PathSet(final Set<String> paths) {
+ this.paths = new HashSet<Path>();
+ for(final String p : paths) {
+ this.paths.add(new Path(p));
+ }
+ }
+
+ public boolean matches(final String otherPath) {
+ for(final Path p : this.paths) {
+ if ( p.matches(otherPath) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Generate an unmodifiable set of exclude paths
+ * @param path The base path
+ * @return Set of exclude paths
+ */
+ public Set<String> getExcludes(final String path) {
+ final Path pathObj = new Path(path);
+ final Set<String> result = new HashSet<String>();
+ for(final Path p : this.paths) {
+ if ( pathObj.matches(p.getPath()) ) {
+ result.add(p.getPath());
+ }
+ }
+ return Collections.unmodifiableSet(result);
+ }
+
+ @Override
+ public Iterator<Path> iterator() {
+ return this.paths.iterator();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + paths.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PathSet other = (PathSet) obj;
+ if (!paths.equals(other.paths))
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
Propchange: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSet.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url