You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by an...@apache.org on 2021/04/07 21:22:32 UTC
[sling-whiteboard] branch master updated: Added support for changes
in References
This is an automated email from the ASF dual-hosted git repository.
andysch pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
The following commit(s) were added to refs/heads/master by this push:
new 77bc17b Added support for changes in References
77bc17b is described below
commit 77bc17be00ec92c56a17b75680a71cea97b6aee2
Author: Andreas Schaefer <sc...@me.com>
AuthorDate: Wed Apr 7 14:22:16 2021 -0700
Added support for changes in References
---
.../ddr/api/DeclarativeDynamicResourceManager.java | 9 ++
.../api/DeclarativeDynamicResourceProvider.java | 1 +
.../DeclarativeDynamicResourceManagerService.java | 137 +++++++++++++++++++--
.../DeclarativeDynamicResourceProviderHandler.java | 5 +
...larativeDynamicResourceProviderHandlerTest.java | 13 +-
5 files changed, 150 insertions(+), 15 deletions(-)
diff --git a/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceManager.java b/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceManager.java
index acb046f..0edb6b8 100644
--- a/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceManager.java
+++ b/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceManager.java
@@ -29,4 +29,13 @@ public interface DeclarativeDynamicResourceManager {
* @param declarativeDynamicProviderPath Path to the Folder where the declarative dynamic resources are located in
*/
void update(String declarativeDynamicProviderPath);
+
+ /**
+ * Add a given Path as Reference to listen for changes in references.
+ * If a parent path of that ref is already register it is ignored.
+ *
+ * @param sourcePath Path of the Source of the Reference
+ * @param targetPath Path of the Target of the Reference
+ */
+ void addReference(String sourcePath, String targetPath);
}
diff --git a/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceProvider.java b/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceProvider.java
index cc064c6..1602c1e 100644
--- a/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceProvider.java
+++ b/org.apache.sling.ddr/api/src/main/java/org/apache/sling/ddr/api/DeclarativeDynamicResourceProvider.java
@@ -38,6 +38,7 @@ public interface DeclarativeDynamicResourceProvider {
*/
long registerService(
Bundle bundle, String targetRootPath, String providerRootPath, ResourceResolverFactory resourceResolverFactory,
+ DeclarativeDynamicResourceManager declarativeDynamicResourceManager,
Map<String, List<String>> allowedDDRFilter, Map<String, List<String>> prohibitedDDRFilter, List<String> followedLinkNames
);
diff --git a/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceManagerService.java b/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceManagerService.java
index 4c91735..1c8c9cd 100644
--- a/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceManagerService.java
+++ b/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceManagerService.java
@@ -118,6 +118,8 @@ public class DeclarativeDynamicResourceManagerService
private Map<String, List<String>> prohibitedFilter = new HashMap<>();
private List<String> followedLinkNames = new ArrayList<>();
+ private Map<String, ReferenceEventListener> referenceListeners = new HashMap<>();
+
@Activate
void activate(BundleContext bundleContext, Configuration configuration) {
this.bundleContext = bundleContext;
@@ -127,6 +129,7 @@ public class DeclarativeDynamicResourceManagerService
parseDDRFilter(configuration.prohibited_ddr_filter(), prohibitedFilter);
followedLinkNames.addAll(Arrays.asList(configuration.followed_link_names()));
try {
+ // The Resource Resolver needs to be kept alive until this Service is deactivated due to the Event Listeners
resourceResolver = resourceResolverFactory.getServiceResourceResolver(
new HashMap<String, Object>() {{ put(ResourceResolverFactory.SUBSERVICE, DYNAMIC_COMPONENTS_SERVICE_USER); }}
);
@@ -186,7 +189,7 @@ public class DeclarativeDynamicResourceManagerService
private void handleDDRSource(Resource resource) {
if(resource != null) {
- // Find the Resource in the tree with the Target Path
+ // Find the Provider Root Resource
Resource ddrProvider = findDDRSource(resource);
if(ddrProvider != null) {
ValueMap properties = ddrProvider.getValueMap();
@@ -201,6 +204,7 @@ public class DeclarativeDynamicResourceManagerService
log.info("Dynamic Target: '{}', Dynamic Provider: '{}'", ddrTargetResource, ddrProvider);
long id = service.registerService(
bundleContext.getBundle(), ddrTargetPath, ddrProvider.getPath(), resourceResolverFactory,
+ this,
allowedFilter, prohibitedFilter, followedLinkNames
);
log.info("After Registering Tenant RP: service: '{}', id: '{}'", service, id);
@@ -215,10 +219,29 @@ public class DeclarativeDynamicResourceManagerService
resourceProvider.update(ddrTargetPath);
}
}
+ } else {
+ // Provider Resource found -> check that this resource was previous target and if so remove it
+ DeclarativeDynamicResourceProvider toBeRemoved = null;
+ for(Entry<String, DeclarativeDynamicResourceProvider> entry: registeredServicesByProvider.entrySet()) {
+ if(resource.getPath().startsWith(entry.getKey())) {
+ toBeRemoved = entry.getValue();
+ break;
+ }
+ }
+ if(toBeRemoved != null) {
+ registeredServicesByProvider.remove(toBeRemoved.getProviderRootPath());
+ registeredServicesByTarget.remove(toBeRemoved.getTargetRootPath());
+ toBeRemoved.unregisterService();
+ }
}
}
}
+ /**
+ * Find the Resource in the Tree that contains the Target Path
+ * @param resource The resource where the search starts
+ * @return The resource containing the DDR Target Path or null if not found
+ */
private Resource findDDRSource(Resource resource) {
Resource answer = null;
if (resource != null) {
@@ -233,6 +256,7 @@ public class DeclarativeDynamicResourceManagerService
return answer;
}
+ @Override
public void update(String dynamicProviderPath) {
try (ResourceResolver resourceResolver = resourceResolverFactory.getServiceResourceResolver(
new HashMap<String, Object>() {{ put(ResourceResolverFactory.SUBSERVICE, DYNAMIC_COMPONENTS_SERVICE_USER); }}
@@ -244,6 +268,30 @@ public class DeclarativeDynamicResourceManagerService
}
}
+ @Override
+ public void addReference(String sourcePath, String targetPath) {
+ ReferenceEventListener referenceEventListener = null;
+ for(Entry<String, ReferenceEventListener> entry: referenceListeners.entrySet()) {
+ // If there is already a registered Event Listener for the given target or one of its parents when we ignore it
+ if(targetPath.startsWith(entry.getValue().getReferencedPath())) {
+ referenceEventListener = entry.getValue();
+ break;
+ }
+ //AS TODO: this should be handled by the caller (Resource Provider) as he knows the Provider Root
+// //AS TODO: Should we only limit this to /conf/.../settings/dynamic ?
+// if(sourcePath.startsWith(CONFIGURATION_ROOT_PATH)) {
+// // A reference is pointing inside the Dynamic Folder which is already handled so we ignore it
+// referenceEventListener = entry.getValue();
+// break;
+// }
+ }
+ if(referenceEventListener == null) {
+ referenceEventListener = new ReferenceEventListener();
+ referenceEventListener.registerListener(sourcePath, targetPath, resourceResolver);
+ referenceListeners.put(sourcePath, referenceEventListener);
+ }
+ }
+
@Deactivate
private void deactivate() {
for(Entry<String, DeclarativeDynamicResourceProvider> entry: registeredServicesByTarget.entrySet()) {
@@ -256,6 +304,18 @@ public class DeclarativeDynamicResourceManagerService
}
registeredServicesByProvider.clear();
registeredServicesByTarget.clear();
+ for(Entry<String, ReferenceEventListener> entry: referenceListeners.entrySet()) {
+ entry.getValue().unregisterListener(resourceResolver);
+ }
+ Session session = resourceResolver.adaptTo(Session.class);
+ if (session != null) {
+ log.info("Register Event Listener on Path: '{}'", CONFIGURATION_ROOT_PATH);
+ try {
+ session.getWorkspace().getObservationManager().removeEventListener(this);
+ } catch (RepositoryException e) {
+ // Ignore
+ }
+ }
if(resourceResolver != null) {
resourceResolver.close();
}
@@ -279,8 +339,10 @@ public class DeclarativeDynamicResourceManagerService
path = path.substring(0, index -1);
}
log.info("Property Added or Changed, path: '{}'", path);
+ handleNodeChange(path, true);
+ break;
case Event.NODE_ADDED:
- handleNodeAdded(path);
+ handleNodeChange(path, true);
break;
case Event.NODE_REMOVED:
handleNodeRemoved(path);
@@ -290,26 +352,23 @@ public class DeclarativeDynamicResourceManagerService
Map info = event.getInfo();
Object temp = info.get("srcAbsPath");
if(temp instanceof String) {
- // Source found -> get target and update it
+ // Source found -> get target and remove it
String sourcePath = temp.toString();
handleNodeRemoved(sourcePath);
- String destPath = info.get("destAbsPath") + "";
- handleNodeAdded(destPath);
}
temp = info.get("destAbsPath");
if(temp instanceof String) {
- // Destination found -> get target and update it
+ // Destination found -> get target and add it
String destPath = temp.toString();
- handleNodeAdded(destPath);
+ handleNodeChange(destPath, true);
}
break;
case Event.PROPERTY_REMOVED:
index = path.lastIndexOf('/');
if(index > 0) {
String resourcePath = path.substring(0, index);
- handleNodeAdded(resourcePath);
+ handleNodeChange(resourcePath, false);
}
-// break;
}
}
} catch (LoginException | RepositoryException e) {
@@ -317,7 +376,7 @@ public class DeclarativeDynamicResourceManagerService
}
}
- private void handleNodeAdded(String path) {
+ private void handleNodeChange(String path, boolean added) {
Resource source = resourceResolver.getResource(path);
log.info("Source Resource found: '{}'", source);
if(source != null) {
@@ -329,8 +388,7 @@ public class DeclarativeDynamicResourceManagerService
DeclarativeDynamicResourceProvider toBeRemoved = null;
for(Entry<String, DeclarativeDynamicResourceProvider> entry: registeredServicesByProvider.entrySet()) {
if(entry.getKey().equals(path)) {
- // Provider remove -> remove service
- entry.getValue().unregisterService();
+ // Provider to be removed found
toBeRemoved = entry.getValue();
break;
} else if(path.startsWith(entry.getKey())) {
@@ -342,11 +400,66 @@ public class DeclarativeDynamicResourceManagerService
if(toBeRemoved != null) {
registeredServicesByProvider.remove(toBeRemoved.getProviderRootPath());
registeredServicesByTarget.remove(toBeRemoved.getTargetRootPath());
+ toBeRemoved.unregisterService();
}
}
Map<String, DeclarativeDynamicResourceProvider> getRegisteredServicesByTarget() {
return Collections.unmodifiableMap(registeredServicesByTarget);
}
+
+ class ReferenceEventListener implements EventListener {
+
+ private String sourcePath;
+ private String referencedPath;
+
+ /** @return The path of where the reference is found **/
+ public String getSourcePath() {
+ return sourcePath;
+ }
+
+ /** @return The path to where the reference points to **/
+ public String getReferencedPath() {
+ return referencedPath;
+ }
+
+ void registerListener(String sourcePath, String referencedPath, ResourceResolver resourceResolver) {
+ this.sourcePath = sourcePath;
+ this.referencedPath = referencedPath;
+ Session session = resourceResolver.adaptTo(Session.class);
+ if (session != null) {
+ log.info("Register Event Listener on Path: '{}'", sourcePath);
+ try {
+ session.getWorkspace().getObservationManager().addEventListener(
+ this, EVENT_TYPES, referencedPath,
+ true, null, null, false
+ );
+ } catch (RepositoryException e) {
+ // Ignore
+ }
+ } else {
+ log.warn("Resource Resolver could not be adapted to Session");
+ }
+ }
+
+ void unregisterListener(ResourceResolver resourceResolver) {
+ Session session = resourceResolver.adaptTo(Session.class);
+ if (session != null) {
+ log.info("Unregister Event Listener on Path: '{}'", sourcePath);
+ try {
+ session.getWorkspace().getObservationManager().removeEventListener(this);
+ } catch (RepositoryException e) {
+ // Ignore
+ }
+ } else {
+ log.warn("Resource Resolver could not be adapted to Session");
+ }
+ }
+
+ @Override
+ public void onEvent(EventIterator events) {
+ handleNodeChange(sourcePath, false);
+ }
+ }
}
diff --git a/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandler.java b/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandler.java
index 63e518e..9f0f4a9 100644
--- a/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandler.java
+++ b/org.apache.sling.ddr/core/src/main/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandler.java
@@ -21,6 +21,7 @@ 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.ValueMap;
+import org.apache.sling.ddr.api.DeclarativeDynamicResourceManager;
import org.apache.sling.ddr.api.DeclarativeDynamicResourceProvider;
import org.apache.sling.spi.resource.provider.ProviderContext;
import org.apache.sling.spi.resource.provider.ResolveContext;
@@ -67,6 +68,7 @@ public class DeclarativeDynamicResourceProviderHandler
private String providerRootPath;
private boolean active;
private ResourceResolverFactory resourceResolverFactory;
+ private DeclarativeDynamicResourceManager declarativeDynamicResourceManager;
private Map<String, List<String>> allowedDDRFilter;
private Map<String, List<String>> prohibitedDDRFilter;
private List<String> followedLinkNames;
@@ -79,11 +81,13 @@ public class DeclarativeDynamicResourceProviderHandler
public long registerService(
Bundle bundle, String targetRootPath, String providerRootPath, ResourceResolverFactory resourceResolverFactory,
+ DeclarativeDynamicResourceManager declarativeDynamicResourceManager,
Map<String, List<String>> allowedDDRFilter, Map<String, List<String>> prohibitedDDRFilter, List<String> followedLinkNames
) {
this.targetRootPath = targetRootPath;
this.providerRootPath = providerRootPath;
this.resourceResolverFactory = resourceResolverFactory;
+ this.declarativeDynamicResourceManager = declarativeDynamicResourceManager;
this.allowedDDRFilter = allowedDDRFilter == null ? new HashMap<String, List<String>>(): allowedDDRFilter;
this.prohibitedDDRFilter = prohibitedDDRFilter == null ? new HashMap<String, List<String>>(): prohibitedDDRFilter;
this.followedLinkNames = followedLinkNames == null ? new ArrayList<String>() : followedLinkNames;
@@ -331,6 +335,7 @@ public class DeclarativeDynamicResourceProviderHandler
childrenList.add(new Reference(child.getPath(), referencePath));
String parentPath = targetRootPath + (postfix.isEmpty() ? "" : SLASH + postfix);
mappings.put(parentPath + SLASH + child.getName(), new Reference(child.getPath(), referencePath));
+ declarativeDynamicResourceManager.addReference(child.getPath(), referencePath);
if(returnChildren) {
answer.add(
createSyntheticFromResource(
diff --git a/org.apache.sling.ddr/core/src/test/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandlerTest.java b/org.apache.sling.ddr/core/src/test/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandlerTest.java
index 5cc7493..14e995d 100644
--- a/org.apache.sling.ddr/core/src/test/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandlerTest.java
+++ b/org.apache.sling.ddr/core/src/test/java/org/apache/sling/ddr/core/DeclarativeDynamicResourceProviderHandlerTest.java
@@ -22,6 +22,7 @@ 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.ValueMap;
+import org.apache.sling.ddr.api.DeclarativeDynamicResourceManager;
import org.apache.sling.spi.resource.provider.ResolveContext;
import org.apache.sling.spi.resource.provider.ResourceContext;
import org.apache.sling.spi.resource.provider.ResourceProvider;
@@ -53,6 +54,8 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -67,6 +70,8 @@ public class DeclarativeDynamicResourceProviderHandlerTest {
private ResolveContext resolveContext;
@Mock
private ResourceContext resourceContext;
+ @Mock
+ private DeclarativeDynamicResourceManager declarativeDynamicResourceManager;
@Mock
private ResourceResolverFactory resourceResolverFactory;
@@ -111,7 +116,7 @@ public class DeclarativeDynamicResourceProviderHandlerTest {
Resource dynamicParent = resourceResolver.getResource(dynamicResourceRoot);
declarativeDynamicResourceProviderHandler.registerService(
context.bundleContext().getBundle(), dynamicResourceRoot, confResourceRoot,
- resourceResolverFactory, null,
+ resourceResolverFactory, null, null,
new HashMap<String, List<String>>() {{
put("jcr:primaryType", Arrays.asList("nt:file"));
}},
@@ -156,7 +161,7 @@ public class DeclarativeDynamicResourceProviderHandlerTest {
declarativeDynamicResourceProviderHandler.registerService(
context.bundleContext().getBundle(), dynamicResourceRoot, confResourceRoot,
- resourceResolverFactory, null,
+ resourceResolverFactory, null, null,
new HashMap<String, List<String>>() {{
put("jcr:primaryType", Arrays.asList("nt:file", "nt:resource"));
}},
@@ -196,9 +201,11 @@ public class DeclarativeDynamicResourceProviderHandlerTest {
Resource dynamicParent = resourceResolver.getResource(dynamicResourceRoot);
+ doNothing().when(declarativeDynamicResourceManager).addReference(anyString(), anyString());
+
declarativeDynamicResourceProviderHandler.registerService(
context.bundleContext().getBundle(), dynamicResourceRoot, confResourceRoot,
- resourceResolverFactory, null, null,
+ resourceResolverFactory, declarativeDynamicResourceManager,null, null,
Arrays.asList("sling:ddrRef")
);