You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2022/10/14 06:57:52 UTC
[jackrabbit-oak] branch OAK-9966 created (now 32fbb343df)
This is an automated email from the ASF dual-hosted git repository.
angela pushed a change to branch OAK-9966
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
at 32fbb343df OAK-9966 : Internal code calls Node.isCheckedOut and VersionManager.isCheckedOut
This branch includes the following new commits:
new 32fbb343df OAK-9966 : Internal code calls Node.isCheckedOut and VersionManager.isCheckedOut
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[jackrabbit-oak] 01/01: OAK-9966 : Internal code calls Node.isCheckedOut and VersionManager.isCheckedOut
Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
angela pushed a commit to branch OAK-9966
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 32fbb343dfe2315655ee796984f2060d9113cd89
Author: angela <an...@adobe.com>
AuthorDate: Fri Oct 14 08:57:36 2022 +0200
OAK-9966 : Internal code calls Node.isCheckedOut and VersionManager.isCheckedOut
---
.../plugins/version/ReadOnlyVersionManager.java | 22 +++++------
.../apache/jackrabbit/oak/jcr/query/QueryImpl.java | 4 +-
.../jackrabbit/oak/jcr/session/ItemImpl.java | 6 +--
.../jackrabbit/oak/jcr/session/NodeImpl.java | 37 ++++++++++-------
.../jackrabbit/oak/jcr/session/PropertyImpl.java | 27 ++++++++-----
.../jackrabbit/oak/jcr/session/SessionImpl.java | 4 +-
.../jackrabbit/oak/jcr/session/WorkspaceImpl.java | 4 ++
.../oak/jcr/version/VersionManagerImpl.java | 34 +++++++++-------
.../jackrabbit/oak/jcr/xml/ImporterImpl.java | 7 ++--
.../oak/jcr/version/VersionableTest.java | 46 ++++++++++++++++++++++
10 files changed, 130 insertions(+), 61 deletions(-)
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
index 7281cc5f29..c4e1216fdf 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
@@ -112,18 +112,16 @@ public abstract class ReadOnlyVersionManager {
* @return whether the tree is checked out or not.
*/
public boolean isCheckedOut(@NotNull Tree tree) {
- if (checkNotNull(tree).exists()) {
- PropertyState p = tree.getProperty(VersionConstants.JCR_ISCHECKEDOUT);
- if (p != null) {
- return p.getValue(Type.BOOLEAN);
- }
- } else {
- // FIXME: this actually means access to the tree is restricted
- // and may result in wrong isCheckedOut value. This should never
- // be the case in a commit hook because it operates on non-access-
- // controlled NodeStates. This means consistency is not at risk
- // but it may mean oak-jcr sees a node as checked out even though
- // it is in fact read-only because of a checked-in ancestor.
+ // NOTE: if the given tree does not exist it mean that it is a non-accessible ancestor
+ // in this case it may result in wrong isCheckedOut value. This should never
+ // be the case in a commit hook because it operates on non-access-
+ // controlled NodeStates. This means consistency is not at risk
+ // but it may mean oak-jcr sees a node as checked out even though
+ // it is in fact read-only because of a checked-in (but non-accessible) ancestor.
+ // if this turns out to be an issue see NodeImpl#getReadOnlyTree for an potential fix
+ PropertyState p = tree.getProperty(VersionConstants.JCR_ISCHECKEDOUT);
+ if (p != null) {
+ return p.getValue(Type.BOOLEAN);
}
if (tree.isRoot()) {
return true;
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java
index b4dc9fae07..8a6e26a565 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java
@@ -159,8 +159,8 @@ public class QueryImpl implements Query {
if (parentDelegate == null) {
throw new PathNotFoundException("The specified path does not exist: " + parent);
}
- Node parentNode = NodeImpl.createNode(parentDelegate, sessionContext);
- if (!parentNode.isCheckedOut()) {
+ NodeImpl parentNode = NodeImpl.createNode(parentDelegate, sessionContext);
+ if (!parentNode.internalIsCheckedOut()) {
throw new VersionException("Cannot store query. Node at " +
absPath + " is checked in.");
}
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/ItemImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/ItemImpl.java
index 9a0f861d48..5340383580 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/ItemImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/ItemImpl.java
@@ -40,7 +40,6 @@ import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.version.VersionManager;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
@@ -50,6 +49,7 @@ import org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate;
import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
import org.apache.jackrabbit.oak.jcr.session.operation.ItemOperation;
import org.apache.jackrabbit.oak.jcr.session.operation.SessionOperation;
+import org.apache.jackrabbit.oak.jcr.version.VersionManagerImpl;
import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
import org.apache.jackrabbit.oak.plugins.nodetype.write.ReadWriteNodeTypeManager;
import org.jetbrains.annotations.NotNull;
@@ -349,8 +349,8 @@ abstract class ItemImpl<T extends ItemDelegate> implements Item {
}
@NotNull
- VersionManager getVersionManager() throws RepositoryException {
- return sessionContext.getWorkspace().getVersionManager();
+ VersionManagerImpl getVersionManager() {
+ return sessionContext.getWorkspace().internalGetVersionManager();
}
@NotNull
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
index 816f91d0b6..a2ee56b397 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java
@@ -83,10 +83,12 @@ import org.apache.jackrabbit.oak.commons.LazyValue;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate;
import org.apache.jackrabbit.oak.jcr.delegate.PropertyDelegate;
+import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
import org.apache.jackrabbit.oak.jcr.delegate.VersionManagerDelegate;
import org.apache.jackrabbit.oak.jcr.lock.LockDeprecation;
import org.apache.jackrabbit.oak.jcr.session.operation.ItemOperation;
import org.apache.jackrabbit.oak.jcr.session.operation.NodeOperation;
+import org.apache.jackrabbit.oak.jcr.session.operation.SessionOperation;
import org.apache.jackrabbit.oak.jcr.version.VersionHistoryImpl;
import org.apache.jackrabbit.oak.jcr.version.VersionImpl;
import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
@@ -956,7 +958,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ if (!internalIsCheckedOut()) {
throw new VersionException(format("Cannot set primary type. Node [%s] is checked in.", getNodePath()));
}
}
@@ -978,7 +980,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ if (!internalIsCheckedOut()) {
throw new VersionException(format(
"Cannot add mixin type. Node [%s] is checked in.", getNodePath()));
}
@@ -997,7 +999,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ if (!internalIsCheckedOut()) {
throw new VersionException(format(
"Cannot remove mixin type. Node [%s] is checked in.", getNodePath()));
}
@@ -1030,7 +1032,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
return sessionContext.getAccessManager().hasPermissions(
node.getTree(), prop, Permissions.NODE_TYPE_MANAGEMENT)
&& !node.isProtected()
- && getVersionManager().isCheckedOut(toJcrPath(dlg.getPath())) // TODO: avoid nested calls
+ && getVersionManager().isCheckedOut(node)
&& node.canAddMixin(oakTypeName);
}
});
@@ -1140,13 +1142,14 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
*/
@Override
public boolean isCheckedOut() throws RepositoryException {
- try {
- return getVersionManager().isCheckedOut(getPath());
- } catch (UnsupportedRepositoryOperationException ex) {
- // when versioning is not supported all nodes are considered to be
- // checked out
- return true;
- }
+ final SessionDelegate sessionDelegate = sessionContext.getSessionDelegate();
+ return sessionDelegate.perform(new SessionOperation<Boolean>("isCheckedOut") {
+ @NotNull
+ @Override
+ public Boolean perform() throws RepositoryException {
+ return internalIsCheckedOut();
+ }
+ });
}
/**
@@ -1295,6 +1298,10 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
}
//------------------------------------------------------------< internal >---
+ public boolean internalIsCheckedOut() throws RepositoryException {
+ return getVersionManager().isCheckedOut(dlg);
+ }
+
@Nullable
private String getPrimaryTypeName(@NotNull Tree tree) {
return TreeUtil.getPrimaryTypeName(tree, getReadOnlyTree(tree));
@@ -1392,7 +1399,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut() && getOPV(dlg.getTree(), state) != OnParentVersionAction.IGNORE) {
+ if (!internalIsCheckedOut() && getOPV(dlg.getTree(), state) != OnParentVersionAction.IGNORE) {
throw new VersionException(format(
"Cannot set property. Node [%s] is checked in.", getNodePath()));
}
@@ -1438,7 +1445,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut() && getOPV(dlg.getTree(), state) != OnParentVersionAction.IGNORE) {
+ if (!internalIsCheckedOut() && getOPV(dlg.getTree(), state) != OnParentVersionAction.IGNORE) {
throw new VersionException(format(
"Cannot set property. Node [%s] is checked in.", getNodePath()));
}
@@ -1484,7 +1491,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
super.checkPreconditions();
PropertyDelegate property = dlg.getPropertyOrNull(oakName);
if (property != null &&
- !isCheckedOut() &&
+ !internalIsCheckedOut() &&
getOPV(dlg.getTree(), property.getPropertyState()) != OnParentVersionAction.IGNORE) {
throw new VersionException(format(
"Cannot remove property. Node [%s] is checked in.", getNodePath()));
@@ -1611,7 +1618,7 @@ public class NodeImpl<T extends NodeDelegate> extends ItemImpl<T> implements Jac
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!isCheckedOut()) {
+ if (!internalIsCheckedOut()) {
throw new VersionException(format("Cannot set mixin types. Node [%s] is checked in.", getNodePath()));
}
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
index ded63e6e2f..5a8e340727 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
@@ -76,12 +76,7 @@ public class PropertyImpl extends ItemImpl<PropertyDelegate> implements Property
@NotNull
@Override
public Node perform() throws RepositoryException {
- NodeDelegate parent = property.getParent();
- if (parent == null) {
- throw new AccessDeniedException();
- } else {
- return NodeImpl.createNode(parent, sessionContext);
- }
+ return internalGetParent(property, sessionContext);
}
});
}
@@ -114,7 +109,7 @@ public class PropertyImpl extends ItemImpl<PropertyDelegate> implements Property
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!getParent().isCheckedOut() && getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
+ if (!parentIsCheckedOut() && getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
throw new VersionException(
"Cannot set property. Node is checked in.");
}
@@ -464,7 +459,7 @@ public class PropertyImpl extends ItemImpl<PropertyDelegate> implements Property
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!getParent().isCheckedOut() && getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
+ if (!parentIsCheckedOut() && getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
throw new VersionException(
"Cannot set property. Node is checked in.");
}
@@ -500,7 +495,7 @@ public class PropertyImpl extends ItemImpl<PropertyDelegate> implements Property
@Override
public void checkPreconditions() throws RepositoryException {
super.checkPreconditions();
- if (!getParent().isCheckedOut() && getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
+ if (!parentIsCheckedOut() && getDefinition().getOnParentVersion() != OnParentVersionAction.IGNORE) {
throw new VersionException(
"Cannot set property. Node is checked in.");
}
@@ -532,4 +527,18 @@ public class PropertyImpl extends ItemImpl<PropertyDelegate> implements Property
});
}
+ private boolean parentIsCheckedOut() throws RepositoryException {
+ return internalGetParent(dlg, sessionContext).internalIsCheckedOut();
+ }
+
+ @NotNull
+ private static NodeImpl<? extends NodeDelegate> internalGetParent(@NotNull PropertyDelegate propertyDlg, @NotNull SessionContext sessionContext) throws RepositoryException {
+ NodeDelegate parent = propertyDlg.getParent();
+ if (parent == null) {
+ throw new AccessDeniedException();
+ } else {
+ return NodeImpl.createNode(parent, sessionContext);
+ }
+ }
+
}
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java
index 72b783cfbf..41e579766b 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java
@@ -686,8 +686,8 @@ public class SessionImpl implements JackrabbitSession {
}
boolean isNode = ((ItemImpl<?>) target).isNode();
- Node parent = (isNode) ? (Node) target : ((ItemImpl<?>) target).getParent();
- if (!parent.isCheckedOut()) {
+ NodeImpl parent = (NodeImpl) ((isNode) ? target : ((ItemImpl<?>) target).getParent());
+ if (!parent.internalIsCheckedOut()) {
return false;
}
boolean hasLocking = sessionContext.getRepository().getDescriptorValue(Repository.OPTION_LOCKING_SUPPORTED)
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java
index 58135d5ed9..b3d2c97721 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java
@@ -327,6 +327,10 @@ public class WorkspaceImpl implements JackrabbitWorkspace {
return sessionContext.getPrivilegeManager();
}
+ //------------------------------------------------------------< internal >---
+ public @NotNull VersionManagerImpl internalGetVersionManager() {
+ return versionManager;
+ }
//------------------------------------------------------------< private >---
private void ensureIsAlive() throws RepositoryException {
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
index 3a2f74589c..16868d9106 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionManagerImpl.java
@@ -252,7 +252,7 @@ public class VersionManagerImpl implements VersionManager {
@Override
public boolean isCheckedOut(final String absPath) throws RepositoryException {
final SessionDelegate sessionDelegate = sessionContext.getSessionDelegate();
- return sessionDelegate.perform(new SessionOperation<Boolean>("isCheckoutOut") {
+ return sessionDelegate.perform(new SessionOperation<Boolean>("isCheckedOut") {
@NotNull
@Override
public Boolean perform() throws RepositoryException {
@@ -261,20 +261,7 @@ public class VersionManagerImpl implements VersionManager {
if (nodeDelegate == null) {
throw new PathNotFoundException(absPath);
}
- 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;
+ return isCheckedOut(nodeDelegate);
}
});
}
@@ -380,6 +367,23 @@ public class VersionManagerImpl implements VersionManager {
}
//----------------------------< internal >----------------------------------
+
+ public boolean isCheckedOut(final @NotNull NodeDelegate nodeDelegate) throws RepositoryException {
+ 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;
+ }
private void checkPendingChangesForRestore(SessionDelegate sessionDelegate)
throws InvalidItemStateException {
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java
index 5049fbb363..a8f6f9934e 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java
@@ -35,7 +35,6 @@ import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.version.VersionException;
-import javax.jcr.version.VersionManager;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
@@ -48,10 +47,12 @@ import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate;
import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
import org.apache.jackrabbit.oak.jcr.security.AccessManager;
import org.apache.jackrabbit.oak.jcr.session.SessionContext;
import org.apache.jackrabbit.oak.jcr.session.WorkspaceImpl;
+import org.apache.jackrabbit.oak.jcr.version.VersionManagerImpl;
import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
@@ -143,8 +144,8 @@ public class ImporterImpl implements Importer {
}
WorkspaceImpl wsp = sessionContext.getWorkspace();
- VersionManager vMgr = wsp.getVersionManager();
- if (!vMgr.isCheckedOut(absPath)) {
+ VersionManagerImpl vMgr = wsp.internalGetVersionManager();
+ if (!vMgr.isCheckedOut(new NodeDelegate(sd, importTargetTree))) {
throw new VersionException("Target node is checked in.");
}
boolean hasLocking = sessionContext.getRepository().getDescriptorValue(Repository.OPTION_LOCKING_SUPPORTED).getBoolean();
diff --git a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/VersionableTest.java b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/VersionableTest.java
index f7da2d27c1..5bdaad1a68 100644
--- a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/VersionableTest.java
+++ b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/VersionableTest.java
@@ -16,11 +16,13 @@
*/
package org.apache.jackrabbit.oak.jcr.version;
+import javax.jcr.GuestCredentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
@@ -28,6 +30,10 @@ import javax.jcr.version.VersionManager;
import com.google.common.base.Function;
import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.jetbrains.annotations.Nullable;
@@ -316,6 +322,46 @@ public class VersionableTest extends AbstractJCRTest {
assertSuccessors(history, of("1.1.0", "1.3"), "1.1");
}
+ /**
+ * See {@link org.apache.jackrabbit.oak.plugins.version.ReadOnlyVersionManager#isCheckedOut(Tree)} for details.
+ */
+ public void testIsCheckedOutOnNonAccessibleParent() throws Exception {
+ Node node = testRootNode.addNode(nodeName1, testNodeType);
+ node.addMixin(mixVersionable);
+ Node child = node.addNode(nodeName2, testNodeType);
+
+ String nodePath = node.getPath();
+ String childPath = child.getPath();
+
+ // grant the guest-session read-access to child but not the parent.
+ AccessControlUtils.deny(node, EveryonePrincipal.NAME, PrivilegeConstants.JCR_READ);
+ AccessControlUtils.allow(child, EveryonePrincipal.NAME, PrivilegeConstants.JCR_READ);
+ superuser.save();
+
+ node.checkin();
+ assertFalse(node.isCheckedOut());
+ assertFalse(child.isCheckedOut());
+
+ Session guest = getHelper().getRepository().login(new GuestCredentials());
+ assertFalse(guest.nodeExists(nodePath));
+ assertTrue(guest.nodeExists((childPath)));
+
+ assertTrue(guest.getWorkspace().getVersionManager().isCheckedOut(childPath));
+ assertTrue(guest.getNode(childPath).isCheckedOut());
+
+ // grant the guest-session read-access on the parent as well -> checkin-status is visible
+ AccessControlUtils.allow(node, EveryonePrincipal.NAME, PrivilegeConstants.JCR_READ);
+ superuser.save();
+
+ guest.refresh(false);
+ assertTrue(guest.nodeExists(nodePath));
+ assertFalse(guest.getWorkspace().getVersionManager().isCheckedOut(childPath));
+ assertFalse(guest.getWorkspace().getVersionManager().isCheckedOut(nodePath));
+
+ assertFalse(guest.getNode(childPath).isCheckedOut());
+ assertFalse(guest.getNode(nodePath).isCheckedOut());
+ }
+
private static void assertSuccessors(VersionHistory history, Set<String> expectedSuccessors, String versionName) throws RepositoryException {
assertEquals(expectedSuccessors, getNames(history.getVersion(versionName).getSuccessors()));
}