Merge pull request #35 from jsedding/issues/SLING-11483
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java
index 9ed5979..e9f4a23 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java
@@ -26,6 +26,7 @@
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -45,6 +46,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+
/**
* OperationVisitor which processes only operations related to setting node
* properties. Having several such specialized visitors makes it easy to control
@@ -291,15 +293,18 @@
for (PropertyLine pl : propertyLines) {
final String pName = pl.getPropertyName();
if (needToSetProperty(n, pl)) {
- final PropertyLine.PropertyType pType = pl.getPropertyType();
- final int type = PropertyType.valueFromName(pType.name());
- final List<Object> values = pl.getPropertyValues();
- if (values.size() > 1) {
- Value[] pValues = convertToValues(values);
- n.setProperty(pName, pValues, type);
- } else {
- Value pValue = convertToValue(values.get(0));
- n.setProperty(pName, pValue, type);
+ final int newType = PropertyType.valueFromName(pl.getPropertyType().name());
+ Value[] newValues = convertToValues(pl.getPropertyValues());
+ Property oldProperty = n.hasProperty(pName) ? n.getProperty(pName) : null;
+ // only set property if type and/or values change
+ // note: Node#setProperty() touches the node even if the property value is unchanged
+ // and thus needs to be explicitly avoided
+ if(hasPropertyChange(oldProperty, newType, newValues)) {
+ if (newValues.length == 1) {
+ n.setProperty(pName, newValues[0], newType);
+ } else {
+ n.setProperty(pName, newValues, newType);
+ }
}
} else {
log.info("Property '{}' already set on path '{}', existing value will not be overwritten in 'default' mode",
@@ -308,6 +313,31 @@
}
}
+ private boolean hasPropertyChange(Property oldProperty, int newType, Value... newValues) throws RepositoryException {
+ if (oldProperty == null || oldProperty.getType() != newType) {
+ return true;
+ }
+
+ final Value[] oldValues = oldProperty.isMultiple() ? oldProperty.getValues() : new Value[]{ oldProperty.getValue() };
+ if (oldValues.length != newValues.length) {
+ return true;
+ }
+
+ for (int i = 0; i < oldValues.length; i++) {
+ final Value oldValue = oldValues[i];
+ final Value newValue = newValues[i];
+ if (!valueEquals(oldValue, newValue)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean valueEquals(Value oldValue, Value newValue) throws RepositoryException {
+ return oldValue.getType() == newValue.getType()
+ && oldValue.getString().equals(newValue.getString());
+ }
+
@Override
public void visitSetProperties(SetProperties sp) {
for (String nodePath : sp.getPaths()) {
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java b/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java
index 92d0446..5c9b5f8 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java
@@ -16,7 +16,9 @@
*/
package org.apache.sling.jcr.repoinit;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
@@ -43,7 +45,6 @@
import org.junit.Rule;
import org.junit.Test;
-
/** Test the setting of properties on nodes */
public class SetPropertiesTest {
@@ -56,13 +57,14 @@
private static final String path1 = pathPrefix + UUID.randomUUID();
private static final String path2 = pathPrefix + UUID.randomUUID();
private static final String path3 = pathPrefix + UUID.randomUUID();
+ private static final String path4 = pathPrefix + UUID.randomUUID();
@Before
public void setup() throws RepositoryException, IOException, RepoInitParsingException {
U = new TestUtil(context);
vf = U.adminSession.getValueFactory();
RepositoryUtil.registerSlingNodeTypes(U.adminSession);
- for(String p : new String[] { path1, path2, path3 }) {
+ for(String p : new String[] { path1, path2, path3, path4 }) {
U.parseAndExecute("create path " + p);
U.assertNodeExists(p);
}
@@ -221,6 +223,19 @@
// all good
}
}
+
+ @Test
+ public void noChangeOnSameProps() throws Exception {
+ String testRT = "/my/props/test";
+ String repoinitStr = "set properties on " + path4 + " \n set sling:ResourceType{String} to "+testRT+" \n end";
+ boolean hasChanges = U.parseAndExecute(repoinitStr);
+ assertTrue("No changes first attempt - session should contain changes.", hasChanges);
+ hasChanges = U.parseAndExecute(repoinitStr);
+ assertFalse("Returning changes on second execution with same values - session should NOT contain changes.", hasChanges);
+ Value expectedValue = vf.createValue(testRT);
+ U.assertSVPropertyExists(path4, "sling:ResourceType", expectedValue);
+
+ }
/**
* SLING-11293 "set default properties" instruction to change autocreated property value
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java b/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java
index fd57723..406686c 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java
@@ -244,10 +244,12 @@
}
}
- public void parseAndExecute(String input) throws RepositoryException, RepoInitParsingException {
+ public boolean parseAndExecute(String input) throws RepositoryException, RepoInitParsingException {
final JcrRepoInitOpsProcessorImpl p = new JcrRepoInitOpsProcessorImpl();
p.apply(adminSession, parse(input));
+ boolean hasChanges = adminSession.hasPendingChanges();
adminSession.save();
+ return hasChanges;
}
public void cleanupUser() throws RepositoryException, RepoInitParsingException {