/* * 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.core; import javax.jcr.Node; import javax.jcr.Workspace; import javax.jcr.NodeIterator; import javax.jcr.query.QueryManager; import javax.jcr.query.Query; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.ObservationManager; import org.apache.jackrabbit.core.observation.SynchronousEventListener; import org.apache.jackrabbit.test.AbstractJCRTest; /** * Tests features available with shareable nodes. */ public class ShareableNodeTest extends AbstractJCRTest { //------------------------------------------------------ specification tests /** * Verify that observation events are sent only once (6.13.15). */ public void testObservation() throws Exception { // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); // add mixin b1.addMixin("mix:shareable"); b1.save(); // clone Workspace workspace = b1.getSession().getWorkspace(); workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", false); // event listener that counts events received class EventCounter implements SynchronousEventListener { private int count; public void onEvent(EventIterator events) { while (events.hasNext()) { events.nextEvent(); count++; } } public int getEventCount() { return count; } public void resetCount() { count = 0; } } EventCounter el = new EventCounter(); ObservationManager om = superuser.getWorkspace().getObservationManager(); // add node underneath shared set: verify it generates one event only om.addEventListener(el, Event.NODE_ADDED, testRootNode.getPath(), true, null, null, false); b1.addNode("c"); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); assertEquals(1, el.getEventCount()); // remove node underneath shared set: verify it generates one event only el.resetCount(); om.addEventListener(el, Event.NODE_REMOVED, testRootNode.getPath(), true, null, null, false); b1.getNode("c").remove(); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); assertEquals(1, el.getEventCount()); // add property underneath shared set: verify it generates one event only el.resetCount(); om.addEventListener(el, Event.PROPERTY_ADDED, testRootNode.getPath(), true, null, null, false); b1.setProperty("c", "1"); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); assertEquals(1, el.getEventCount()); // modify property underneath shared set: verify it generates one event only el.resetCount(); om.addEventListener(el, Event.PROPERTY_CHANGED, testRootNode.getPath(), true, null, null, false); b1.setProperty("c", "2"); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); assertEquals(1, el.getEventCount()); // remove property underneath shared set: verify it generates one event only el.resetCount(); om.addEventListener(el, Event.PROPERTY_REMOVED, testRootNode.getPath(), true, null, null, false); b1.getProperty("c").remove(); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); assertEquals(1, el.getEventCount()); } /** * Verify that a shared node is removed when the ancestor is removed. * See also JCR-2257. */ public void testRemoveAncestorOfSharedNode() throws Exception { Node a1 = testRootNode.addNode("a1"); Node a2 = a1.addNode("a2"); Node b1 = a1.addNode("b1"); ensureMixinType(b1, mixShareable); testRootNode.save(); //now we have a shareable node N with path a1/b1 Workspace workspace = testRootNode.getSession().getWorkspace(); String path = a2.getPath() + "/b2"; workspace.clone(workspace.getName(), b1.getPath(), path, false); testRootNode.save(); //now we have another shareable node N' in the same shared set as N with path a1/a2/b2 a2.remove(); testRootNode.save(); // assert b2 is removed from index QueryManager qm = superuser.getWorkspace().getQueryManager(); String stmt = testPath + "//b2"; NodeIterator it = qm.createQuery(stmt, Query.XPATH).execute().getNodes(); assertFalse(it.hasNext()); } }