SLING-6174 : reverting rev 1771884 due to dependency on oak 1.5.14 snapshot
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/resource@1771944 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 6925b0a..057d5d6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,8 +50,8 @@
<properties>
<site.jira.version.id>12314286</site.jira.version.id>
<site.javadoc.exclude>**.internal.**</site.javadoc.exclude>
- <oak.version>1.5.13</oak.version>
- <jackrabbit.version>2.13.4</jackrabbit.version>
+ <oak.version>1.3.10</oak.version>
+ <jackrabbit.version>2.11.2</jackrabbit.version>
</properties>
<build>
@@ -135,13 +135,6 @@
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
- <artifactId>oak-jcr</artifactId>
- <version>${oak.version}</version>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.jackrabbit</groupId>
<artifactId>oak-core</artifactId>
<version>${oak.version}</version>
<scope>test</scope>
@@ -254,6 +247,12 @@
<version>1.4</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>oak-jcr</artifactId>
+ <version>${oak.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java b/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java
index d0dba96..69be949 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java
@@ -25,13 +25,13 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;
import org.apache.jackrabbit.api.observation.JackrabbitEventFilter;
import org.apache.jackrabbit.api.observation.JackrabbitObservationManager;
-import org.apache.jackrabbit.oak.jcr.observation.filter.FilterFactory;
-import org.apache.jackrabbit.oak.jcr.observation.filter.OakEventFilter;
+import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
import org.apache.sling.api.resource.path.Path;
import org.apache.sling.jcr.api.SlingRepository;
@@ -63,7 +63,6 @@
throws RepositoryException {
this.pathMapper = pathMapper;
this.reporter = reporter;
- // The session should have read access on the whole repository
this.session = repository.loginAdministrative(repository.getDefaultWorkspace());
}
@@ -76,47 +75,107 @@
this.session.logout();
}
- /**
- * Register a JCR event listener
- * @param listener The listener
- * @param config The configuration
- * @throws RepositoryException If registration fails.
- */
- public void register(final EventListener listener, final ObserverConfiguration config)
+ public void register(final JcrResourceListener listener, final ObserverConfiguration config)
throws RepositoryException {
final ObservationManager mgr = this.session.getWorkspace().getObservationManager();
if ( mgr instanceof JackrabbitObservationManager ) {
- final OakEventFilter filter = FilterFactory.wrap(new JackrabbitEventFilter());
+ final JackrabbitEventFilter filter = new JackrabbitEventFilter();
+
// paths
final Set<String> paths = config.getPaths().toStringSet();
- int globCount = 0, pathCount = 0;
+ final String[] pathArray = new String[paths.size()];
+ int i=0;
+ // remove global prefix
+ boolean hasGlob = false;
for(final String p : paths) {
if ( p.startsWith(Path.GLOB_PREFIX )) {
- globCount++;
- } else {
- pathCount++;
+ hasGlob = true;
}
+ pathArray[i] = (p.startsWith(Path.GLOB_PREFIX) ? p.substring(Path.GLOB_PREFIX.length()) : p);
+ i++;
}
- final String[] pathArray = pathCount > 0 ? new String[pathCount] : null;
- final String[] globArray = globCount > 0 ? new String[globCount] : null;
- pathCount = 0;
- globCount = 0;
+ final EventListener regListener;
+ if ( hasGlob ) {
+ // TODO we can't use glob patterns directly here
+ filter.setAbsPath("/");
+ regListener = new EventListener() {
- // create arrays and remove global prefix
- for(final String p : paths) {
- if ( p.startsWith(Path.GLOB_PREFIX )) {
- globArray[globCount] = p.substring(Path.GLOB_PREFIX.length());
- globCount++;
- } else {
- pathArray[pathCount] = p;
- pathCount++;
- }
- }
- if ( globArray != null ) {
- filter.withIncludeGlobPaths(globArray);
- }
- if ( pathArray != null ) {
+ @Override
+ public void onEvent(final EventIterator events) {
+ listener.onEvent(new EventIterator() {
+
+ Event next = seek();
+
+ private Event seek() {
+ while ( events.hasNext() ) {
+ final Event e = events.nextEvent();
+ String path = null;
+ try {
+ path = e.getPath();
+ if ( e.getType() == Event.PROPERTY_ADDED
+ || e.getType() == Event.PROPERTY_CHANGED
+ || e.getType() == Event.PROPERTY_REMOVED ) {
+ path = ResourceUtil.getParent(path);
+ }
+ if ( config.getPaths().matches(path) != null ) {
+ return e;
+ }
+ if ( path.endsWith("/jcr:content") && config.getPaths().matches(path.substring(0, path.length() - 12)) != null ) {
+ return e;
+
+ }
+ } catch (RepositoryException e1) {
+ // ignore
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ // we don't support this -> NOP
+ }
+
+ @Override
+ public Object next() {
+ return nextEvent();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public void skip(long skipNum) {
+ // we don't support this -> NOP
+ }
+
+ @Override
+ public long getSize() {
+ // we don't support this -> 0
+ return 0;
+ }
+
+ @Override
+ public long getPosition() {
+ // we don't support this -> 0
+ return 0;
+ }
+
+ @Override
+ public Event nextEvent() {
+ final Event result = next;
+ next = seek();
+ return result;
+ }
+ });
+ }
+ };
+
+ } else {
filter.setAdditionalPaths(pathArray);
+ regListener = listener;
}
filter.setIsDeep(true);
@@ -132,24 +191,13 @@
// types
filter.setEventTypes(this.getTypes(config));
- // nt:file handling
- filter.withNodeTypeAggregate(new String[] {"nt:file"}, new String[] {"", "jcr:content"});
-
- // anchestor removes
- filter.withIncludeAncestorsRemove();
-
- ((JackrabbitObservationManager)mgr).addEventListener(listener, filter);
+ ((JackrabbitObservationManager)mgr).addEventListener(regListener, filter);
} else {
throw new RepositoryException("Observation manager is not a JackrabbitObservationManager");
}
}
- /**
- * Get the event types based on the configuraiton
- * @param c The configuration
- * @return The event type mask
- */
private int getTypes(final ObserverConfiguration c) {
int result = 0;
for (ChangeType t : c.getChangeTypes()) {
@@ -172,22 +220,18 @@
return result;
}
- /**
- * Unregister the listener.
- * @param listener The listener
- */
- public void unregister(final EventListener listener) {
+ public void unregister(final JcrResourceListener listener) {
try {
this.session.getWorkspace().getObservationManager().removeEventListener(listener);
- } catch (final RepositoryException e) {
+ } catch (RepositoryException e) {
logger.warn("Unable to remove session listener: " + this, e);
}
}
- /**
- * The observation reporter
- * @return The observation reporter.
- */
+ public Logger getLogger() {
+ return this.logger;
+ }
+
public ObservationReporter getReporter() {
return this.reporter;
}
@@ -195,4 +239,8 @@
public PathMapper getPathMapper() {
return this.pathMapper;
}
+
+ public Session getSession() {
+ return this.session;
+ }
}
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java b/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
index 24c7109..3b48366 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
@@ -30,12 +30,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.observation.JackrabbitEvent;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
@@ -61,24 +64,11 @@
this.baseConfig.register(this, config);
}
- /**
- * Update the observation configuration.
- *
- * @param cfg The updated config
- */
public void update(final ObserverConfiguration cfg) {
this.config = cfg;
}
/**
- * Get the observation configuration
- * @return The observation configuration
- */
- public ObserverConfiguration getConfig() {
- return this.config;
- }
-
- /**
* Dispose this listener.
*/
@Override
@@ -96,55 +86,39 @@
final Map<String, ResourceChange> changedEvents = new HashMap<String, ResourceChange>();
final Map<String, ResourceChange> removedEvents = new HashMap<String, ResourceChange>();
+ AtomicBoolean refreshedSession = new AtomicBoolean(false);
while ( events.hasNext() ) {
final Event event = events.nextEvent();
- final String identifier;
- final String path;
try {
- identifier = event.getIdentifier();
- path = event.getPath();
- } catch (final RepositoryException e) {
- // event.getPath or event.getIdentifier threw an exception
- // there is nothing we can do about it anyway
- continue;
- }
+ final String eventPath = event.getPath();
+ final int type = event.getType();
- final String eventPath = (identifier != null && identifier.startsWith("/") ? identifier : path);
- final int type = event.getType();
-
- if ( type == PROPERTY_ADDED && path.endsWith("/jcr:primaryType") ) {
- final int lastSlash = path.lastIndexOf('/');
- final String rsrcPath = path.substring(0, lastSlash);
-
- // add is stronger than update
- changedEvents.remove(rsrcPath);
- addedEvents.put(rsrcPath, createResourceChange(event, rsrcPath, ChangeType.ADDED));
- } else if ( type == PROPERTY_ADDED
+ if ( type == PROPERTY_ADDED
|| type == PROPERTY_REMOVED
|| type == PROPERTY_CHANGED ) {
- final String rsrcPath;
- if ( identifier == null || !identifier.startsWith("/") ) {
final int lastSlash = eventPath.lastIndexOf('/');
- rsrcPath = eventPath.substring(0, lastSlash);
- } else {
- rsrcPath = eventPath;
- }
- if ( !addedEvents.containsKey(rsrcPath)
- && !removedEvents.containsKey(rsrcPath)
- && !changedEvents.containsKey(rsrcPath) ) {
+ final String rsrcPath = stripNtFilePath(eventPath.substring(0, lastSlash), refreshedSession);
+ if ( !addedEvents.containsKey(rsrcPath)
+ && !removedEvents.containsKey(rsrcPath)
+ && !changedEvents.containsKey(rsrcPath) ) {
- changedEvents.put(rsrcPath, createResourceChange(event, rsrcPath, ChangeType.CHANGED));
+ changedEvents.put(rsrcPath, createResourceChange(event, rsrcPath, ChangeType.CHANGED));
+ }
+ } else {
+ if ( type == NODE_ADDED ) {
+ // add is stronger than update
+ changedEvents.remove(eventPath);
+ addedEvents.put(eventPath, createResourceChange(event, eventPath, ChangeType.ADDED));
+ } else if ( type == NODE_REMOVED) {
+ // remove is stronger than add and change
+ addedEvents.remove(eventPath);
+ changedEvents.remove(eventPath);
+ removedEvents.put(eventPath, createResourceChange(event, eventPath, ChangeType.REMOVED));
+ }
}
- } else if ( type == NODE_ADDED ) {
- // add is stronger than update
- changedEvents.remove(eventPath);
- addedEvents.put(eventPath, createResourceChange(event, eventPath, ChangeType.ADDED));
- } else if ( type == NODE_REMOVED) {
- // remove is stronger than add and change
- addedEvents.remove(eventPath);
- changedEvents.remove(eventPath);
- removedEvents.put(eventPath, createResourceChange(event, eventPath, ChangeType.REMOVED));
+ } catch (final RepositoryException e) {
+ this.baseConfig.getLogger().error("Error during modification: {}", e);
}
}
@@ -178,8 +152,31 @@
return false;
}
+ private static final String JCR_CONTENT_POSTFIX = "/" + JcrConstants.JCR_CONTENT;
+
+ private String stripNtFilePath(final String path, final AtomicBoolean refreshedSession) {
+ if (!path.endsWith(JCR_CONTENT_POSTFIX)) {
+ return path;
+ }
+ try {
+ if ( refreshedSession.compareAndSet(false, true) ) {
+ baseConfig.getSession().refresh(false);
+ }
+ final Node node = baseConfig.getSession().getNode(path);
+ final Node parent = node.getParent();
+ if (parent.isNodeType(JcrConstants.NT_FILE)) {
+ return parent.getPath();
+ } else {
+ return path;
+ }
+ } catch (final RepositoryException e) {
+ return path;
+ }
+ }
+
@Override
public String toString() {
return "JcrResourceListener [" + config + "]";
}
+
}
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderState.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderState.java
index b19e530..77671dc 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderState.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderState.java
@@ -23,7 +23,6 @@
import javax.jcr.Session;
-import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.resource.internal.HelperData;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
@@ -34,7 +33,7 @@
private final BundleContext bundleContext;
- private final ServiceReference<SlingRepository> repositoryRef;
+ private final ServiceReference repositoryRef;
private final boolean logout;
@@ -42,15 +41,11 @@
private final HelperData helperData;
- JcrProviderState(final Session session, final HelperData helperData, final boolean logout) {
+ JcrProviderState(Session session, HelperData helperData, boolean logout) {
this(session, helperData, logout, null, null);
}
- JcrProviderState(final Session session,
- final HelperData helperData,
- final boolean logout,
- final BundleContext bundleContext,
- final ServiceReference<SlingRepository> repositoryRef) {
+ JcrProviderState(Session session, HelperData helperData, boolean logout, BundleContext bundleContext, ServiceReference repositoryRef) {
this.session = session;
this.bundleContext = bundleContext;
this.repositoryRef = repositoryRef;
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderStateFactory.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderStateFactory.java
index 7a1a8e1..2169586 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderStateFactory.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrProviderStateFactory.java
@@ -50,7 +50,7 @@
private final Logger logger = LoggerFactory.getLogger(JcrProviderStateFactory.class);
- private final ServiceReference<SlingRepository> repositoryReference;
+ private final ServiceReference repositoryReference;
private final SlingRepository repository;
@@ -58,7 +58,7 @@
private final PathMapper pathMapper;
- public JcrProviderStateFactory(final ServiceReference<SlingRepository> repositoryReference,
+ public JcrProviderStateFactory(final ServiceReference repositoryReference,
final SlingRepository repository,
final AtomicReference<DynamicClassLoaderManager> dynamicClassLoaderManagerReference,
final PathMapper pathMapper) {
@@ -67,8 +67,8 @@
this.dynamicClassLoaderManagerReference = dynamicClassLoaderManagerReference;
this.pathMapper = pathMapper;
}
-
- /** Get the calling Bundle from auth info, fail if not provided
+
+ /** Get the calling Bundle from auth info, fail if not provided
* @throws LoginException if no calling bundle info provided
*/
@CheckForNull
@@ -98,7 +98,7 @@
final Bundle bundle = extractCallingBundle(authenticationInfo);
if (bundle != null) {
bc = bundle.getBundleContext();
- final SlingRepository repo = bc.getService(repositoryReference);
+ final SlingRepository repo = (SlingRepository) bc.getService(repositoryReference);
if (repo == null) {
logger.warn("Cannot login {} because cannot get SlingRepository on behalf of bundle {} ({})",
isLoginAdministrative ? "admin" : "service",
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
index bb28dde..172b115 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
@@ -60,7 +60,6 @@
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.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
@@ -81,8 +80,7 @@
ResourceProvider.PROPERTY_ADAPTABLE + ":Boolean=true",
ResourceProvider.PROPERTY_ATTRIBUTABLE + ":Boolean=true",
ResourceProvider.PROPERTY_REFRESHABLE + ":Boolean=true",
- ResourceProvider.PROPERTY_AUTHENTICATE + "=" + ResourceProvider.AUTHENTICATE_REQUIRED,
- Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
+ ResourceProvider.PROPERTY_AUTHENTICATE + "=" + ResourceProvider.AUTHENTICATE_REQUIRED
})
public class JcrResourceProvider extends ResourceProvider<JcrProviderState> {
@@ -113,7 +111,7 @@
private volatile JcrListenerBaseConfig listenerConfig;
/** The JCR observation listeners. */
- private final Map<ObserverConfiguration, Closeable> listeners = new HashMap<>();
+ private volatile Map<ObserverConfiguration, Closeable> listeners = new HashMap<>();
private volatile SlingRepository repository;
@@ -192,13 +190,11 @@
*/
private void registerListeners() {
if ( this.repository != null ) {
- logger.debug("Registering resource listeners...");
try {
this.listenerConfig = new JcrListenerBaseConfig(this.getProviderContext().getObservationReporter(),
this.pathMapper,
this.repository);
for(final ObserverConfiguration config : this.getProviderContext().getObservationReporter().getObserverConfigurations()) {
- logger.debug("Registering listener for {}", config.getPaths());
final Closeable listener = new JcrResourceListener(this.listenerConfig,
config);
this.listeners.put(config, listener);
@@ -206,7 +202,6 @@
} catch (final RepositoryException e) {
throw new SlingException("Can't create the JCR event listener.", e);
}
- logger.debug("Registered resource listeners");
}
}
@@ -214,10 +209,8 @@
* Unregister all observation listeners.
*/
private void unregisterListeners() {
- logger.debug("Unregistering resource listeners...");
for(final Closeable c : this.listeners.values()) {
try {
- logger.debug("Removing listener for {}", ((JcrResourceListener)c).getConfig().getPaths());
c.close();
} catch (final IOException e) {
// ignore this as the method above does not throw it
@@ -232,7 +225,6 @@
}
this.listenerConfig = null;
}
- logger.debug("Unregistered resource listeners");
}
/**
@@ -243,7 +235,6 @@
this.unregisterListeners();
this.registerListeners();
} else {
- logger.debug("Updating resource listeners...");
final Map<ObserverConfiguration, Closeable> oldMap = new HashMap<>(this.listeners);
this.listeners.clear();
try {
@@ -251,10 +242,8 @@
// check if such a listener already exists
Closeable listener = oldMap.remove(config);
if ( listener == null ) {
- logger.debug("Registering listener for {}", config.getPaths());
listener = new JcrResourceListener(this.listenerConfig, config);
} else {
- logger.debug("Updating listener for {}", config.getPaths());
((JcrResourceListener)listener).update(config);
}
this.listeners.put(config, listener);
@@ -264,13 +253,11 @@
}
for(final Closeable c : oldMap.values()) {
try {
- logger.debug("Removing listener for {}", ((JcrResourceListener)c).getConfig().getPaths());
c.close();
} catch (final IOException e) {
// ignore this as the method above does not throw it
}
}
- logger.debug("Updated resource listeners");
}
}
diff --git a/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java b/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
index 00acb9f..3091b32 100644
--- a/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
+++ b/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
@@ -160,7 +160,7 @@
};
this.config.unregister(this.listener);
this.listener = null;
- final Session session = this.adminSession;
+ final Session session = this.config.getSession();
if ( !session.nodeExists("/libs") ) {
createNode(session, "/libs");
}