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 ju...@apache.org on 2013/07/02 17:27:39 UTC

svn commit: r1498977 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/ oak-jcr/src/main/j...

Author: jukka
Date: Tue Jul  2 15:27:39 2013
New Revision: 1498977

URL: http://svn.apache.org/r1498977
Log:
OAK-803: Backwards compatibility of long-lived sessions

Auto-refresh only if events have been delivered or if the session has not been accessed in more than one seconds (TODO: make configurable)

Moved ObservationManagerImpl and a few of the supporting classes from oak-core to o.a.j.oak.jcr.observation as they are only needed in oak-jcr.

Added:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java   (contents, props changed)
      - copied, changed from r1498912, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java   (contents, props changed)
      - copied, changed from r1498912, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventFilter.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java   (contents, props changed)
      - copied, changed from r1498912, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java
Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventFilter.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java
Modified:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionContext.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/MoveRemoveTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java?rev=1498977&r1=1498976&r2=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java Tue Jul  2 15:27:39 2013
@@ -121,25 +121,12 @@ public class RepositoryImpl implements R
      */
     @Override
     public Session login(@Nullable Credentials credentials, @Nullable String workspaceName) throws RepositoryException {
-        // TODO implement auto refresh configuration. See OAK-803, OAK-88
-        final boolean autoRefresh = true;
         try {
-            ContentSession contentSession = contentRepository.login(credentials, workspaceName);
-
-            final SessionContext[] context = new SessionContext[1];  // FIXME hack[]
-            SessionDelegate sessionDelegate = new SessionDelegate(contentSession) {
-                @Override
-                protected void refresh() {
-                    // Refresh is always needed if this is an auto refresh session or there
-                    // are pending observation events
-                    if (autoRefresh || context[0].hasPendingEvents()) {
-                        refresh(true);
-                    }
-                }
-            };
-
-            context[0] = new SessionContext(this, whiteboard, sessionDelegate);
-            return context[0].getSession();
+            ContentSession contentSession =
+                    contentRepository.login(credentials, workspaceName);
+            SessionContext context = new SessionContext(
+                    this, whiteboard, new SessionDelegate(contentSession));
+            return context.getSession();
         } catch (LoginException e) {
             throw new javax.jcr.LoginException(e.getMessage(), e);
         }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionContext.java?rev=1498977&r1=1498976&r2=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionContext.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionContext.java Tue Jul  2 15:27:39 2013
@@ -41,12 +41,12 @@ import org.apache.jackrabbit.JcrConstant
 import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.UserManager;
-import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.ContentSession;
 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.observation.ObservationManagerImpl;
 import org.apache.jackrabbit.oak.jcr.security.AccessManager;
 import org.apache.jackrabbit.oak.jcr.version.VersionHistoryImpl;
 import org.apache.jackrabbit.oak.jcr.version.VersionImpl;
@@ -58,7 +58,6 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.nodetype.EffectiveNodeTypeProvider;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.plugins.observation.Observable;
-import org.apache.jackrabbit.oak.plugins.observation.ObservationManagerImpl;
 import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
 import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConfiguration;
@@ -90,7 +89,7 @@ public class SessionContext implements N
     private PrincipalManager principalManager;
     private UserManager userManager;
     private PrivilegeManager privilegeManager;
-    private ObservationManager observationManager;
+    private ObservationManagerImpl observationManager;
 
     SessionContext(
             RepositoryImpl repository, Whiteboard whiteboard,
@@ -227,24 +226,19 @@ public class SessionContext implements N
     @Nonnull
     public ObservationManager getObservationManager() throws UnsupportedRepositoryOperationException {
         if (observationManager == null) {
-            ContentRepository contentRepository = repository.getContentRepository();
             ContentSession contentSession = getSessionDelegate().getContentSession();
             if (!(contentSession instanceof Observable)) {
                 throw new UnsupportedRepositoryOperationException("Observation not supported for session " + contentSession);
             }
 
             observationManager = new ObservationManagerImpl(
-                contentSession,
+                delegate,
                 ReadOnlyNodeTypeManager.getInstance(delegate.getRoot(), namePathMapper),
                 namePathMapper, whiteboard);
         }
         return observationManager;
     }
 
-    public boolean hasPendingEvents() {
-        return observationManager != null && (((ObservationManagerImpl) observationManager).hasEvents());
-    }
-
     //-----------------------------------------------------< NamePathMapper >---
 
     @Override
@@ -331,7 +325,7 @@ public class SessionContext implements N
 
     void dispose() {
         if (observationManager != null) {
-            ((ObservationManagerImpl) observationManager).dispose();
+            observationManager.dispose();
         }
         namespaces.clear();
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java?rev=1498977&r1=1498976&r2=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java Tue Jul  2 15:27:39 2013
@@ -365,16 +365,26 @@ public class SessionImpl implements Jack
 
     @Override
     public void save() throws RepositoryException {
-        sd.checkAlive();
-        sd.save();
-        sessionContext.refresh();
+        perform(new CheckedSessionOperation<Void>() {
+            @Override
+            protected Void perform() throws RepositoryException {
+                sd.save();
+                sessionContext.refresh();
+                return null;
+            }
+        });
     }
 
     @Override
-    public void refresh(boolean keepChanges) throws RepositoryException {
-        sd.checkAlive();
-        sd.refresh(keepChanges);
-        sessionContext.refresh();
+    public void refresh(final boolean keepChanges) throws RepositoryException {
+        perform(new CheckedSessionOperation<Void>() {
+            @Override
+            protected Void perform() throws RepositoryException {
+                sd.refresh(keepChanges);
+                sessionContext.refresh();
+                return null;
+            }
+        });
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java?rev=1498977&r1=1498976&r2=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java Tue Jul  2 15:27:39 2013
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.jcr.de
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.io.IOException;
+import java.util.concurrent.TimeUnit;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
@@ -53,6 +54,10 @@ public class SessionDelegate {
 
     static final Logger log = LoggerFactory.getLogger(SessionDelegate.class);
 
+    // TODO implement auto refresh configuration. See OAK-803, OAK-88
+    private static final long AUTO_REFRESH_INTERVAL =
+            TimeUnit.SECONDS.toMillis(1);
+
     private final ContentSession contentSession;
     private final Root root;
     private final IdentifierManager idManager;
@@ -60,18 +65,16 @@ public class SessionDelegate {
     private boolean isAlive = true;
     private int sessionOpCount;
 
+    private long lastAccessed = System.currentTimeMillis();
+
     public SessionDelegate(@Nonnull ContentSession contentSession) {
         this.contentSession = checkNotNull(contentSession);
         this.root = contentSession.getLatestRoot();
         this.idManager = new IdentifierManager(root);
     }
 
-    /**
-     * Called by {@link #perform(SessionOperation)} when the session needs to be
-     * refreshed before the actual {@link SessionOperation} is executed.
-     * This default implementation is empty.
-     */
-    protected void refresh() {
+    public void refreshAtNextAccess() {
+        lastAccessed = -1;
     }
 
     /**
@@ -85,11 +88,17 @@ public class SessionDelegate {
      * @return  the result of {@code sessionOperation.perform()}
      * @throws RepositoryException
      */
-    public synchronized <T> T perform(SessionOperation<T> sessionOperation) throws RepositoryException {
+    public synchronized <T> T perform(SessionOperation<T> sessionOperation)
+            throws RepositoryException {
         // Synchronize to avoid conflicting refreshes from concurrent JCR API calls
         if (sessionOpCount == 0) {
             // Refresh and checks only for non re-entrant session operations
-            refresh();
+            long now = System.currentTimeMillis();
+            if (now > lastAccessed + AUTO_REFRESH_INTERVAL) {
+                refresh(true);
+            }
+            lastAccessed = now;
+
             sessionOperation.checkPreconditions();
         }
         try {
@@ -247,6 +256,7 @@ public class SessionDelegate {
                 throw new RepositoryException("Cannot copy node at " + srcPath + " to " + destPath);
             }
             currentRoot.commit();
+            refresh(false);
         } catch (CommitFailedException e) {
             throw newRepositoryException(e);
         }
@@ -291,6 +301,7 @@ public class SessionDelegate {
             }
             if (!transientOp) {
                 moveRoot.commit();
+                refresh(true);
             }
         } catch (CommitFailedException e) {
             throw newRepositoryException(e);

Copied: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java (from r1498912, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java?p2=jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java&r1=1498912&r2=1498977&rev=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java Tue Jul  2 15:27:39 2013
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.jackrabbit.oak.plugins.observation;
+package org.apache.jackrabbit.oak.jcr.observation;
 
 import static com.google.common.base.Preconditions.checkState;
 
@@ -36,10 +36,14 @@ import org.apache.jackrabbit.JcrConstant
 import org.apache.jackrabbit.api.jmx.EventListenerMBean;
 import org.apache.jackrabbit.commons.iterator.EventIteratorAdapter;
 import org.apache.jackrabbit.commons.observation.ListenerTracker;
+import org.apache.jackrabbit.oak.api.ContentSession;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.observation.EventImpl;
+import org.apache.jackrabbit.oak.plugins.observation.Observable;
+import org.apache.jackrabbit.oak.plugins.observation.RecursingNodeStateDiff;
 import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.ChangeSet;
 import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.Listener;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -65,7 +69,7 @@ class ChangeProcessor implements Runnabl
     private static final Logger log =
             LoggerFactory.getLogger(ChangeProcessor.class);
 
-    private final ObservationManagerImpl observationManager;
+    private final ContentSession contentSession;
     private final NamePathMapper namePathMapper;
     private final AtomicReference<EventFilter> filterRef;
     private final AtomicReference<String> userDataRef = new AtomicReference<String>(null);
@@ -82,11 +86,10 @@ class ChangeProcessor implements Runnabl
     private Listener changeListener;
 
     public ChangeProcessor(
-            ObservationManagerImpl observationManager,
-            ListenerTracker tracker,
-            EventFilter filter) {
-        this.observationManager = observationManager;
-        this.namePathMapper = observationManager.getNamePathMapper();
+            ContentSession contentSession, NamePathMapper namePathMapper,
+            ListenerTracker tracker, EventFilter filter) {
+        this.contentSession = contentSession;
+        this.namePathMapper = namePathMapper;
         this.tracker = tracker;
         this.listener = tracker.getTrackedListener();
         filterRef = new AtomicReference<EventFilter>(filter);
@@ -118,7 +121,7 @@ class ChangeProcessor implements Runnabl
         checkState(runnable == null, "Change processor started already");
 
         stopping = false;
-        changeListener = observationManager.newChangeListener();
+        changeListener = ((Observable) contentSession).newListener();
         runnable = WhiteboardUtils.scheduleWithFixedDelay(whiteboard, this, 1);
         mbean = WhiteboardUtils.registerMBean(
                 whiteboard, EventListenerMBean.class, tracker.getListenerMBean(),
@@ -180,7 +183,7 @@ class ChangeProcessor implements Runnabl
             ChangeSet changes = changeListener.getChanges();
             while (!stopping && changes != null) {
                 EventFilter filter = filterRef.get();
-                if (!(filter.excludeLocal() && changes.isLocal(observationManager.getContentSession()))) {
+                if (!(filter.excludeLocal() && changes.isLocal(contentSession))) {
                     String path = namePathMapper.getOakPath(filter.getPath());
                     EventGeneratingNodeStateDiff diff = new EventGeneratingNodeStateDiff(changes, path);
                     changes.diff(VisibleDiff.wrap(diff), path);
@@ -237,7 +240,6 @@ class ChangeProcessor implements Runnabl
         public void sendEvents() {
             Iterator<Event> eventIt = Iterators.concat(events.iterator());
             if (eventIt.hasNext()) {
-                observationManager.setHasEvents();
                 listener.onEvent(new EventIteratorAdapter(eventIt) {
                     @Override
                     public boolean hasNext() {

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Copied: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java (from r1498912, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventFilter.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java?p2=jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventFilter.java&r1=1498912&r2=1498977&rev=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventFilter.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java Tue Jul  2 15:27:39 2013
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.jackrabbit.oak.plugins.observation;
+package org.apache.jackrabbit.oak.jcr.observation;
 
 import static com.google.common.base.Objects.toStringHelper;
 

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Copied: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java (from r1498912, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java?p2=jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java&r1=1498912&r2=1498977&rev=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java Tue Jul  2 15:27:39 2013
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.jackrabbit.oak.plugins.observation;
+package org.apache.jackrabbit.oak.jcr.observation;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.Lists.newArrayList;
@@ -24,7 +24,6 @@ import static com.google.common.collect.
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
@@ -36,9 +35,10 @@ import javax.jcr.observation.Observation
 import org.apache.jackrabbit.commons.iterator.EventListenerIteratorAdapter;
 import org.apache.jackrabbit.commons.observation.ListenerTracker;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
-import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.Listener;
+import org.apache.jackrabbit.oak.plugins.observation.Observable;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,6 +46,7 @@ import org.slf4j.Marker;
 import org.slf4j.MarkerFactory;
 
 public class ObservationManagerImpl implements ObservationManager {
+
     private static final Logger log = LoggerFactory.getLogger(ObservationManagerImpl.class);
 
     public static final Marker OBSERVATION =
@@ -54,8 +55,10 @@ public class ObservationManagerImpl impl
     private static final Marker DEPRECATED =
             MarkerFactory.getMarker("deprecated");
 
-    private final Map<EventListener, ChangeProcessor> processors = new HashMap<EventListener, ChangeProcessor>();
-    private final AtomicBoolean hasEvents = new AtomicBoolean(false);
+    private final Map<EventListener, ChangeProcessor> processors =
+            new HashMap<EventListener, ChangeProcessor>();
+
+    private final SessionDelegate sessionDelegate;
     private final ContentSession contentSession;
     private final ReadOnlyNodeTypeManager ntMgr;
     private final NamePathMapper namePathMapper;
@@ -72,12 +75,13 @@ public class ObservationManagerImpl impl
      * @param whiteboard
      * @throws IllegalArgumentException if {@code contentSession} doesn't implement {@code Observable}.
      */
-    public ObservationManagerImpl(ContentSession contentSession, ReadOnlyNodeTypeManager nodeTypeManager,
+    public ObservationManagerImpl(
+            SessionDelegate sessionDelegate, ReadOnlyNodeTypeManager nodeTypeManager,
             NamePathMapper namePathMapper, Whiteboard whiteboard) {
 
+        this.sessionDelegate = sessionDelegate;
+        this.contentSession = sessionDelegate.getContentSession();
         checkArgument(contentSession instanceof Observable);
-
-        this.contentSession = contentSession;
         this.ntMgr = nodeTypeManager;
         this.namePathMapper = namePathMapper;
         this.whiteboard = whiteboard;
@@ -96,15 +100,6 @@ public class ObservationManagerImpl impl
         }
     }
 
-    /**
-     * Determine whether events have been generated since the time this method has been called.
-     * @return  {@code true} if this {@code ObservationManager} instance has generated events
-     *          since the last time this method has been called, {@code false} otherwise.
-     */
-    public boolean hasEvents() {
-        return hasEvents.getAndSet(false);
-    }
-
     @Override
     public synchronized void addEventListener(EventListener listener, int eventTypes, String absPath,
             boolean isDeep, String[] uuid, String[] nodeTypeName, boolean noLocal) throws RepositoryException {
@@ -116,12 +111,17 @@ public class ObservationManagerImpl impl
             ListenerTracker tracker = new ListenerTracker(
                     listener, eventTypes, absPath, isDeep,
                     uuid, nodeTypeName, noLocal) {
-                        @Override
-                        protected void warn(String message) {
-                            log.warn(DEPRECATED, message, initStackTrace);
-                        }
+                @Override
+                protected void warn(String message) {
+                    log.warn(DEPRECATED, message, initStackTrace);
+                }
+                @Override
+                protected void beforeEventDelivery() {
+                    sessionDelegate.refreshAtNextAccess();
+                }
             };
-            processor = new ChangeProcessor(this, tracker, filter);
+            processor = new ChangeProcessor(
+                    contentSession, namePathMapper, tracker, filter);
             processors.put(listener, processor);
             processor.start(whiteboard);
         } else {
@@ -164,21 +164,4 @@ public class ObservationManagerImpl impl
         throw new UnsupportedRepositoryOperationException();
     }
 
-    //------------------------------------------------------------< internal >---
-
-    NamePathMapper getNamePathMapper() {
-        return namePathMapper;
-    }
-
-    void setHasEvents() {
-        hasEvents.set(true);
-    }
-
-    Listener newChangeListener() {
-        return ((Observable) contentSession).newListener();
-    }
-
-    public ContentSession getContentSession() {
-        return contentSession;
-    }
 }

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/MoveRemoveTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/MoveRemoveTest.java?rev=1498977&r1=1498976&r2=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/MoveRemoveTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/MoveRemoveTest.java Tue Jul  2 15:27:39 2013
@@ -76,6 +76,7 @@ public class MoveRemoveTest extends Abst
         n.remove();
         session.save();
 
+        session2.refresh(false);
         try {
             n2.getPath();
             fail();
@@ -83,6 +84,8 @@ public class MoveRemoveTest extends Abst
 
         session.getRootNode().addNode("new");
         session.save();
+
+        session2.refresh(false);
         assertEquals("/new", n2.getPath());
 
         session2.logout();
@@ -136,6 +139,7 @@ public class MoveRemoveTest extends Abst
         n.getParent().remove();
         session.save();
 
+        session2.refresh(false);
         try {
             n2.getPath();
             fail();
@@ -143,6 +147,8 @@ public class MoveRemoveTest extends Abst
 
         session.getRootNode().addNode("parent").addNode("new");
         session.save();
+
+        session2.refresh(false);
         assertEquals("/parent/new", n2.getPath());
 
         session2.logout();
@@ -184,6 +190,7 @@ public class MoveRemoveTest extends Abst
         session.move("/new", "/moved");
         session.save();
 
+        session2.refresh(false);
         try {
             n2.getPath();
             fail();
@@ -191,6 +198,8 @@ public class MoveRemoveTest extends Abst
 
         session.getRootNode().addNode("new");
         session.save();
+
+        session2.refresh(false);
         assertEquals("/new", n2.getPath());
 
         session2.logout();
@@ -234,6 +243,7 @@ public class MoveRemoveTest extends Abst
         session.move("/parent", "/moved");
         session.save();
 
+        session2.refresh(false);
         try {
             n2.getPath();
             fail();
@@ -241,6 +251,8 @@ public class MoveRemoveTest extends Abst
 
         session.getRootNode().addNode("parent").addNode("new");
         session.save();
+
+        session2.refresh(false);
         assertEquals("/parent/new", n2.getPath());
 
         session2.logout();

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java?rev=1498977&r1=1498976&r2=1498977&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java Tue Jul  2 15:27:39 2013
@@ -35,7 +35,6 @@ import java.math.BigDecimal;
 import java.util.Calendar;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.Executors;
 
 import javax.jcr.Binary;
 import javax.jcr.GuestCredentials;
@@ -1336,7 +1335,15 @@ public class RepositoryTest extends Abst
 
             session1.save();
 
-            // Make sure these items are still accessible through another session
+            // Make sure they are still not accessible through another session
+            assertFalse(session2.itemExists("/node1"));
+            assertFalse(session2.itemExists("/node1/node2"));
+            assertFalse(session2.itemExists("/node1/node3"));
+            assertFalse(session2.itemExists("/node1/node3/property1"));
+
+            session2.refresh(false);
+
+            // Make sure they are accessible through another session after refresh
             assertTrue(session2.itemExists("/node1"));
             assertTrue(session2.itemExists("/node1/node2"));
             assertTrue(session2.itemExists("/node1/node3"));
@@ -1439,8 +1446,8 @@ public class RepositoryTest extends Abst
             session1.save();
             session2.save();
             assertTrue(session1.getRootNode().hasNode("node1"));
-            assertTrue(session1.getRootNode().hasNode("node2"));
-            assertTrue(session2.getRootNode().hasNode("node1"));
+            assertFalse(session1.getRootNode().hasNode("node2")); // was not visible during save
+            assertTrue(session2.getRootNode().hasNode("node1")); // save refreshes
             assertTrue(session2.getRootNode().hasNode("node2"));
         } finally {
             session1.logout();
@@ -1493,7 +1500,7 @@ public class RepositoryTest extends Abst
 
             session1.save();
             assertFalse(session1.getRootNode().hasNode("node"));
-            assertFalse(session2.getRootNode().hasNode("node"));
+            assertTrue(session2.getRootNode().hasNode("node"));
 
             try {
                 session2.save();