Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrObservationManager.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrObservationManager.java (revision 1875)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrObservationManager.java (working copy)
@@ -91,6 +91,11 @@ final class JcrObservationManager implements ObservationManager {
private final ValueFactories valueFactories;
/**
+ * The name of the session's workspace; cached for performance reasons.
+ */
+ private final String workspaceName;
+
+ /**
* @param session the owning session (never null
)
* @param repositoryObservable the repository observable used to register JCR listeners (never null
)
* @throws IllegalArgumentException if either parameter is null
@@ -105,6 +110,7 @@ final class JcrObservationManager implements ObservationManager {
this.listeners = new ConcurrentHashMap();
this.namespaceRegistry = this.session.getExecutionContext().getNamespaceRegistry();
this.valueFactories = this.session.getExecutionContext().getValueFactories();
+ this.workspaceName = this.session.getWorkspace().getName();
}
/**
@@ -194,6 +200,13 @@ final class JcrObservationManager implements ObservationManager {
}
/**
+ * @return workspaceName
+ */
+ final String getWorkspaceName() {
+ return workspaceName;
+ }
+
+ /**
* Remove all of the listeners. This is typically called when the {@link JcrSession#logout() session logs out}.
*/
synchronized void removeAllEventListeners() {
@@ -698,6 +711,10 @@ final class JcrObservationManager implements ObservationManager {
// loop through changes saving the parent locations of the changed locations
for (ChangeRequest request : changes.getChangeRequests()) {
+ // ignore all events other than those on this workspace ...
+ if (!getWorkspaceName().equals(request.changedWorkspace())) {
+ continue;
+ }
Path changedPath = request.changedLocation().getPath();
Path parentPath = changedPath.getParent();
changedLocations.add(Location.create(parentPath));
@@ -725,6 +742,11 @@ final class JcrObservationManager implements ObservationManager {
Collection events = new ArrayList();
for (NetChange change : netChanges.getNetChanges()) {
+ // ignore all events other than those on this workspace ...
+ if (!getWorkspaceName().equals(change.getRepositoryWorkspaceName())) {
+ continue;
+ }
+
// ignore if lock/unlock
if (change.includes(ChangeType.NODE_LOCKED) || change.includes(ChangeType.NODE_UNLOCKED)) {
continue;
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrObservationManagerTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrObservationManagerTest.java (revision 1875)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrObservationManagerTest.java (working copy)
@@ -113,10 +113,15 @@ public final class JcrObservationManagerTest extends TestSuite {
// ===========================================================================================================================
// Fields
// ===========================================================================================================================
+ protected static final String WORKSPACE = "ws1";
+ protected static final String WORKSPACE2 = "ws2";
+ protected static final String REPOSITORY = "r1";
+ protected static final String SOURCE = "store";
private JcrEngine engine;
private Session session;
private Node testRootNode;
+ private List sessions;
// ===========================================================================================================================
// Methods
@@ -140,26 +145,49 @@ public final class JcrObservationManagerTest extends TestSuite {
String[] uuids,
String[] nodeTypeNames,
boolean noLocal ) throws Exception {
+ return addListener(this.session, eventsExpected, numIterators, eventTypes, absPath, isDeep, uuids, nodeTypeNames, noLocal);
+ }
+
+ TestListener addListener( Session session,
+ int eventsExpected,
+ int eventTypes,
+ String absPath,
+ boolean isDeep,
+ String[] uuids,
+ String[] nodeTypeNames,
+ boolean noLocal ) throws Exception {
+ return addListener(session, eventsExpected, 1, eventTypes, absPath, isDeep, uuids, nodeTypeNames, noLocal);
+ }
+
+ TestListener addListener( Session session,
+ int eventsExpected,
+ int numIterators,
+ int eventTypes,
+ String absPath,
+ boolean isDeep,
+ String[] uuids,
+ String[] nodeTypeNames,
+ boolean noLocal ) throws Exception {
TestListener listener = new TestListener(eventsExpected, numIterators, eventTypes);
- this.session.getWorkspace().getObservationManager().addEventListener(listener,
- eventTypes,
- absPath,
- isDeep,
- uuids,
- nodeTypeNames,
- noLocal);
+ session.getWorkspace().getObservationManager().addEventListener(listener,
+ eventTypes,
+ absPath,
+ isDeep,
+ uuids,
+ nodeTypeNames,
+ noLocal);
return listener;
}
@After
public void afterEach() {
try {
- if (this.session != null) {
- this.session.logout();
+ for (Session session : sessions) {
+ if (session != null && session.isLive()) session.logout();
}
} finally {
this.session = null;
-
+ this.sessions.clear();
try {
this.engine.shutdown();
} finally {
@@ -170,14 +198,13 @@ public final class JcrObservationManagerTest extends TestSuite {
@Before
public void beforeEach() throws RepositoryException {
- final String WORKSPACE = "ws1";
- final String REPOSITORY = "r1";
- final String SOURCE = "store";
+ sessions = new ArrayList();
JcrConfiguration config = new JcrConfiguration();
config.repositorySource("store")
.usingClass(InMemoryRepositorySource.class)
.setRetryLimit(100)
+ .setProperty("predefinedWorkspaceNames", new String[] {WORKSPACE, WORKSPACE2})
.setProperty("defaultWorkspaceName", WORKSPACE);
config.repository(REPOSITORY).setSource(SOURCE).setOption(Option.JAAS_LOGIN_CONFIG_NAME, "modeshape-jcr");
config.save();
@@ -187,14 +214,25 @@ public final class JcrObservationManagerTest extends TestSuite {
this.engine.start();
// Create repository and session
- Repository repository = this.engine.getRepository(REPOSITORY);
- Credentials credentials = new SimpleCredentials(USER_ID, USER_ID.toCharArray());
- this.session = repository.login(credentials, WORKSPACE);
+ this.session = login(REPOSITORY, WORKSPACE, USER_ID, USER_ID.toCharArray());
this.testRootNode = this.session.getRootNode().addNode("testroot", UNSTRUCTURED);
save();
}
+ protected Session login( String repositoryName,
+ String workspaceName,
+ String userId,
+ char[] password ) throws RepositoryException {
+ Repository repository = this.engine.getRepository(repositoryName);
+ Credentials credentials = new SimpleCredentials(userId, password);
+ Session session = repository.login(credentials, workspaceName);
+ if (session != null) {
+ sessions.add(session);
+ }
+ return session;
+ }
+
void checkResults( TestListener listener ) {
if (listener.getActualEventCount() != listener.getExpectedEventCount()) {
// Wrong number ...
@@ -1643,6 +1681,42 @@ public final class JcrObservationManagerTest extends TestSuite {
+ ", expected=" + oldPath, containsPath(removeNodeListener, oldPath));
}
+ @Test
+ public void shouldNotReceiveEventsFromOtherWorkspaces() throws Exception {
+ // Log into a second workspace ...
+ Session session2 = login(REPOSITORY, "ws2", USER_ID, USER_ID.toCharArray());
+
+ // Register 2 listeners in the first session ...
+ TestListener listener1 = addListener(session, 4, ALL_EVENTS, "/", true, null, null, false);
+ TestListener addListener1 = addListener(session, 1, Event.NODE_ADDED, "/", true, null, null, false);
+
+ // Register 2 listeners in the second session ...
+ TestListener listener2 = addListener(session2, 0, ALL_EVENTS, "/", true, null, null, false);
+ TestListener addListener2 = addListener(session2, 0, Event.NODE_ADDED, "/", true, null, null, false);
+
+ // Add a node to the first session ...
+ session.getRootNode().addNode("nodeA", "nt:unstructured");
+ session.save();
+
+ // Wait for the events on the first session's listeners (that should get the events) ...
+ listener1.waitForEvents();
+ addListener1.waitForEvents();
+ removeListener(listener1);
+ removeListener(addListener1);
+
+ // Wait for the events on the second session's listeners (that should NOT get the events) ...
+ listener2.waitForEvents();
+ // addListener2.waitForEvents();
+ removeListener(listener2);
+ removeListener(addListener2);
+
+ // Verify the expected events were received ...
+ checkResults(listener1);
+ checkResults(addListener1);
+ checkResults(listener2);
+ checkResults(addListener2);
+ }
+
// ===========================================================================================================================
// Inner Class
// ===========================================================================================================================