Skip to content

Commit

Permalink
OAK-9613 : Define API to retrieve parent or null for a given Item
Browse files Browse the repository at this point in the history
  • Loading branch information
anchela committed Nov 4, 2021
1 parent 2c3ce07 commit ccf825d
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 1 deletion.
10 changes: 10 additions & 0 deletions oak-jackrabbit-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,15 @@
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.jackrabbit.api.security.principal.PrincipalManager;

import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.Session;
Expand All @@ -28,6 +29,7 @@
import javax.jcr.UnsupportedRepositoryOperationException;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Jackrabbit specific extension of the JCR {@link javax.jcr.Session} interface.
Expand Down Expand Up @@ -252,4 +254,22 @@ public interface JackrabbitSession extends Session {
*/
Node getNodeOrNull(final String absPath) throws RepositoryException;

/**
* Returns the parent of the given {@code Item} or {@code null} if no parent exists (either because the given {@code Item}
* represents the root node or the current session does not have sufficient access to retrieve the parent).
*
* @param item An {@code Item} that has been obtained by the current session.
* @return The parent node of the given {@code Item} or {@code null}.
* @throws RepositoryException If another error occurs.
* @see Item#getParent()
* @since 1.42
*/
@Nullable
default Node getParentOrNull(@NotNull Item item) throws RepositoryException {
try {
return item.getParent();
} catch (ItemNotFoundException | AccessDeniedException e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
/**
* Jackrabbit extensions for JCR core interfaces
*/
@org.osgi.annotation.versioning.Version("2.6.0")
@org.osgi.annotation.versioning.Version("2.7.0")
package org.apache.jackrabbit.api;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.api;

import org.junit.Test;
import org.mockito.Answers;

import javax.jcr.AccessDeniedException;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;

import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;

public class JackrabbitSessionTest {

@Test
public void testGetParentOrNull() throws Exception {
JackrabbitSession s = mock(JackrabbitSession.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));
Node parent = mock(Node.class);
Item item = mock(Item.class);

when(item.getParent()).thenReturn(parent).getMock();
assertSame(parent, s.getParentOrNull(item));

doThrow(new AccessDeniedException()).when(item).getParent();
assertNull(s.getParentOrNull(item));

doThrow(new ItemNotFoundException()).when(item).getParent();
assertNull(s.getParentOrNull(item));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,35 @@ public Item performNullable() throws RepositoryException {
});
}

@Override
@Nullable
public Node getParentOrNull(@NotNull Item item) throws RepositoryException {
checkAlive();
ItemImpl itemImpl = checkItemImpl(item);
checkContext(itemImpl, sessionContext);
return sd.performNullable(new ReadOperation<Node>("getParentOrNull") {
@Override
public Node performNullable() throws RepositoryException {
return NodeImpl.createNodeOrNull(itemImpl.dlg.getParent(), sessionContext);
}
});
}

private static void checkContext(@NotNull ItemImpl item, @NotNull SessionContext context) throws RepositoryException {
if (item.sessionContext != context) {
throw new RepositoryException("Item '"+item+"' has been obtained through a different Session.");
}
}

@NotNull
private static ItemImpl checkItemImpl(@NotNull Item item) throws RepositoryException {
if (item instanceof ItemImpl) {
return (ItemImpl) item;
} else {
throw new RepositoryException("Invalid item implementation '"+item.getClass().getName()+"'. Excpected org.apache.jackrabbit.oak.jcr.session.ItemImpl");
}
}

//------------------------------------------------------------< Session >---

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.oak.jcr.session;

import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.apache.jackrabbit.test.NotExecutableException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.jcr.GuestCredentials;
import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;

import static org.mockito.Mockito.mock;

public class JackrabbitSessionTest extends AbstractJCRTest {

private JackrabbitSession s;

@Override
protected void setUp() throws Exception {
super.setUp();

if (superuser instanceof JackrabbitSession) {
s = (JackrabbitSession) superuser;
} else {
throw new NotExecutableException("JackrabbitSession expected");
}
}

public void testGetParentOrNullRootNode() throws Exception {
assertNull(s.getParentOrNull(s.getRootNode()));
}

public void testGetParentOrNull() throws Exception {
Node n = s.getNode(testRoot);
assertEquivalentNode(n, s.getParentOrNull(n.getProperty(Property.JCR_PRIMARY_TYPE)));
assertEquivalentNode(n.getParent(), s.getParentOrNull(n));
}

private static void assertEquivalentNode(@NotNull Node expected, @Nullable Node result) throws Exception {
assertNotNull(result);
assertEquals(expected.getPath(), result.getPath());
}

public void testGetParentOrNullSessionMismatch() throws Exception {
JackrabbitSession guest = (JackrabbitSession) getHelper().getRepository().login(new GuestCredentials());
try {
guest.getParentOrNull(s.getNode(testRoot));
fail("RepositoryException expected");
} catch (RepositoryException e) {
// success
} finally {
guest.logout();
}
}

public void testGetParentOrNullImplMismatch() {
try {
Item item = mock(Item.class);
s.getParentOrNull(item);
fail("RepositoryException expected");
} catch (RepositoryException e) {
// success
}
}


}

0 comments on commit ccf825d

Please sign in to comment.