You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by np...@apache.org on 2021/10/05 15:22:24 UTC
[sling-org-apache-sling-pipes] branch master updated: SLING-10846
introduce markWithJcrLastModified api
This is an automated email from the ASF dual-hosted git repository.
npeltier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-pipes.git
The following commit(s) were added to refs/heads/master by this push:
new de3179f SLING-10846 introduce markWithJcrLastModified api
de3179f is described below
commit de3179f618476c40de8b832b1165b31364384759
Author: Nicolas Peltier <np...@apache.org>
AuthorDate: Tue Oct 5 17:21:01 2021 +0200
SLING-10846 introduce markWithJcrLastModified api
- new plumber api markWithJcrLastModified that writes date, user, and eventually pipe path (if configured, defaults to false),
- usage of api in write pipe, when properties are written (we might miss some cases, or update too much in other case but for now that can work),
- usage of api in path pipe, only in case the resource is created
---
src/main/java/org/apache/sling/pipes/Plumber.java | 7 +++++
.../org/apache/sling/pipes/internal/PathPipe.java | 4 +++
.../apache/sling/pipes/internal/PlumberImpl.java | 23 +++++++++++++++-
.../org/apache/sling/pipes/internal/WritePipe.java | 5 ++++
.../java/org/apache/sling/pipes/package-info.java | 2 +-
.../org/apache/sling/pipes/AbstractPipeTest.java | 1 +
.../apache/sling/pipes/internal/PathPipeTest.java | 25 +++++++++++++++--
.../apache/sling/pipes/internal/WritePipeTest.java | 31 +++++++++++++++-------
8 files changed, 85 insertions(+), 13 deletions(-)
diff --git a/src/main/java/org/apache/sling/pipes/Plumber.java b/src/main/java/org/apache/sling/pipes/Plumber.java
index c625c6c..a2fc9f0 100644
--- a/src/main/java/org/apache/sling/pipes/Plumber.java
+++ b/src/main/java/org/apache/sling/pipes/Plumber.java
@@ -20,6 +20,7 @@ import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.event.jobs.Job;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
@@ -169,6 +170,12 @@ public interface Plumber {
*/
@Nullable Resource getReferencedResource(Resource referrer, String reference);
+ /**
+ * marks a given resource as updated
+ * @param resource resource to mark
+ */
+ void markWithJcrLastModified(@NotNull Pipe pipe, @NotNull Resource resource);
+
/*
* Generates unique pipe path for persistence sake
*/
diff --git a/src/main/java/org/apache/sling/pipes/internal/PathPipe.java b/src/main/java/org/apache/sling/pipes/internal/PathPipe.java
index e804c11..e51b476 100644
--- a/src/main/java/org/apache/sling/pipes/internal/PathPipe.java
+++ b/src/main/java/org/apache/sling/pipes/internal/PathPipe.java
@@ -80,6 +80,7 @@ public class PathPipe extends BasePipe {
try {
String path = isRootPath(expr) ? expr : getInput().getPath() + SLASH + expr;
logger.info("creating path {}", path);
+ boolean modified = resolver.getResource(path) == null;
if (!isDryRun()) {
if (StringUtils.isNotBlank(nodeType)) {
//in that case we are in a "JCR" mode
@@ -88,6 +89,9 @@ public class PathPipe extends BasePipe {
ResourceUtil.getOrCreateResource(resolver, path, resourceType, intermediateType, autosave);
}
Resource resource = resolver.getResource(path);
+ if (modified) {
+ plumber.markWithJcrLastModified(this, resource);
+ }
output = Collections.singleton(resource).iterator();
}
} catch (PersistenceException | RepositoryException e) {
diff --git a/src/main/java/org/apache/sling/pipes/internal/PlumberImpl.java b/src/main/java/org/apache/sling/pipes/internal/PlumberImpl.java
index 855afe7..2e1c948 100644
--- a/src/main/java/org/apache/sling/pipes/internal/PlumberImpl.java
+++ b/src/main/java/org/apache/sling/pipes/internal/PlumberImpl.java
@@ -48,6 +48,7 @@ import org.apache.sling.pipes.PipeExecutor;
import org.apache.sling.pipes.Plumber;
import org.apache.sling.pipes.PlumberMXBean;
import org.apache.sling.pipes.internal.bindings.ConfigurationMap;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -85,6 +86,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import static org.apache.jackrabbit.JcrConstants.JCR_LASTMODIFIED;
import static org.apache.sling.api.resource.ResourceResolverFactory.SUBSERVICE;
import static org.apache.sling.pipes.BasePipe.PN_STATUS;
import static org.apache.sling.pipes.BasePipe.PN_STATUS_MODIFIED;
@@ -114,7 +116,9 @@ public class PlumberImpl implements Plumber, JobConsumer, PlumberMXBean, Runnabl
static final String PERMISSION_EXECUTION = "/system/sling/permissions/pipes/exec";
- static final int MAX_LENGTH = 1000;
+ static final String JCR_LAST_MODIFIED_BY = JCR_LASTMODIFIED + "By";
+
+ static final String JCR_LAST_MODIFIED_BY_PIPE = JCR_LAST_MODIFIED_BY + "Pipe";
public static final String PIPES_REPOSITORY_PATH = "/var/pipes";
@@ -141,6 +145,9 @@ public class PlumberImpl implements Plumber, JobConsumer, PlumberMXBean, Runnabl
@AttributeDefinition(description = "max age (in days) of automatically generated pipe persistence")
int maxAge() default 31;
+ @AttributeDefinition(description = "should add pipe path to updated properties")
+ boolean mark_pipe_path() default false;
+
@AttributeDefinition(description = "schedule of purge process")
String scheduler_expression() default "0 0 12 */7 * ?";
}
@@ -278,6 +285,20 @@ public class PlumberImpl implements Plumber, JobConsumer, PlumberMXBean, Runnabl
}
@Override
+ public void markWithJcrLastModified(@NotNull Pipe pipe, @NotNull Resource resource) {
+ if (!pipe.isDryRun()) {
+ ModifiableValueMap mvm = resource.adaptTo(ModifiableValueMap.class);
+ if (mvm != null) {
+ mvm.put(JCR_LASTMODIFIED, Calendar.getInstance());
+ mvm.put(JCR_LAST_MODIFIED_BY, resource.getResourceResolver().getUserID());
+ if (configuration.mark_pipe_path()) {
+ mvm.put(JCR_LAST_MODIFIED_BY_PIPE, pipe.getResource().getPath());
+ }
+ }
+ }
+ }
+
+ @Override
public Map<String, Object> getBindingsFromRequest(SlingHttpServletRequest request, boolean writeAllowed) throws IOException
{
Map<String, Object> bindings = new HashMap<>();
diff --git a/src/main/java/org/apache/sling/pipes/internal/WritePipe.java b/src/main/java/org/apache/sling/pipes/internal/WritePipe.java
index 7e243d6..bb0fad7 100644
--- a/src/main/java/org/apache/sling/pipes/internal/WritePipe.java
+++ b/src/main/java/org/apache/sling/pipes/internal/WritePipe.java
@@ -165,6 +165,7 @@ public class WritePipe extends BasePipe {
private void copyProperties(@Nullable Resource conf, Resource target) {
ValueMap writeMap = conf != null ? conf.adaptTo(ValueMap.class) : null;
ModifiableValueMap targetProperties = target.adaptTo(ModifiableValueMap.class);
+ boolean modified = false;
//writing current node
if (properties != null && writeMap != null) {
@@ -173,9 +174,13 @@ public class WritePipe extends BasePipe {
String key = parent != null ? bindings.instantiateExpression(entry.getKey()) : entry.getKey();
Object value = computeValue(target, key, entry.getValue());
copyProperty(targetProperties, target, key, value);
+ modified = true;
}
}
}
+ if (modified) {
+ plumber.markWithJcrLastModified(this, target);
+ }
}
/**
diff --git a/src/main/java/org/apache/sling/pipes/package-info.java b/src/main/java/org/apache/sling/pipes/package-info.java
index 711bf13..cc775f0 100644
--- a/src/main/java/org/apache/sling/pipes/package-info.java
+++ b/src/main/java/org/apache/sling/pipes/package-info.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("4.2.0")
+@Version("4.3.0")
package org.apache.sling.pipes;
import org.osgi.annotation.versioning.Version;
diff --git a/src/test/java/org/apache/sling/pipes/AbstractPipeTest.java b/src/test/java/org/apache/sling/pipes/AbstractPipeTest.java
index 105ec2f..683a6ec 100644
--- a/src/test/java/org/apache/sling/pipes/AbstractPipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/AbstractPipeTest.java
@@ -79,6 +79,7 @@ public class AbstractPipeTest {
context.registerInjectActivateService(plumber, "authorizedUsers", new String[]{},
"bufferSize", PlumberImpl.DEFAULT_BUFFER_SIZE,
"executionPermissionResource", PATH_FRUITS,
+ "mark.pipe.path",true,
"referencesPaths", new String [] { "/conf/global/sling/pipes", "/apps/scripts" });
plumber.registerPipe("slingPipes/dummyNull", DummyNull.class);
plumber.registerPipe("slingPipes/dummySearch", DummySearch.class);
diff --git a/src/test/java/org/apache/sling/pipes/internal/PathPipeTest.java b/src/test/java/org/apache/sling/pipes/internal/PathPipeTest.java
index afde834..7265b5e 100644
--- a/src/test/java/org/apache/sling/pipes/internal/PathPipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/PathPipeTest.java
@@ -19,9 +19,9 @@ package org.apache.sling.pipes.internal;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.pipes.AbstractPipeTest;
import org.apache.sling.pipes.Pipe;
-import org.junit.Ignore;
import org.junit.Test;
import javax.jcr.Node;
@@ -29,9 +29,12 @@ import javax.jcr.Node;
import static org.apache.sling.jcr.resource.JcrResourceConstants.NT_SLING_FOLDER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import java.lang.reflect.InvocationTargetException;
+import java.time.Instant;
+import java.util.Calendar;
+
/**
* Testing path pipe using pipe builder
*/
@@ -73,4 +76,22 @@ public class PathPipeTest extends AbstractPipeTest {
plumber.newPipe(resolver).echo(PATH_FRUITS).mkdir(WATERMELON_RELATIVEPATH).run();
assertNotNull("Resource should be here & saved", resolver.getResource(WATERMELON_FULL_PATH));
}
+ @Test
+ public void testJcrMark() throws InvocationTargetException, IllegalAccessException {
+ Instant now = Instant.now();
+ String path = "/content/my/new/path";
+ execute("mkdir " + path);
+ ValueMap fruits = context.resourceResolver().getResource(path).adaptTo(ValueMap.class);
+ assertNotNull(fruits.get("jcr:lastModified", Calendar.class));
+ Instant modified = Instant.ofEpochMilli(fruits.get("jcr:lastModified", Calendar.class).getTimeInMillis());
+ assertTrue(modified.isAfter(now));
+ assertNotNull(fruits.get("jcr:lastModifiedBy", String.class));
+ //we configured the plumber to mark pipe path
+ assertNotNull(fruits.get("jcr:lastModifiedByPipe", String.class));
+ execute("mkdir " + path);
+ fruits = context.resourceResolver().getResource(path).adaptTo(ValueMap.class);
+ Instant modifiedAgain = Instant.ofEpochMilli(fruits.get("jcr:lastModified", Calendar.class).getTimeInMillis());
+ assertEquals("path should not mark *again* a path already created", modified, modifiedAgain);
+ }
+
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java b/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java
index 5914f74..9db23a4 100644
--- a/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java
@@ -31,6 +31,7 @@ import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import java.lang.reflect.InvocationTargetException;
+import java.time.Instant;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
@@ -67,20 +68,19 @@ public class WritePipeTest extends AbstractPipeTest {
assertTrue("this pipe should be marked as content modifier", pipe.modifiesContent());
pipe.getOutput();
context.resourceResolver().commit();
- ValueMap properties = context.resourceResolver().getResource(PATH_APPLE).adaptTo(ValueMap.class);
+ ValueMap properties = context.resourceResolver().getResource(PATH_APPLE).adaptTo(ValueMap.class);
assertTrue("There should be hasSeed set to true", properties.get("hasSeed", false));
assertArrayEquals("Colors should be correctly set", new String[]{"green", "red"}, properties.get("colors", String[].class));
assertFalse("worm property should be gone (${null} conf)", properties.get("worm", false));
}
/**
- *
* @param resource
*/
public static void assertPiped(Resource resource) {
ValueMap properties = resource.adaptTo(ValueMap.class);
- String[] array = new String[]{"cabbage","carrot"};
- assertArrayEquals("Second fruit should have been correctly instantiated & patched, added to the first", new String[]{"apple","banana"}, properties.get("fruits", String[].class));
+ String[] array = new String[]{"cabbage", "carrot"};
+ assertArrayEquals("Second fruit should have been correctly instantiated & patched, added to the first", new String[]{"apple", "banana"}, properties.get("fruits", String[].class));
assertArrayEquals("Fixed mv should be there", array, properties.get("fixedVegetables", String[].class));
assertArrayEquals("Expr fixed mv should there and computed", array, properties.get("computedVegetables", String[].class));
}
@@ -127,7 +127,7 @@ public class WritePipeTest extends AbstractPipeTest {
pipe.getOutput();
context.resourceResolver().commit();
Resource appleResource = context.resourceResolver().getResource(PATH_APPLE);
- ValueMap properties = appleResource.adaptTo(ValueMap.class);
+ ValueMap properties = appleResource.adaptTo(ValueMap.class);
assertTrue("There should be hasSeed set to true", properties.get("hasSeed", false));
assertArrayEquals("Colors should be correctly set", new String[]{"green", "red"}, properties.get("colors", String[].class));
Node appleNode = appleResource.adaptTo(Node.class);
@@ -143,9 +143,9 @@ public class WritePipeTest extends AbstractPipeTest {
assertEquals("result should have 1", 1, result.size());
Resource root = resolver.getResource(path);
assertNotNull("target resource should be created", root);
- Resource property = root.getChild("index");
+ Resource property = root.getChild("index");
assertNotNull("property should be here", property);
- assertArrayEquals("index property should be the same", new String[] {"apple","banana"}, property.adaptTo(String[].class));
+ assertArrayEquals("index property should be the same", new String[]{"apple", "banana"}, property.adaptTo(String[].class));
List<Resource> resources = IteratorUtils.toList(root.listChildren());
List<String> children = resources.stream().map(r -> r.getPath()).collect(Collectors.toList());
assertEquals("there should be 2 subpipes", 2, children.size());
@@ -169,12 +169,12 @@ public class WritePipeTest extends AbstractPipeTest {
pipe.getOutput().next();
context.resourceResolver().commit();
Resource resource = context.resourceResolver().getResource(expectedPath);
- if (nodeExpected){
+ if (nodeExpected) {
assertNotNull("there should be isTrue node for test binding " + bindingValue, resource);
} else {
assertNull("there should be no isTrue node created for test binding " + bindingValue, resource);
}
- if (resource != null){
+ if (resource != null) {
resource.adaptTo(Node.class).remove();
}
}
@@ -204,4 +204,17 @@ public class WritePipeTest extends AbstractPipeTest {
execute("mkdir /content/copies/one | write @ expr /content${number} @ bindings number=/1");
assertTrue(context.resourceResolver().getResource("/content/copies/one/to/copy") != null);
}
+
+ @Test
+ public void testJcrMark() throws InvocationTargetException, IllegalAccessException {
+ Instant now = Instant.now();
+ execute("echo /content/fruits | write foo=bar");
+ ValueMap fruits = context.resourceResolver().getResource("/content/fruits").adaptTo(ValueMap.class);
+ assertNotNull(fruits.get("jcr:lastModified", Calendar.class));
+ Instant modified = Instant.ofEpochMilli(fruits.get("jcr:lastModified", Calendar.class).getTimeInMillis());
+ assertTrue(modified.isAfter(now));
+ assertNotNull(fruits.get("jcr:lastModifiedBy", String.class));
+ //we configured the plumber to mark pipe path
+ assertNotNull(fruits.get("jcr:lastModifiedByPipe", String.class));
+ }
}