Author: mreutegg
Date: Wed Dec 14 15:20:22 2016
New Revision: 1774264
URL: http://svn.apache.org/viewvc?rev=1774264&view=rev
Log:
OAK-3328: checked-in state should only affect properties with OPV!=IGNORE
Apply patch provided by Marco Piovesana
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/OpvIgnoreTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java?rev=1774264&r1=1774263&r2=1774264&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java
Wed Dec 14 15:20:22 2016
@@ -27,12 +27,15 @@ import static org.apache.jackrabbit.oak.
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.version.OnParentVersionAction;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.lock.LockConstants;
+import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -85,10 +88,10 @@ class VersionEditor implements Editor {
// deleted or versionable -> check if it was checked in
// a node cannot be modified if it was checked in
// unless it has a new identifier
- isReadOnly = wasCheckedIn() && !hasNewIdentifier();
+ isReadOnly = wasCheckedIn() && !hasNewIdentifier() &&
!isIgnoreOnOPV();
} else {
// otherwise inherit from parent
- isReadOnly = parent != null && parent.isReadOnly;
+ isReadOnly = parent != null && parent.isReadOnly &&
!isIgnoreOnOPV();
}
}
@@ -108,7 +111,7 @@ class VersionEditor implements Editor {
vMgr.restore(node, after.getValue(Type.REFERENCE), null);
return;
}
- if (!isReadOnly) {
+ if (!isReadOnly || getOPV(after) == OnParentVersionAction.IGNORE) {
return;
}
// JCR allows to put a lock on a checked in node.
@@ -124,7 +127,7 @@ class VersionEditor implements Editor {
public void propertyChanged(PropertyState before, PropertyState after)
throws CommitFailedException {
if (!isVersionable()) {
- if (!isVersionProperty(after) && isReadOnly) {
+ if (!isVersionProperty(after) && isReadOnly && getOPV(after) !=
OnParentVersionAction.IGNORE) {
throwCheckedIn("Cannot change property " + after.getName()
+ " on checked in node");
}
@@ -146,7 +149,7 @@ class VersionEditor implements Editor {
vMgr.restore(node, baseVersion, null);
} else if (isVersionProperty(after)) {
throwProtected(after.getName());
- } else if (isReadOnly) {
+ } else if (isReadOnly && getOPV(after) !=
OnParentVersionAction.IGNORE) {
throwCheckedIn("Cannot change property " + after.getName()
+ " on checked in node");
}
@@ -156,7 +159,7 @@ class VersionEditor implements Editor {
public void propertyDeleted(PropertyState before)
throws CommitFailedException {
if (isReadOnly) {
- if (!isVersionProperty(before) && !isLockProperty(before)) {
+ if (!isVersionProperty(before) && !isLockProperty(before) &&
getOPV(before) != OnParentVersionAction.IGNORE) {
throwCheckedIn("Cannot delete property on checked in node");
}
}
@@ -253,4 +256,27 @@ class VersionEditor implements Editor {
throw new CommitFailedException(CommitFailedException.CONSTRAINT, 100,
"Property is protected: " + name);
}
+
+ private boolean isIgnoreOnOPV() throws CommitFailedException {
+ if (this.parent != null) {
+ try {
+ NodeDefinition definition =
this.vMgr.getNodeTypeManager().getDefinition(TreeFactory.createTree(parent.node),
this.name);
+ return definition.getOnParentVersion() ==
OnParentVersionAction.IGNORE;
+ } catch (Exception e) {
+ throw new CommitFailedException(CommitFailedException.VERSION,
+
VersionExceptionCode.UNEXPECTED_REPOSITORY_EXCEPTION.ordinal(), e.getMessage());
+ }
+ }
+ return false;
+ }
+
+ private int getOPV(PropertyState property) throws CommitFailedException {
+ try {
+ return
this.vMgr.getNodeTypeManager().getDefinition(TreeFactory.createReadOnlyTree(this.node.getNodeState()),
+ property, false).getOnParentVersion();
+ } catch (Exception e) {
+ throw new CommitFailedException(CommitFailedException.VERSION,
+
VersionExceptionCode.UNEXPECTED_REPOSITORY_EXCEPTION.ordinal(), e.getMessage());
+ }
+ }
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java?rev=1774264&r1=1774263&r2=1774264&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
Wed Dec 14 15:20:22 2016
@@ -61,6 +61,7 @@ import javax.jcr.nodetype.ConstraintViol
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.version.OnParentVersionAction;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
@@ -1364,7 +1365,7 @@ public class NodeImpl<T extends NodeDele
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ if (!isCheckedOut() && getOPV(dlg.getTree(), state) !=
OnParentVersionAction.IGNORE) {
throw new VersionException(format(
"Cannot set property. Node [%s] is checked in.",
getNodePath()));
}
@@ -1400,7 +1401,7 @@ public class NodeImpl<T extends NodeDele
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ if (!isCheckedOut() && getOPV(dlg.getTree(), state) !=
OnParentVersionAction.IGNORE) {
throw new VersionException(format(
"Cannot set property. Node [%s] is checked in.",
getNodePath()));
}
@@ -1444,7 +1445,8 @@ public class NodeImpl<T extends NodeDele
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ PropertyDelegate property = dlg.getPropertyOrNull(oakName);
+ if (!isCheckedOut() && getOPV(dlg.getTree(),
property.getPropertyState()) != OnParentVersionAction.IGNORE) {
throw new VersionException(format(
"Cannot remove property. Node [%s] is checked
in.", getNodePath()));
}
@@ -1599,6 +1601,13 @@ public class NodeImpl<T extends NodeDele
return dlg.getPath();
}
+ private int getOPV(Tree nodeTree, PropertyState property)
+ throws RepositoryException {
+ return getNodeTypeManager().getDefinition(nodeTree,
+ property, false).getOnParentVersion();
+
+ }
+
private static class PropertyIteratorDelegate {
private final NodeDelegate node;
private final Predicate<PropertyDelegate> predicate;
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java?rev=1774264&r1=1774263&r2=1774264&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
Wed Dec 14 15:20:22 2016
@@ -37,6 +37,7 @@ import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
import javax.jcr.version.VersionException;
import org.apache.jackrabbit.oak.api.Tree.Status;
@@ -113,7 +114,7 @@ public class PropertyImpl extends ItemIm
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!getParent().isCheckedOut()) {
+ if (!getParent().isCheckedOut() &&
getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
throw new VersionException(
"Cannot set property. Node is checked in.");
}
@@ -463,7 +464,7 @@ public class PropertyImpl extends ItemIm
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!getParent().isCheckedOut()) {
+ if (!getParent().isCheckedOut() &&
getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
throw new VersionException(
"Cannot set property. Node is checked in.");
}
@@ -499,7 +500,7 @@ public class PropertyImpl extends ItemIm
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!getParent().isCheckedOut()) {
+ if (!getParent().isCheckedOut() &&
getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
throw new VersionException(
"Cannot set property. Node is checked in.");
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java?rev=1774264&r1=1774263&r2=1774264&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
Wed Dec 14 15:20:22 2016
@@ -33,8 +33,10 @@ import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.util.TraversingItemVisitor;
+import javax.jcr.version.OnParentVersionAction;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
@@ -50,6 +52,7 @@ import org.apache.jackrabbit.oak.jcr.del
import org.apache.jackrabbit.oak.jcr.lock.LockManagerImpl;
import org.apache.jackrabbit.oak.jcr.session.SessionContext;
import org.apache.jackrabbit.oak.jcr.session.operation.SessionOperation;
+import
org.apache.jackrabbit.oak.plugins.nodetype.write.ReadWriteNodeTypeManager;
public class VersionManagerImpl implements VersionManager {
@@ -257,7 +260,20 @@ public class VersionManagerImpl implemen
if (nodeDelegate == null) {
throw new PathNotFoundException(absPath);
}
- return versionManagerDelegate.isCheckedOut(nodeDelegate);
+ boolean isCheckedOut =
versionManagerDelegate.isCheckedOut(nodeDelegate);
+ if (!isCheckedOut) {
+ // check OPV
+ ReadWriteNodeTypeManager ntMgr =
sessionContext.getWorkspace().getNodeTypeManager();
+ NodeDelegate parent = nodeDelegate.getParent();
+ NodeDefinition definition;
+ if (parent == null) {
+ definition = ntMgr.getRootDefinition();
+ } else {
+ definition = ntMgr.getDefinition(parent.getTree(),
nodeDelegate.getTree());
+ }
+ isCheckedOut = definition.getOnParentVersion() ==
OnParentVersionAction.IGNORE;
+ }
+ return isCheckedOut;
}
});
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/OpvIgnoreTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/OpvIgnoreTest.java?rev=1774264&r1=1774263&r2=1774264&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/OpvIgnoreTest.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/OpvIgnoreTest.java
Wed Dec 14 15:20:22 2016
@@ -18,6 +18,13 @@ package org.apache.jackrabbit.oak.jcr.ve
import javax.annotation.Nonnull;
import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinitionTemplate;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import javax.jcr.version.OnParentVersionAction;
@@ -32,6 +39,8 @@ import org.apache.jackrabbit.oak.spi.sec
import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.apache.jackrabbit.test.AbstractJCRTest;
+import java.util.List;
+
/**
* Test OPV IGNORE
*/
@@ -91,4 +100,147 @@ public class OpvIgnoreTest extends Abstr
assertTrue(frozenChild.hasNode(nodeName2));
assertFalse(frozenChild.hasNode(AccessControlConstants.REP_POLICY));
}
+
+ //OAK-3328
+ public void testWritePropertyWithIgnoreOPVAfterCheckIn() throws
RepositoryException {
+ Node ignoreTestNode = testRootNode.addNode("ignoreTestNode",
JcrConstants.NT_UNSTRUCTURED);
+ String ignoredPropertyName = "ignoredProperty";
+ NodeTypeTemplate mixinWithIgnoreProperty =
createNodeTypeWithIgnoreOPVProperty(ignoredPropertyName);
+
+ Node node = ignoreTestNode.addNode("testNode", testNodeType);
+ node.addMixin(mixinWithIgnoreProperty.getName());
+ node.setProperty(ignoredPropertyName, "initial value");
+ node.addMixin(mixVersionable);
+ superuser.save();
+ VersionManager vMgr = superuser.getWorkspace().getVersionManager();
+ if (!node.isCheckedOut()) {
+ vMgr.checkout(node.getPath());
+ }
+ vMgr.checkin(node.getPath());
+ node.setProperty(ignoredPropertyName, "next value");
+ superuser.save();
+ Property ignoreProperty = node.getProperty(ignoredPropertyName);
+ assertEquals("next value", ignoreProperty.getString());
+ }
+
+ //OAK-3328
+ public void testRemovePropertyWithIgnoreOPVAfterCheckIn() throws
RepositoryException {
+ Node ignoreTestNode = testRootNode.addNode("ignoreTestNode",
JcrConstants.NT_UNSTRUCTURED);
+ String ignoredPropertyName = "test:ignoredProperty";
+ NodeTypeTemplate mixinWithIgnoreProperty =
createNodeTypeWithIgnoreOPVProperty(ignoredPropertyName);
+
+ Node node = ignoreTestNode.addNode("testNode", testNodeType);
+ node.addMixin(mixinWithIgnoreProperty.getName());
+ node.setProperty(ignoredPropertyName, "initial value");
+ node.addMixin(mixVersionable);
+ superuser.save();
+ VersionManager vMgr = superuser.getWorkspace().getVersionManager();
+ if (!node.isCheckedOut()) {
+ vMgr.checkout(node.getPath());
+ }
+ vMgr.checkin(node.getPath());
+ node.getProperty(ignoredPropertyName).remove();
+ superuser.save();
+ assertFalse(node.hasProperty(ignoredPropertyName));
+ }
+
+ //OAK-3328
+ public void testAddChildNodeWithIgnoreOPVAfterCheckIn() throws
RepositoryException {
+ Node ignoreTestNode = testRootNode.addNode("ignoreTestNode",
JcrConstants.NT_UNSTRUCTURED);
+ String nodeTypeName = "testOpvIgnore";
+ NodeDefinitionTemplate nodeDefinition =
createNodeDefinitionWithIgnoreOPVNode(nodeTypeName);
+
+ ignoreTestNode.addMixin(JcrConstants.MIX_VERSIONABLE);
+ ignoreTestNode.addMixin(nodeTypeName);
+ superuser.save();
+
+ VersionManager vMgr = superuser.getWorkspace().getVersionManager();
+ if (!ignoreTestNode.isCheckedOut()) {
+ vMgr.checkout(ignoreTestNode.getPath());
+ }
+ vMgr.checkin(ignoreTestNode.getPath());
+
+ Node expected = ignoreTestNode.addNode(nodeDefinition.getName(),
NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
+ superuser.save();
+ Node childNode = ignoreTestNode.getNode(nodeDefinition.getName());
+ assertTrue(expected.isSame(childNode));
+ }
+
+ //OAK-3328
+ public void testRemoveChildNodeWithIgnoreOPVAfterCheckIn() throws
RepositoryException {
+ Node ignoreTestNode = testRootNode.addNode("ignoreTestNode",
JcrConstants.NT_UNSTRUCTURED);
+ String nodeTypeName = "testOpvIgnore";
+ NodeDefinitionTemplate nodeDefinition =
createNodeDefinitionWithIgnoreOPVNode(nodeTypeName);
+
+ ignoreTestNode.addMixin(JcrConstants.MIX_VERSIONABLE);
+ ignoreTestNode.addMixin(nodeTypeName);
+ Node expected = ignoreTestNode.addNode(nodeDefinition.getName(),
NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ superuser.save();
+
+ VersionManager vMgr = superuser.getWorkspace().getVersionManager();
+ if (!ignoreTestNode.isCheckedOut()) {
+ vMgr.checkout(ignoreTestNode.getPath());
+ }
+ vMgr.checkin(ignoreTestNode.getPath());
+
+ Node child = ignoreTestNode.getNode(nodeDefinition.getName());
+ child.remove();
+
+ superuser.save();
+ assertFalse(ignoreTestNode.hasNode(nodeDefinition.getName()));
+ }
+
+ //OAK-3328
+ public void testIsCheckedOutOPVIgnore() throws RepositoryException {
+ Node test = testRootNode.addNode("test", JcrConstants.NT_UNSTRUCTURED);
+ String nodeTypeName = "testOpvIgnore";
+ NodeDefinitionTemplate nodeDefinition =
createNodeDefinitionWithIgnoreOPVNode(nodeTypeName);
+
+ test.addMixin(JcrConstants.MIX_VERSIONABLE);
+ test.addMixin(nodeTypeName);
+ Node ignored = test.addNode(nodeDefinition.getName(),
NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ superuser.save();
+
+ VersionManager vMgr = superuser.getWorkspace().getVersionManager();
+ vMgr.checkin(test.getPath());
+
+ assertTrue(ignored.isCheckedOut());
+ assertTrue(vMgr.isCheckedOut(ignored.getPath()));
+ }
+
+ private NodeTypeTemplate createNodeTypeWithIgnoreOPVProperty(String
propertyName) throws RepositoryException {
+ NodeTypeManager manager =
superuser.getWorkspace().getNodeTypeManager();
+
+ NodeTypeTemplate nt = manager.createNodeTypeTemplate();
+ nt.setName("testType");
+ nt.setMixin(true);
+ PropertyDefinitionTemplate opt =
manager.createPropertyDefinitionTemplate();
+ opt.setMandatory(false);
+ opt.setName(propertyName);
+ opt.setRequiredType(PropertyType.STRING);
+ opt.setOnParentVersion(OnParentVersionAction.IGNORE);
+ List pdt = nt.getPropertyDefinitionTemplates();
+ pdt.add(opt);
+ manager.registerNodeType(nt, true);
+
+ return nt;
+ }
+
+ private NodeDefinitionTemplate
createNodeDefinitionWithIgnoreOPVNode(String nodeTypeName) throws
RepositoryException {
+ NodeTypeManager manager =
superuser.getWorkspace().getNodeTypeManager();
+
+ NodeDefinitionTemplate def = manager.createNodeDefinitionTemplate();
+ def.setOnParentVersion(OnParentVersionAction.IGNORE);
+ def.setName("child");
+ def.setRequiredPrimaryTypeNames(new String[]{JcrConstants.NT_BASE});
+
+ NodeTypeTemplate tmpl = manager.createNodeTypeTemplate();
+ tmpl.setName(nodeTypeName);
+ tmpl.setMixin(true);
+ tmpl.getNodeDefinitionTemplates().add(def);
+ manager.registerNodeType(tmpl, true);
+
+ return def;
+ }
}
\ No newline at end of file