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 md...@apache.org on 2012/10/19 14:27:09 UTC

svn commit: r1400068 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/api/ main/java/org/apache/jackrabbit/oak/core/ test/java/org/apache/jackrabbit/oak/api/

Author: mduerig
Date: Fri Oct 19 12:27:09 2012
New Revision: 1400068

URL: http://svn.apache.org/viewvc?rev=1400068&view=rev
Log:
OAK-387: Clarify behavior/state of Root and Tree after calling ContentSession#close()

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentSessionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java?rev=1400068&r1=1400067&r2=1400068&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java Fri Oct 19 12:27:09 2012
@@ -26,6 +26,10 @@ import javax.annotation.Nonnull;
  * <p>
  * The data returned by this class filtered for the access rights that are set
  * in the {@link ContentSession} that created this object.
+ * <p>
+ * All root instances created by a content session become invalid after the
+ * content session is closed. Any method called on an invalid root instance
+ * will throw an {@code InvalidStateException}.
  */
 public interface Root {
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java?rev=1400068&r1=1400067&r2=1400068&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java Fri Oct 19 12:27:09 2012
@@ -51,6 +51,10 @@ import javax.annotation.Nonnull;
  * The data returned by this class and intermediary objects such as
  * {@link PropertyState} is filtered for the access rights that are set in the
  * {@link ContentSession} that created the {@link Root} of this object.
+ * <p>
+ * All tree instances created in the context of a content session become invalid
+ * after the content session is closed. Any method called on an invalid tree instance
+ * will throw an {@code InvalidStateException}.
  */
 public interface Tree {
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentSessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentSessionImpl.java?rev=1400068&r1=1400067&r2=1400068&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentSessionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentSessionImpl.java Fri Oct 19 12:27:09 2012
@@ -35,6 +35,8 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkState;
+
 /**
  * {@code MicroKernel}-based implementation of the {@link ContentSession} interface.
  */
@@ -49,6 +51,8 @@ class ContentSessionImpl implements Cont
     private final ConflictHandler conflictHandler;
     private final QueryIndexProvider indexProvider;
 
+    private volatile boolean live = true;
+
     public ContentSessionImpl(LoginContext loginContext,
             AccessControlProvider accProvider, String workspaceName,
             NodeStore store, ConflictHandler conflictHandler,
@@ -61,10 +65,15 @@ class ContentSessionImpl implements Cont
         this.indexProvider = indexProvider;
     }
 
+    private void checkLive() {
+        checkState(live, "This session has been closed");
+    }
+
     //-----------------------------------------------------< ContentSession >---
     @Nonnull
     @Override
     public AuthInfo getAuthInfo() {
+        checkLive();
         Set<AuthInfo> infoSet = loginContext.getSubject().getPublicCredentials(AuthInfo.class);
         if (infoSet.isEmpty()) {
             return AuthInfo.EMPTY;
@@ -81,7 +90,13 @@ class ContentSessionImpl implements Cont
     @Nonnull
     @Override
     public Root getLatestRoot() {
-        RootImpl root = new RootImpl(store, workspaceName, loginContext.getSubject(), accProvider, indexProvider);
+        checkLive();
+        RootImpl root = new RootImpl(store, workspaceName, loginContext.getSubject(), accProvider, indexProvider) {
+            @Override
+            protected void checkLive() {
+                ContentSessionImpl.this.checkLive();
+            }
+        };
         if (conflictHandler != null) {
             root.setConflictHandler(conflictHandler);
         }
@@ -90,6 +105,7 @@ class ContentSessionImpl implements Cont
 
     @Override
     public Blob createBlob(InputStream inputStream) throws IOException {
+        checkLive();
         return store.createBlob(inputStream);
     }
 
@@ -98,6 +114,7 @@ class ContentSessionImpl implements Cont
     public synchronized void close() throws IOException {
         try {
             loginContext.logout();
+            live = false;
         } catch (LoginException e) {
             log.error("Error during logout.", e);
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1400068&r1=1400067&r2=1400068&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java Fri Oct 19 12:27:09 2012
@@ -140,9 +140,14 @@ public class RootImpl implements Root {
         return conflictHandler;
     }
 
+    protected void checkLive() {
+
+    }
+
     //---------------------------------------------------------------< Root >---
     @Override
     public boolean move(String sourcePath, String destPath) {
+        checkLive();
         TreeImpl source = rootTree.getTree(sourcePath);
         if (source == null) {
             return false;
@@ -164,23 +169,27 @@ public class RootImpl implements Root {
 
     @Override
     public boolean copy(String sourcePath, String destPath) {
+        checkLive();
         purgePendingChanges();
         return branch.copy(sourcePath, destPath);
     }
 
     @Override
     public TreeImpl getTree(String path) {
+        checkLive();
         return rootTree.getTree(path);
     }
 
     @Override
     public TreeLocation getLocation(String path) {
+        checkLive();
         checkArgument(path.startsWith("/"));
         return rootTree.getLocation().getChild(path.substring(1));
     }
 
     @Override
     public void rebase() {
+        checkLive();
         if (!store.getRoot().equals(rootTree.getBaseState())) {
             purgePendingChanges();
             NodeState base = getBaseState();
@@ -192,12 +201,14 @@ public class RootImpl implements Root {
 
     @Override
     public final void refresh() {
+        checkLive();
         branch = store.branch();
         rootTree = TreeImpl.createRoot(this);
     }
 
     @Override
     public void commit() throws CommitFailedException {
+        checkLive();
         rebase();
         purgePendingChanges();
         CommitFailedException exception = Subject.doAs(
@@ -236,11 +247,13 @@ public class RootImpl implements Root {
 
     @Override
     public boolean hasPendingChanges() {
+        checkLive();
         return !getBaseState().equals(rootTree.getNodeState());
     }
 
     @Nonnull
     public ChangeExtractor getChangeExtractor() {
+        checkLive();
         return new ChangeExtractor() {
             private NodeState baseLine = store.getRoot();
 
@@ -255,6 +268,7 @@ public class RootImpl implements Root {
 
     @Override
     public SessionQueryEngine getQueryEngine() {
+        checkLive();
         return new SessionQueryEngineImpl(store, indexProvider);
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java?rev=1400068&r1=1400067&r2=1400068&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java Fri Oct 19 12:27:09 2012
@@ -99,16 +99,19 @@ public class TreeImpl implements Tree, P
 
     @Override
     public String getName() {
+        root.checkLive();
         return name;
     }
 
     @Override
     public boolean isRoot() {
+        root.checkLive();
         return parent == null;
     }
 
     @Override
     public String getPath() {
+        root.checkLive();
         if (isRoot()) {
             // shortcut
             return "/";
@@ -121,6 +124,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public Tree getParent() {
+        root.checkLive();
         if (parent != null && canRead(parent)) {
             return parent;
         } else {
@@ -130,6 +134,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public PropertyState getProperty(String name) {
+        root.checkLive();
         PropertyState property = internalGetProperty(name);
         if (canRead(property)) {
             return property;
@@ -141,6 +146,7 @@ public class TreeImpl implements Tree, P
     @Override
     public Status getPropertyStatus(String name) {
         // TODO: see OAK-212
+        root.checkLive();
         Status nodeStatus = getStatus();
         if (nodeStatus == Status.NEW) {
             return (hasProperty(name)) ? Status.NEW : null;
@@ -170,16 +176,19 @@ public class TreeImpl implements Tree, P
 
     @Override
     public boolean hasProperty(String name) {
+        root.checkLive();
         return getProperty(name) != null;
     }
 
     @Override
     public long getPropertyCount() {
+        root.checkLive();
         return Iterables.size(getProperties());
     }
 
     @Override
     public Iterable<? extends PropertyState> getProperties() {
+        root.checkLive();
         return Iterables.filter(getNodeBuilder().getProperties(),
                 new Predicate<PropertyState>() {
                     @Override
@@ -191,6 +200,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public TreeImpl getChild(String name) {
+        root.checkLive();
         TreeImpl child = internalGetChild(name);
         if (child != null && canRead(child)) {
             return child;
@@ -201,6 +211,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public Status getStatus() {
+        root.checkLive();
         if (isRemoved()) {
             return Status.REMOVED;
         }
@@ -223,17 +234,20 @@ public class TreeImpl implements Tree, P
 
     @Override
     public boolean hasChild(String name) {
+        root.checkLive();
         return getChild(name) != null;
     }
 
     @Override
     public long getChildrenCount() {
         // TODO: make sure cnt respects access control
+        root.checkLive();
         return getNodeBuilder().getChildNodeCount();
     }
 
     @Override
     public Iterable<Tree> getChildren() {
+        root.checkLive();
         Iterable<String> childNames;
         if (hasOrderableChildren()) {
             childNames = getOrderedChildNames();
@@ -263,6 +277,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public Tree addChild(String name) {
+        root.checkLive();
         if (!hasChild(name)) {
             getNodeBuilder().child(name);
             if (hasOrderableChildren()) {
@@ -281,6 +296,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public boolean remove() {
+        root.checkLive();
         if (isRemoved()) {
             throw new IllegalStateException("Cannot remove removed tree");
         }
@@ -306,6 +322,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public boolean orderBefore(final String name) {
+        root.checkLive();
         if (isRoot()) {
             // root does not have siblings
             return false;
@@ -352,6 +369,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public void setProperty(PropertyState property) {
+        root.checkLive();
         NodeBuilder builder = getNodeBuilder();
         builder.setProperty(property);
         root.purge();
@@ -359,6 +377,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public <T> void setProperty(String name, T value) {
+        root.checkLive();
         NodeBuilder builder = getNodeBuilder();
         builder.setProperty(name, value);
         root.purge();
@@ -366,6 +385,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public <T> void setProperty(String name, T value, Type<T> type) {
+        root.checkLive();
         NodeBuilder builder = getNodeBuilder();
         builder.setProperty(name, value, type);
         root.purge();
@@ -373,6 +393,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public void removeProperty(String name) {
+        root.checkLive();
         NodeBuilder builder = getNodeBuilder();
         builder.removeProperty(name);
         root.purge();
@@ -380,6 +401,7 @@ public class TreeImpl implements Tree, P
 
     @Override
     public TreeLocation getLocation() {
+        root.checkLive();
         return new NodeLocation(this);
     }
 
@@ -502,8 +524,8 @@ public class TreeImpl implements Tree, P
     }
 
     /**
-     * @return <code>true</code> if this tree has orderable children;
-     *         <code>false</code> otherwise.
+     * @return {@code true} if this tree has orderable children;
+     *         {@code false} otherwise.
      */
     private boolean hasOrderableChildren() {
         return internalGetProperty(OAK_CHILD_ORDER) != null;
@@ -521,7 +543,7 @@ public class TreeImpl implements Tree, P
             @Override
             public Iterator<String> iterator() {
                 return new Iterator<String>() {
-                    PropertyState childOrder = internalGetProperty(OAK_CHILD_ORDER);
+                    final PropertyState childOrder = internalGetProperty(OAK_CHILD_ORDER);
                     int index = 0;
 
                     @Override

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java?rev=1400068&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java Fri Oct 19 12:27:09 2012
@@ -0,0 +1,73 @@
+/*
+ * 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.api;
+
+import java.io.IOException;
+
+import javax.jcr.NoSuchWorkspaceException;
+import javax.security.auth.login.LoginException;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.plugins.commit.AnnotatingConflictHandler;
+import org.apache.jackrabbit.oak.plugins.commit.ConflictValidator;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ContentSessionTest {
+
+    private ContentRepository repository;
+
+    @Before
+    public void setUp() {
+        repository = new Oak()
+                .with(new ConflictValidator())
+                .with(new AnnotatingConflictHandler())
+                .createContentRepository();
+    }
+
+    @After
+    public void tearDown() {
+        repository = null;
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void throwOnClosedSession() throws LoginException, NoSuchWorkspaceException, IOException {
+        ContentSession session = repository.login(null, null);
+        session.close();
+        session.getLatestRoot();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void throwOnClosedRoot() throws LoginException, NoSuchWorkspaceException, IOException {
+        ContentSession session = repository.login(null, null);
+        Root root = session.getLatestRoot();
+        session.close();
+        root.getTree("/");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void throwOnClosedTree() throws LoginException, NoSuchWorkspaceException, IOException {
+        ContentSession session = repository.login(null, null);
+        Root root = session.getLatestRoot();
+        Tree tree = root.getTree("/");
+        session.close();
+        tree.getChild("any");
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/ContentSessionTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL