/*
* 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.test.api.observation;
import org.apache.jackrabbit.test.NotExecutableException;
import javax.jcr.observation.Event;
import javax.jcr.RepositoryException;
import javax.jcr.Node;
import javax.jcr.Session;
/**
* Tests the options for addEventListener().
* <p>
* Configuration requirements:
* <p>
* The {@link #testRoot} must allow child nodes of type {@link #testNodeType}.
* The child nodes that are created will be named {@link #nodeName1} and
* {@link #nodeName2}. Furthermore {@link #testNodeType} must allow to add
* child nodes of the same type ({@link #testNodeType}).
* <p>
* Certain test require that {@link #testNodeType} is mix:referenceable or
* allows to add that mixin. If the repository does not support mix:referenceable
* a {@link org.apache.jackrabbit.test.NotExecutableException} is thrown
* in those test cases.
*
*/
public class AddEventListenerTest extends AbstractObservationTest {
/**
* Tests if events are only created for a sub tree of the workspace.
*/
public void testPath() throws RepositoryException {
EventResult listener = new EventResult(log);
obsMgr.addEventListener(listener, Event.NODE_ADDED, testRoot + "/" + nodeName1, true, null, null, false);
Node n = testRootNode.addNode(nodeName1, testNodeType);
n.addNode(nodeName2, testNodeType);
testRootNode.getSession().save();
Event[] events = listener.getEvents(DEFAULT_WAIT_TIMEOUT);
obsMgr.removeEventListener(listener);
checkNodeAdded(events, new String[]{nodeName1 + "/" + nodeName2}, null);
}
/**
* Tests if {@link javax.jcr.observation.Event#NODE_ADDED} is created only
* for the specified path if <code>isDeep</code> is <code>false</code>.
*/
public void testIsDeepFalseNodeAdded() throws RepositoryException {
EventResult listener = new EventResult(log);
obsMgr.addEventListener(listener, Event.NODE_ADDED, testRoot + "/" + nodeName1, false, null, null, false);
Node n = testRootNode.addNode(nodeName1, testNodeType);
n.addNode(nodeName2, testNodeType);
testRootNode.getSession().save();
Event[] events = listener.getEvents(DEFAULT_WAIT_TIMEOUT);
obsMgr.removeEventListener(listener);
checkNodeAdded(events, new String[]{nodeName1 + "/" + nodeName2}, null);
}
/**
* Tests if {@link javax.jcr.observation.Event#PROPERTY_ADDED} is created only
* for the specified path if <code>isDeep</code> is <code>false</code>.
*/
public void testIsDeepFalsePropertyAdded() throws RepositoryException {
Node n1 = testRootNode.addNode(nodeName1, testNodeType);
Node n2 = testRootNode.addNode(nodeName2, testNodeType);
testRootNode.getSession().save();
EventResult listener = new EventResult(log);
obsMgr.addEventListener(listener, Event.PROPERTY_ADDED, testRoot + "/" + nodeName1, false, null, null, false);
n1.setProperty(propertyName1, "foo");
n2.setProperty(propertyName1, "foo");
testRootNode.getSession().save();
Event[] events = listener.getEvents(DEFAULT_WAIT_TIMEOUT);
obsMgr.removeEventListener(listener);
checkPropertyAdded(events, new String[]{nodeName1 + "/" + propertyName1});
}
/**
* Tests if no events are generated for own modifications if
* <code>noLocal</code> is set to <code>true</code>.
*/
public void testNoLocalTrue() throws RepositoryException {
EventResult listener = new EventResult(log);
obsMgr.addEventListener(listener,
Event.NODE_ADDED,
testRoot,
true,
null,
null,
true); // noLocal
testRootNode.addNode(nodeName1, testNodeType);
testRootNode.getSession().save();
// only wait one second because we don't expect any event
Event[] events = listener.getEvents(1000);
obsMgr.removeEventListener(listener);
assertEquals("EventListener must not receive own modification when noLocal=true", 0, events.length);
}
/**
* Tests if events are only generated for specified UUIDs.
*/
public void testUUID() throws RepositoryException, NotExecutableException {
Node n1 = null;
Node n2 = null;
try {
n1 = createReferenceable(nodeName1, testNodeType);
n2 = createReferenceable(nodeName2, testNodeType);
} catch (RepositoryException e) {
throw new NotExecutableException("Repository does not support mix:referenceable");
}
testRootNode.getSession().save();
EventResult listener = new EventResult(log);
obsMgr.addEventListener(listener,
Event.PROPERTY_ADDED,
testRoot,
true,
new String[]{n1.getIdentifier()},
null,
false);
n1.setProperty(propertyName1, "foo");
n2.setProperty(propertyName1, "foo");
testRootNode.getSession().save();
Event[] events = listener.getEvents(DEFAULT_WAIT_TIMEOUT);
obsMgr.removeEventListener(listener);
checkPropertyAdded(events, new String[]{nodeName1 + "/" + propertyName1});
}
/**
* Tests if events are only generated for specified node types.
*/
public void testNodeType() throws RepositoryException {
String nodetype2 = getProperty("nodetype2");
EventResult listener = new EventResult(log);
Node n1 = testRootNode.addNode(nodeName1, testNodeType);
Node n2 = testRootNode.addNode(nodeName2, nodetype2);
testRootNode.getSession().save();
obsMgr.addEventListener(listener,
Event.NODE_ADDED,
testRoot,
true,
null,
new String[]{testNodeType},
false);
Session s = getHelper().getSuperuserSession();
try {
Node n = (Node) s.getItem(n1.getPath());
n.addNode(nodeName3, testNodeType);
n = (Node) s.getItem(n2.getPath());
n.addNode(nodeName3, nodetype2);
n = (Node) s.getItem(testRoot);
n.save();
} finally {
s.logout();
}
Event[] events = listener.getEvents(DEFAULT_WAIT_TIMEOUT);
obsMgr.removeEventListener(listener);
checkNodeAdded(events, new String[]{nodeName1 + "/" + nodeName3}, null);
}
//-------------------------< internal >-------------------------------------
/**
* Creates a node with name <code>nodeName</code> with type
* <code>nodeType</code> as a child node of {@link #testRootNode}.
* If the created node is not of type mix:referenceable a mixin is added
* of that type.
*
* @param nodeName the node name.
* @param nodeType the node type of the node to create.
* @return the created node
* @throws RepositoryException if node creation fails.
*/
private Node createReferenceable(String nodeName, String nodeType)
throws RepositoryException, NotExecutableException {
Node n = testRootNode.addNode(nodeName, nodeType);
ensureMixinType(n, mixReferenceable);
testRootNode.getSession().save();
return n;
}
}