You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2009/04/15 21:43:02 UTC
svn commit: r765328 [1/2] - in /jackrabbit/trunk:
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/obse...
Author: mreutegg
Date: Wed Apr 15 19:43:01 2009
New Revision: 765328
URL: http://svn.apache.org/viewvc?rev=765328&view=rev
Log:
JCR-2074: JSR 283: New Event Types
Added:
jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/Event.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/AbstractObservationTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/EventJournalTest.java (contents, props changed)
- copied, changed from r765154, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/EventJournalTest.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetDateTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetIdentifierTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetInfoTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetUserDataTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeMovedTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeReorderTest.java (with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/TestAll.java (with props)
Removed:
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/AbstractObservationTest.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/EventJournalTest.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/UserDataTest.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ChangeLogRecord.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/ShareableNodesTest.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/TestAll.java
jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java
Added: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/Event.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/Event.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/Event.java (added)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/Event.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,112 @@
+/*
+ * 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.api.jsr283.observation;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>Event</code> is a preliminary interface that contains the new methods
+ * introduce in JSR 283.
+ * <p/>
+ * <b>This interface will be removed once JSR 283 is final.</b>
+ */
+public interface Event extends javax.jcr.observation.Event {
+
+ /**
+ * Generated on persist when a node is moved.
+ * <ul>
+ * <li>{@link #getPath} returns the absolute path of the destination of the move.</li>
+ * <li>{@link #getIdentifier} returns the identifier of the moved node.
+ * <li>
+ * {@link #getInfo} If the method that caused this event was
+ * a {@link javax.jcr.Session#move Session.move} or {@link javax.jcr.Workspace#move Workspace.move}
+ * then the returned {@link java.util.Map Map} has keys <code>srcAbsPath</code> and <code>destAbsPath</code>
+ * with values corresponding to the parameters passed to the <code>move</code> method.
+ * <p>
+ * If the method that caused this event was a {@link javax.jcr.Node#orderBefore Node.orderBefore}
+ * then the returned <code>Map</code> has keys <code>srcChildRelPath</code> and <code>destChildRelPath</code>
+ * with values corresponding to the parameters passed to the <code>orderBefore</code> method.
+ * </li>
+ * </ul>
+ *
+ * @since JCR 2.0
+ */
+ public static final int NODE_MOVED = 0x20;
+
+ /**
+ * If event bundling is supported, this event is used to indicate a
+ * bundle boundary within the event journal.
+ * <ul>
+ * <li>{@link #getPath} returns <code>null</code>.</li>
+ * <li>{@link #getIdentifier} returns <code>null</code>.</li>
+ * <li>{@link #getInfo} returns an empty <code>Map</code> object.</li>
+ * </ul>
+ *
+ * @since JCR 2.0
+ */
+ public static final int PERSIST = 0x40;
+
+ /**
+ * Returns the identifier associated with this event or <code>null</code>
+ * if this event has no associated identifier. The meaning of the associated
+ * identifier depends upon the type of the event.
+ * See event type constants above.
+ *
+ * @return the identifier associated with this event or <code>null</code>.
+ * @throws RepositoryException if an error occurs.
+ * @since JCR 2.0
+ */
+ public String getIdentifier() throws RepositoryException;
+
+ /**
+ * Returns the information map associated with this event.
+ * The meaning of the map depends upon the type of the event.
+ * See event type constants above.
+ *
+ * @return A <code>Map</code> containing parameter information
+ * for instances of a <code>NODE_MOVED</code> event.
+ *
+ * @throws RepositoryException if an error occurs.
+ * @since JCR 2.0
+ */
+ public Map getInfo() throws RepositoryException;
+
+ /**
+ * Returns the user data set through <code>ObservationManager.setUserData()</code>
+ * on the <code>ObservationManager</code> bound to the <code>Session</code> that caused
+ * the event.
+ *
+ * @return String
+ * @throws RepositoryException if an error occurs.
+ * @since JCR 2.0
+ */
+ public String getUserData() throws RepositoryException;
+
+ /**
+ * Returns the date when the change was persisted that caused this event.
+ * The date is represented as a millisecond value that is an offset from the
+ * Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian). The granularity of
+ * the returned value is implementation dependent.
+ *
+ * @return the date when the change was persisted that caused this event.
+ * @throws RepositoryException if an error occurs.
+ * @since JCR 2.0
+ */
+ public long getDate() throws RepositoryException;
+}
Propchange: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/observation/Event.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ChangeLogRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ChangeLogRecord.java?rev=765328&r1=765327&r2=765328&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ChangeLogRecord.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ChangeLogRecord.java Wed Apr 15 19:43:01 2009
@@ -22,11 +22,14 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
import javax.jcr.Session;
-import javax.jcr.observation.Event;
+import javax.jcr.PropertyType;
import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.core.journal.JournalException;
import org.apache.jackrabbit.core.journal.Record;
import org.apache.jackrabbit.core.observation.EventState;
@@ -36,6 +39,7 @@
import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.api.jsr283.observation.Event;
/**
* Cluster record representing a workspace or version update.
@@ -278,8 +282,32 @@
mixins.add(record.readQName());
}
String userId = record.readString();
- events.add(createEventState(type, parentId, parentPath, childId,
- childRelPath, ntName, mixins, userId));
+
+ Map info = null;
+ if (type == Event.NODE_MOVED) {
+ info = new HashMap();
+ // read info map
+ int infoSize = record.readInt();
+ for (int i = 0; i < infoSize; i++) {
+ String key = record.readString();
+ int propType = record.readInt();
+ InternalValue value;
+ if (propType == PropertyType.UNDEFINED) {
+ // indicates null value
+ value = null;
+ } else {
+ value = InternalValue.valueOf(record.readString(), propType);
+ }
+ info.put(key, value);
+ }
+ }
+
+ EventState es = createEventState(type, parentId, parentPath, childId,
+ childRelPath, ntName, mixins, userId);
+ if (info != null) {
+ es.setInfo(info);
+ }
+ events.add(es);
}
/**
@@ -299,24 +327,27 @@
NodeId childId, Path.Element childRelPath,
Name ntName, Set mixins, String userId) {
switch (type) {
- case Event.NODE_ADDED:
- return EventState.childNodeAdded(parentId, parentPath, childId, childRelPath,
- ntName, mixins, getOrCreateSession(userId), true);
- case Event.NODE_REMOVED:
- return EventState.childNodeRemoved(parentId, parentPath, childId, childRelPath,
- ntName, mixins, getOrCreateSession(userId), true);
- case Event.PROPERTY_ADDED:
- return EventState.propertyAdded(parentId, parentPath, childRelPath,
- ntName, mixins, getOrCreateSession(userId), true);
- case Event.PROPERTY_CHANGED:
- return EventState.propertyChanged(parentId, parentPath, childRelPath,
- ntName, mixins, getOrCreateSession(userId), true);
- case Event.PROPERTY_REMOVED:
- return EventState.propertyRemoved(parentId, parentPath, childRelPath,
- ntName, mixins, getOrCreateSession(userId), true);
- default:
- String msg = "Unexpected event type: " + type;
- throw new IllegalArgumentException(msg);
+ case Event.NODE_ADDED:
+ return EventState.childNodeAdded(parentId, parentPath, childId, childRelPath,
+ ntName, mixins, getOrCreateSession(userId), true);
+ case Event.NODE_MOVED:
+ return EventState.nodeMoved(parentId, parentPath, childId, childRelPath,
+ ntName, mixins, getOrCreateSession(userId), true);
+ case Event.NODE_REMOVED:
+ return EventState.childNodeRemoved(parentId, parentPath, childId, childRelPath,
+ ntName, mixins, getOrCreateSession(userId), true);
+ case Event.PROPERTY_ADDED:
+ return EventState.propertyAdded(parentId, parentPath, childRelPath,
+ ntName, mixins, getOrCreateSession(userId), true);
+ case Event.PROPERTY_CHANGED:
+ return EventState.propertyChanged(parentId, parentPath, childRelPath,
+ ntName, mixins, getOrCreateSession(userId), true);
+ case Event.PROPERTY_REMOVED:
+ return EventState.propertyRemoved(parentId, parentPath, childRelPath,
+ ntName, mixins, getOrCreateSession(userId), true);
+ default:
+ String msg = "Unexpected event type: " + type;
+ throw new IllegalArgumentException(msg);
}
}
@@ -448,6 +479,25 @@
record.writeQName((Name) iter.next());
}
record.writeString(event.getUserId());
+
+ if (event.getType() == Event.NODE_MOVED) {
+ // write info map
+ Map info = event.getInfo();
+ record.writeInt(info.size());
+ for (Iterator it = info.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) it.next();
+ String key = (String) entry.getKey();
+ InternalValue value = (InternalValue) entry.getValue();
+ record.writeString(key);
+ if (value == null) {
+ // use undefined for null value
+ record.writeInt(PropertyType.UNDEFINED);
+ } else {
+ record.writeInt(value.getType());
+ record.writeString(value.toString());
+ }
+ }
+ }
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java?rev=765328&r1=765327&r2=765328&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java Wed Apr 15 19:43:01 2009
@@ -16,9 +16,15 @@
*/
package org.apache.jackrabbit.core.observation;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
import org.apache.jackrabbit.api.observation.JackrabbitEvent;
+import org.apache.jackrabbit.api.jsr283.observation.Event;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
@@ -31,7 +37,7 @@
* Implementation of the {@link javax.jcr.observation.Event} and
* the {@link JackrabbitEvent} interface.
*/
-public final class EventImpl implements JackrabbitEvent {
+public final class EventImpl implements JackrabbitEvent, Event {
/**
* Logger instance for this class
@@ -119,6 +125,35 @@
return userData;
}
+ /**
+ * {@inheritDoc}
+ */
+ public String getIdentifier() throws RepositoryException {
+ NodeId id = eventState.getChildId();
+ if (id == null) {
+ // property event
+ id = eventState.getParentId();
+ }
+ return id.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map getInfo() throws RepositoryException {
+ Map info = new HashMap();
+ for (Iterator it = eventState.getInfo().entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) it.next();
+ InternalValue value = (InternalValue) entry.getValue();
+ String strValue = null;
+ if (value != null) {
+ strValue = value.toJCRValue(session).getString();
+ }
+ info.put(entry.getKey(), strValue);
+ }
+ return info;
+ }
+
//-----------------------------------------------------------< EventImpl >
/**
@@ -205,6 +240,7 @@
sb.append(", UserId: ").append(getUserID());
sb.append(", Timestamp: ").append(timestamp);
sb.append(", UserData: ").append(userData);
+ sb.append(", Info: ").append(eventState.getInfo());
stringValue = sb.toString();
}
return stringValue;
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java?rev=765328&r1=765327&r2=765328&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java Wed Apr 15 19:43:01 2009
@@ -20,18 +20,25 @@
import org.apache.jackrabbit.core.ItemId;
import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.PathBuilder;
+import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
+import org.apache.jackrabbit.api.jsr283.observation.Event;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import javax.jcr.Session;
+import javax.jcr.PathNotFoundException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.observation.Event;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
/**
* The <code>EventState</code> class encapsulates the session
@@ -45,6 +52,26 @@
private static final Logger log = LoggerFactory.getLogger(EventState.class);
/**
+ * The key <code>srcAbsPath</code> in the info map.
+ */
+ static final String SRC_ABS_PATH = "srcAbsPath";
+
+ /**
+ * The key <code>destAbsPath</code> in the info map.
+ */
+ static final String DEST_ABS_PATH = "destAbsPath";
+
+ /**
+ * The key <code>srcChildRelPath</code> in the info map.
+ */
+ static final String SRC_CHILD_REL_PATH = "srcChildRelPath";
+
+ /**
+ * The key <code>destChildRelPath</code> in the info map.
+ */
+ static final String DEST_CHILD_REL_PATH = "destChildRelPath";
+
+ /**
* The {@link javax.jcr.observation.Event} of this event.
*/
private final int type;
@@ -113,6 +140,11 @@
private final boolean external;
/**
+ * The info Map associated with this event.
+ */
+ private Map info = Collections.EMPTY_MAP;
+
+ /**
* If set to <code>true</code>, indicates that the child node of a node
* added or removed event is a shareable node.
*/
@@ -276,6 +308,128 @@
/**
* Creates a new {@link javax.jcr.observation.Event} of type
+ * <code>NODE_MOVED</code>. The parent node associated with this event type
+ * is the parent node of the destination of the move!
+ * This method creates an event state without an info map. A caller of this
+ * method must ensure that it is properly set afterwards.
+ *
+ * @param parentId the id of the parent node associated with
+ * this <code>EventState</code>.
+ * @param parentPath the path of the parent node associated with
+ * this <code>EventState</code>.
+ * @param childId the id of the child node associated with this event.
+ * @param childPath the relative path of the child node that was moved.
+ * @param nodeType the node type of the parent node.
+ * @param mixins mixins assigned to the parent node.
+ * @param session the session that moved the node.
+ * @param external flag indicating whether this is an external event
+ * @return an <code>EventState</code> instance.
+ */
+ public static EventState nodeMoved(NodeId parentId,
+ Path parentPath,
+ NodeId childId,
+ Path.Element childPath,
+ Name nodeType,
+ Set mixins,
+ Session session,
+ boolean external) {
+
+ return new EventState(Event.NODE_MOVED, parentId, parentPath,
+ childId, childPath, nodeType, mixins, session, external);
+ }
+
+ /**
+ * Creates a new {@link javax.jcr.observation.Event} of type
+ * <code>NODE_MOVED</code>. The parent node associated with this event type
+ * is the parent node of the destination of the move!
+ *
+ * @param parentId the id of the parent node associated with this
+ * <code>EventState</code>.
+ * @param destPath the path of the destination of the move.
+ * @param childId the id of the child node associated with this event.
+ * @param srcPath the path of the source of the move.
+ * @param nodeType the node type of the parent node.
+ * @param mixins mixins assigned to the parent node.
+ * @param session the session that removed the node.
+ * @param external flag indicating whether this is an external event
+ * @return an <code>EventState</code> instance.
+ * @throws ItemStateException if <code>destPath</code> does not have a
+ * parent.
+ */
+ public static EventState nodeMoved(NodeId parentId,
+ Path destPath,
+ NodeId childId,
+ Path srcPath,
+ Name nodeType,
+ Set mixins,
+ Session session,
+ boolean external)
+ throws ItemStateException {
+ try {
+ EventState es = nodeMoved(parentId, destPath.getAncestor(1),
+ childId, destPath.getNameElement(), nodeType, mixins,
+ session, external);
+ Map info = new HashMap();
+ info.put(SRC_ABS_PATH, InternalValue.create(srcPath));
+ info.put(DEST_ABS_PATH, InternalValue.create(destPath));
+ es.setInfo(info);
+ return es;
+ } catch (PathNotFoundException e) {
+ // should never happen actually
+ String msg = "Unable to resolve parent for path: " + destPath;
+ log.error(msg);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * Creates a new {@link javax.jcr.observation.Event} of type
+ * <code>NODE_MOVED</code>. The parent node associated with this event type
+ * is the parent node of the destination of the reorder!
+ *
+ * @param parentId the id of the parent node associated with this
+ * <code>EventState</code>.
+ * @param parentPath the path of the parent node associated with
+ * this <code>EventState</code>.
+ * @param childId the id of the child node associated with this
+ * event.
+ * @param destChildPath the name element of the node before it was reordered.
+ * @param srcChildPath the name element of the reordered node before the
+ * reorder operation.
+ * @param beforeChildPath the name element of the node before which the
+ * reordered node is placed. (may be <code>null</code>
+ * if reordered to the end.
+ * @param nodeType the node type of the parent node.
+ * @param mixins mixins assigned to the parent node.
+ * @param session the session that removed the node.
+ * @param external flag indicating whether this is an external event
+ * @return an <code>EventState</code> instance.
+ */
+ public static EventState nodeReordered(NodeId parentId,
+ Path parentPath,
+ NodeId childId,
+ Path.Element destChildPath,
+ Path.Element srcChildPath,
+ Path.Element beforeChildPath,
+ Name nodeType,
+ Set mixins,
+ Session session,
+ boolean external) {
+ EventState es = nodeMoved(parentId, parentPath, childId, destChildPath,
+ nodeType, mixins, session, external);
+ Map info = new HashMap();
+ info.put(SRC_CHILD_REL_PATH, createValue(srcChildPath));
+ InternalValue value = null;
+ if (beforeChildPath != null) {
+ value = createValue(beforeChildPath);
+ }
+ info.put(DEST_CHILD_REL_PATH, value);
+ es.setInfo(info);
+ return es;
+ }
+
+ /**
+ * Creates a new {@link javax.jcr.observation.Event} of type
* {@link javax.jcr.observation.Event#PROPERTY_ADDED}.
*
* @param parentId the id of the parent node associated with
@@ -569,6 +723,22 @@
}
/**
+ * @return an unmodifiable info Map.
+ */
+ public Map getInfo() {
+ return info;
+ }
+
+ /**
+ * Sets a new info map for this event.
+ *
+ * @param info the new info map.
+ */
+ public void setInfo(Map info) {
+ this.info = Collections.unmodifiableMap(new HashMap(info));
+ }
+
+ /**
* Returns a flag indicating whether the child node of this event is a
* shareable node. Only applies to node added/removed events.
*
@@ -601,6 +771,7 @@
sb.append(", Parent: ").append(parentId);
sb.append(", Child: ").append(childRelPath);
sb.append(", UserId: ").append(session.getUserID());
+ sb.append(", Info: ").append(info);
stringValue = sb.toString();
}
return stringValue;
@@ -619,6 +790,7 @@
h = 37 * h + parentId.hashCode();
h = 37 * h + childRelPath.hashCode();
h = 37 * h + session.hashCode();
+ h = 37 * h + info.hashCode();
hashCode = h;
}
return hashCode;
@@ -641,7 +813,8 @@
return this.type == other.type
&& this.parentId.equals(other.parentId)
&& this.childRelPath.equals(other.childRelPath)
- && this.session.equals(other.session);
+ && this.session.equals(other.session)
+ && this.info.equals(other.info);
}
return false;
}
@@ -655,6 +828,8 @@
public static String valueOf(int eventType) {
if (eventType == Event.NODE_ADDED) {
return "NodeAdded";
+ } else if (eventType == Event.NODE_MOVED) {
+ return "NodeMoved";
} else if (eventType == Event.NODE_REMOVED) {
return "NodeRemoved";
} else if (eventType == Event.PROPERTY_ADDED) {
@@ -668,4 +843,20 @@
}
}
+ /**
+ * Creates an internal path value from the given path <code>element</code>.
+ *
+ * @param element the path element.
+ * @return an internal value wrapping the path element.
+ */
+ private static InternalValue createValue(Path.Element element) {
+ PathBuilder builder = new PathBuilder();
+ builder.addFirst(element);
+ try {
+ return InternalValue.create(builder.getPath());
+ } catch (MalformedPathException e) {
+ // this exception is only thrown when number of element is zero
+ throw new InternalError();
+ }
+ }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java?rev=765328&r1=765327&r2=765328&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java Wed Apr 15 19:43:01 2009
@@ -171,7 +171,7 @@
// 2) property removed
// 3) child node added
// 4) child node removed
- // 5) node moved
+ // 5) node moved/reordered
// 6) node reordered
// 7) shareable node added
// 8) shareable node removed
@@ -213,23 +213,24 @@
Path newPath = getPath(n.getNodeId(), hmgr);
Path oldPath = getZombiePath(n.getNodeId(), hmgr);
events.add(EventState.childNodeRemoved(oldParentId,
- getParent(oldPath),
- n.getNodeId(),
+ getParent(oldPath), n.getNodeId(),
oldPath.getNameElement(),
oldParentNodeType.getQName(),
- mixins,
- session));
+ mixins, session));
NodeState newParent = (NodeState) changes.get(newParentId);
NodeTypeImpl newParentNodeType = getNodeType(newParent, session);
mixins = newParent.getMixinTypeNames();
events.add(EventState.childNodeAdded(newParentId,
- getParent(newPath),
- n.getNodeId(),
+ getParent(newPath), n.getNodeId(),
newPath.getNameElement(),
newParentNodeType.getQName(),
- mixins,
- session));
+ mixins, session));
+
+ events.add(EventState.nodeMoved(newParentId,
+ newPath, n.getNodeId(), oldPath,
+ newParentNodeType.getQName(), mixins,
+ session, false));
} else {
// a moved node always has a modified parent node
NodeState parent = null;
@@ -274,20 +275,20 @@
log.error(msg);
throw new ItemStateException(msg, e);
}
- events.add(EventState.childNodeRemoved(parent.getNodeId(),
- parentPath,
- n.getNodeId(),
- oldPath.getNameElement(),
- nodeType.getQName(),
- mixins,
- session));
- events.add(EventState.childNodeAdded(parent.getNodeId(),
- parentPath,
- n.getNodeId(),
- newPath.getNameElement(),
- nodeType.getQName(),
- mixins,
- session));
+ events.add(EventState.childNodeRemoved(
+ parent.getNodeId(), parentPath,
+ n.getNodeId(), oldPath.getNameElement(),
+ nodeType.getQName(), mixins, session));
+
+ events.add(EventState.childNodeAdded(
+ parent.getNodeId(), parentPath,
+ n.getNodeId(), newPath.getNameElement(),
+ nodeType.getQName(), mixins, session));
+
+ events.add(EventState.nodeMoved(
+ parent.getNodeId(), newPath, n.getNodeId(),
+ oldPath, nodeType.getQName(), mixins,
+ session, false));
}
}
}
@@ -302,34 +303,37 @@
// reorder
for (Iterator ro = reordered.iterator(); ro.hasNext();) {
ChildNodeEntry child = (ChildNodeEntry) ro.next();
- Name name = child.getName();
- int index = (child.getIndex() != 1) ? child.getIndex() : 0;
+ Path.Element addedElem = getPathElement(child);
Path parentPath = getPath(n.getNodeId(), hmgr);
- Path.Element addedElem = PathFactoryImpl.getInstance().createElement(name, index);
// get removed index
NodeState overlayed = (NodeState) n.getOverlayedState();
ChildNodeEntry entry = overlayed.getChildNodeEntry(child.getId());
if (entry == null) {
throw new ItemStateException("Unable to retrieve old child index for item: " + child.getId());
}
- int oldIndex = (entry.getIndex() != 1) ? entry.getIndex() : 0;
- Path.Element removedElem = PathFactoryImpl.getInstance().createElement(name, oldIndex);
+ Path.Element removedElem = getPathElement(entry);
events.add(EventState.childNodeRemoved(n.getNodeId(),
- parentPath,
- child.getId(),
- removedElem,
- nodeType.getQName(),
- mixins,
- session));
+ parentPath, child.getId(), removedElem,
+ nodeType.getQName(), mixins, session));
events.add(EventState.childNodeAdded(n.getNodeId(),
- parentPath,
- child.getId(),
- addedElem,
- nodeType.getQName(),
- mixins,
- session));
+ parentPath, child.getId(), addedElem,
+ nodeType.getQName(), mixins, session));
+
+ List cne = n.getChildNodeEntries();
+ // index of the child node entry before which this
+ // child node entry was reordered
+ int idx = cne.indexOf(child) + 1;
+ Path.Element beforeElem = null;
+ if (idx < cne.size()) {
+ beforeElem = getPathElement((ChildNodeEntry) cne.get(idx));
+ }
+
+ events.add(EventState.nodeReordered(n.getNodeId(),
+ parentPath, child.getId(), addedElem,
+ removedElem, beforeElem, nodeType.getQName(), mixins,
+ session, false));
}
}
@@ -342,11 +346,8 @@
NodeTypeImpl nodeType = getNodeType(parent, session);
Set mixins = parent.getMixinTypeNames();
events.add(EventState.propertyChanged(state.getParentId(),
- getParent(path),
- path.getNameElement(),
- nodeType.getQName(),
- mixins,
- session));
+ getParent(path), path.getNameElement(),
+ nodeType.getQName(), mixins, session));
}
}
@@ -753,6 +754,18 @@
}
/**
+ * Returns the path element for the given child node <code>entry</code>.
+ *
+ * @param entry a child node entry.
+ * @return the path element for the given entry.
+ */
+ private Path.Element getPathElement(ChildNodeEntry entry) {
+ Name name = entry.getName();
+ int index = (entry.getIndex() != 1) ? entry.getIndex() : 0;
+ return PathFactoryImpl.getInstance().createElement(name, index);
+ }
+
+ /**
* Get the longest common path of all event state paths.
*
* @return the longest common path
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/AbstractObservationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/AbstractObservationTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/AbstractObservationTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/AbstractObservationTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,119 @@
+/*
+ * 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.api.jsr283.observation;
+
+import java.util.Map;
+import java.util.Arrays;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+
+import org.apache.jackrabbit.test.api.observation.EventResult;
+import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
+
+/**
+ * <code>AbstractObservationTest</code> is a base class with utility methods
+ * for observation related tests.
+ */
+public abstract class AbstractObservationTest
+ extends org.apache.jackrabbit.test.api.observation.AbstractObservationTest {
+
+ /**
+ * TODO: remove when JSR 283 is final
+ */
+ protected static final int NODE_MOVED = org.apache.jackrabbit.api.jsr283.observation.Event.NODE_MOVED;
+
+ protected static final int ALL_TYPES = Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED | org.apache.jackrabbit.api.jsr283.observation.Event.NODE_MOVED;
+
+ protected void setUserData(String userData) throws RepositoryException {
+ // TODO: remove when JCR 2.0 is final
+ ((ObservationManagerImpl) obsMgr).setUserData(userData);
+ }
+
+ protected static String getUserData(Event e) throws RepositoryException {
+ // TODO: remove when JCR 2.0 is final
+ return ((org.apache.jackrabbit.api.jsr283.observation.Event) e).getUserData();
+ }
+
+ protected String getIdentifier(Node node) throws RepositoryException {
+ // TODO: remove when JSR 283 is final
+ return ((org.apache.jackrabbit.api.jsr283.Node) node).getIdentifier();
+ }
+
+ protected String getIdentifier(Event event) throws RepositoryException {
+ // TODO: remove when JSR 283 is final
+ return ((org.apache.jackrabbit.api.jsr283.observation.Event) event).getIdentifier();
+ }
+
+ protected Map getInfo(Event event) throws RepositoryException {
+ // TODO: remove when JSR 283 is final
+ return ((org.apache.jackrabbit.api.jsr283.observation.Event) event).getInfo();
+ }
+
+ protected long getDate(Event event) throws RepositoryException {
+ // TODO: remove when JSR 283 is final
+ return ((org.apache.jackrabbit.api.jsr283.observation.Event) event).getDate();
+ }
+
+ /**
+ * Returns the first event with the given <code>path</code>.
+ *
+ * @param events the events.
+ * @param path the path.
+ * @return the event with the given <code>path</code> or {@link #fail()}s if
+ * no such event exists.
+ * @throws RepositoryException if an error occurs while reading from the
+ * repository.
+ */
+ protected Event getEventByPath(Event[] events, String path)
+ throws RepositoryException {
+ for (int i = 0; i < events.length; i++) {
+ if (events[i].getPath().equals(path)) {
+ return events[i];
+ }
+ }
+ fail("no event with path: " + path + " in " + Arrays.asList(events));
+ return null;
+ }
+
+ /**
+ * Registers an event listener for the passed <code>eventTypes</code> and
+ * calls the callable.
+ *
+ * @param call the callable.
+ * @param eventTypes the types of the events to listen for.
+ * @return the events that were generated during execution of the callable.
+ * @throws RepositoryException if an error occurs.
+ */
+ protected Event[] getEvents(Callable call, int eventTypes)
+ throws RepositoryException {
+ EventResult result = new EventResult(log);
+ addEventListener(result, eventTypes);
+ call.call();
+ Event[] events = result.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(result);
+ return events;
+ }
+
+ /**
+ * Helper interface.
+ */
+ protected interface Callable {
+ public void call() throws RepositoryException;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/AbstractObservationTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/EventJournalTest.java (from r765154, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/EventJournalTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/EventJournalTest.java?p2=jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/EventJournalTest.java&p1=jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/EventJournalTest.java&r1=765154&r2=765328&rev=765328&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/observation/EventJournalTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/EventJournalTest.java Wed Apr 15 19:43:01 2009
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.core.observation;
+package org.apache.jackrabbit.api.jsr283.observation;
import java.util.Set;
import java.util.HashSet;
@@ -26,7 +26,6 @@
import javax.jcr.observation.Event;
import org.apache.jackrabbit.core.WorkspaceImpl;
-import org.apache.jackrabbit.api.jsr283.observation.EventJournal;
/**
* <code>EventJournalTest</code> performs EventJournal tests.
@@ -178,7 +177,7 @@
public void testUserData() throws RepositoryException {
testRootNode.addNode(nodeName1);
String data = createRandomString(5);
- getObservationManager().setUserData(data);
+ setUserData(data);
journal = getEventJournal(ALL_TYPES, testRoot, true, null, null);
journal.skipTo(System.currentTimeMillis());
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/EventJournalTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetDateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetDateTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetDateTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetDateTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,59 @@
+/*
+ * 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.api.jsr283.observation;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Collections;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+
+/**
+ * <code>GetDateTest</code> checks if the dates returned by events are
+ * monotonically increasing.
+ */
+public class GetDateTest extends AbstractObservationTest {
+
+ public void testLinearTime() throws RepositoryException {
+ List names = Arrays.asList(new String[]{nodeName1, nodeName2, nodeName3});
+ List dates = new ArrayList();
+ for (Iterator it = names.iterator(); it.hasNext(); ) {
+ final String name = (String) it.next();
+ Event[] events = getEvents(new Callable() {
+ public void call() throws RepositoryException {
+ testRootNode.addNode(name, testNodeType);
+ testRootNode.save();
+ }
+ }, Event.NODE_ADDED);
+ for (int i = 0; i < events.length; i++) {
+ dates.add(new Long(getDate(events[i])));
+ }
+ try {
+ // wait for a moment
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ List sortedDates = new ArrayList(dates);
+ Collections.sort(sortedDates);
+ assertEquals(sortedDates, dates);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetDateTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetIdentifierTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetIdentifierTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetIdentifierTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetIdentifierTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,106 @@
+/*
+ * 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.api.jsr283.observation;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.observation.Event;
+
+/**
+ * <code>IdentifierTest</code> checks if the identifier of an event is correct.
+ */
+public class GetIdentifierTest extends AbstractObservationTest {
+
+ public void testNodeAdded() throws RepositoryException {
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.save();
+ }
+ }, Event.NODE_ADDED);
+ Node n = testRootNode.getNode(nodeName1);
+ assertEquals(getIdentifier(n), getIdentifier(getEventByPath(events, n.getPath())));
+ }
+
+ public void testNodeMoved() throws RepositoryException {
+ final Node n = testRootNode.addNode(nodeName1, testNodeType);
+ String id = getIdentifier(n);
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ superuser.getWorkspace().move(n.getPath(), testRoot + "/" + nodeName2);
+ }
+ }, NODE_MOVED);
+ String path = testRootNode.getNode(nodeName2).getPath();
+ assertEquals(id, getIdentifier(getEventByPath(events, path)));
+ }
+
+ public void testNodeRemoved() throws RepositoryException {
+ final Node n = testRootNode.addNode(nodeName1, testNodeType);
+ String path = n.getPath();
+ String id = getIdentifier(n);
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ n.remove();
+ testRootNode.save();
+ }
+ }, Event.NODE_REMOVED);
+ assertEquals(id, getIdentifier(getEventByPath(events, path)));
+ }
+
+ public void testPropertyAdded() throws RepositoryException {
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ testRootNode.addNode(nodeName1, testNodeType).setProperty(propertyName1, "test");
+ testRootNode.save();
+ }
+ }, Event.PROPERTY_ADDED);
+ Node n = testRootNode.getNode(nodeName1);
+ Property prop = n.getProperty(propertyName1);
+ assertEquals(getIdentifier(n), getIdentifier(getEventByPath(events, prop.getPath())));
+ }
+
+ public void testPropertyChanged() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ final Property prop = n.setProperty(propertyName1, "test");
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ prop.setValue("modified");
+ testRootNode.save();
+ }
+ }, Event.PROPERTY_CHANGED);
+ assertEquals(getIdentifier(n), getIdentifier(getEventByPath(events, prop.getPath())));
+ }
+
+ public void testPropertyRemoved() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ String id = getIdentifier(n);
+ final Property prop = n.setProperty(propertyName1, "test");
+ String propPath = prop.getPath();
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ prop.remove();
+ testRootNode.save();
+ }
+ }, Event.PROPERTY_REMOVED);
+ assertEquals(id, getIdentifier(getEventByPath(events, propPath)));
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetIdentifierTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetInfoTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetInfoTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetInfoTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetInfoTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,97 @@
+/*
+ * 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.api.jsr283.observation;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.observation.Event;
+
+/**
+ * <code>GetInfoTest</code> checks that the info map is empty for event types:
+ * {@link Event#NODE_ADDED}, {@link Event#NODE_REMOVED},
+ * {@link Event#PROPERTY_ADDED}, {@link Event#PROPERTY_CHANGED} and
+ * {@link Event#PROPERTY_REMOVED}.
+ */
+public class GetInfoTest extends AbstractObservationTest {
+
+ public void testNodeAdded() throws RepositoryException {
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.save();
+ }
+ }, Event.NODE_ADDED);
+ for (int i = 0; i < events.length; i++) {
+ assertEquals("info map must be empty", 0, getInfo(events[i]).size());
+ }
+ }
+
+ public void testNodeRemoved() throws RepositoryException {
+ final Node n = testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ n.remove();
+ testRootNode.save();
+ }
+ }, Event.NODE_REMOVED);
+ for (int i = 0; i < events.length; i++) {
+ assertEquals("info map must be empty", 0, getInfo(events[i]).size());
+ }
+ }
+
+ public void testPropertyAdded() throws RepositoryException {
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ testRootNode.addNode(nodeName1, testNodeType).setProperty(propertyName1, "test");
+ testRootNode.save();
+ }
+ }, Event.PROPERTY_ADDED);
+ for (int i = 0; i < events.length; i++) {
+ assertEquals("info map must be empty", 0, getInfo(events[i]).size());
+ }
+ }
+
+ public void testPropertyChanged() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ final Property prop = n.setProperty(propertyName1, "test");
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ prop.setValue("modified");
+ }
+ }, Event.PROPERTY_CHANGED);
+ for (int i = 0; i < events.length; i++) {
+ assertEquals("info map must be empty", 0, getInfo(events[i]).size());
+ }
+ }
+
+ public void testPropertyRemoved() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ final Property prop = n.setProperty(propertyName1, "test");
+ testRootNode.save();
+ Event[] events = getEvents(new Callable(){
+ public void call() throws RepositoryException {
+ prop.remove();
+ }
+ }, Event.PROPERTY_REMOVED);
+ for (int i = 0; i < events.length; i++) {
+ assertEquals("info map must be empty", 0, getInfo(events[i]).size());
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetInfoTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetUserDataTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetUserDataTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetUserDataTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetUserDataTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,85 @@
+/*
+ * 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.api.jsr283.observation;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.observation.Event;
+
+import org.apache.jackrabbit.test.NotExecutableException;
+
+/**
+ * <code>GetUserDataTest</code> performs observation tests with user data set
+ * on the observation manager.
+ */
+public class GetUserDataTest extends AbstractObservationTest {
+
+ public void testSave() throws RepositoryException {
+ runWithUserData(new Callable() {
+ public void call() throws RepositoryException {
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.save();
+ }
+ }, ALL_TYPES);
+ }
+
+ public void testWorkspaceOperation() throws RepositoryException {
+ testRootNode.addNode(nodeName1);
+ testRootNode.save();
+
+ runWithUserData(new Callable() {
+ public void call() throws RepositoryException {
+ String src = testRoot + "/" + nodeName1;
+ String dest = testRoot + "/" + nodeName2;
+ superuser.getWorkspace().move(src, dest);
+ }
+ }, ALL_TYPES);
+ }
+
+ public void testVersioning()
+ throws RepositoryException, NotExecutableException {
+ checkSupportedOption(Repository.OPTION_VERSIONING_SUPPORTED);
+
+ final Node n1 = testRootNode.addNode(nodeName1);
+ n1.addMixin(mixVersionable);
+ testRootNode.save();
+
+ runWithUserData(new Callable() {
+ public void call() throws RepositoryException {
+ n1.checkin();
+ }
+ }, Event.NODE_ADDED); // get events for added version node
+ }
+
+ protected void runWithUserData(final Callable c, int eventTypes)
+ throws RepositoryException {
+ final String data = createRandomString(5);
+ Event[] events = getEvents(new Callable() {
+ public void call() throws RepositoryException {
+ setUserData(data);
+ c.call();
+ }
+ }, eventTypes);
+
+ assertTrue("no events returned", events.length > 0);
+ for (int i = 0; i < events.length; i++) {
+ assertEquals("Wrong user data", data, getUserData(events[i]));
+ }
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/GetUserDataTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeMovedTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeMovedTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeMovedTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeMovedTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,212 @@
+/*
+ * 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.api.jsr283.observation;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.observation.Event;
+
+import org.apache.jackrabbit.test.api.observation.EventResult;
+
+/**
+ * TODO: sync with NodeMovedTest in jackrabbit-jcr-tests once JSR 283 is final.
+ *
+ * Tests if {@link javax.jcr.Session#move} operations trigger the appropriate
+ * observation events.
+ * <p/>
+ * Configuration requirements are:<br/>
+ * The {@link #testRoot} must allow child nodes of type {@link #testNodeType}.
+ * The child nodes that are created will be named {@link #nodeName1},
+ * {@link #nodeName2}, {@link #nodeName3} and {@link #nodeName4}. Furthermore
+ * {@link #testNodeType} must allow to add child nodes of the same type
+ * ({@link #testNodeType}).
+ *
+ * @test
+ * @sources NodeMovedTest.java
+ * @executeClass org.apache.jackrabbit.test.api.observation.NodeMovedTest
+ * @keywords observation
+ */
+public class NodeMovedTest extends AbstractObservationTest {
+
+ /**
+ * The key <code>srcAbsPath</code> in the info map.
+ */
+ private static final String SRC_ABS_PATH = "srcAbsPath";
+
+ /**
+ * The key <code>destAbsPath</code> in the info map.
+ */
+ private static final String DEST_ABS_PATH = "destAbsPath";
+
+ /**
+ * Tests if node removed and node added event is triggered when a tree
+ * is moved.
+ */
+ public void testMoveTree() throws RepositoryException {
+ /**
+ * Initial tree:
+ * + testroot
+ * + nodename1
+ * + nodename2
+ *
+ * After move:
+ * + testroot
+ * + nodename3
+ * + nodename2
+ */
+
+ Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+ n1.addNode(nodeName2, testNodeType);
+ testRootNode.save();
+ EventResult addNodeListener = new EventResult(log);
+ EventResult removeNodeListener = new EventResult(log);
+ EventResult moveNodeListener = new EventResult(log);
+ addEventListener(addNodeListener, Event.NODE_ADDED);
+ addEventListener(removeNodeListener, Event.NODE_REMOVED);
+ addEventListener(moveNodeListener, NODE_MOVED);
+ superuser.move(n1.getPath(), testRoot + "/" + nodeName3);
+ testRootNode.save();
+ Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] moved = moveNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(addNodeListener);
+ removeEventListener(removeNodeListener);
+ removeEventListener(moveNodeListener);
+ checkNodeAdded(added, new String[]{nodeName3}, new String[]{nodeName3 + "/" + nodeName2});
+ checkNodeRemoved(removed, new String[]{nodeName1}, new String[]{nodeName1 + "/" + nodeName2});
+ checkNodeMoved(moved, nodeName1, nodeName3);
+ }
+
+ /**
+ * Tests if node removed and node added event is triggered when a node
+ * is moved.
+ */
+ public void testMoveNode() throws RepositoryException {
+ /**
+ * Initial tree:
+ * + testroot
+ * + nodename1
+ * + nodename2
+ *
+ * After move:
+ * + testroot
+ * + nodename1
+ * + nodename2
+ */
+
+ Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+ Node n2 = n1.addNode(nodeName2, testNodeType);
+ testRootNode.save();
+ EventResult addNodeListener = new EventResult(log);
+ EventResult removeNodeListener = new EventResult(log);
+ EventResult moveNodeListener = new EventResult(log);
+ addEventListener(addNodeListener, Event.NODE_ADDED);
+ addEventListener(removeNodeListener, Event.NODE_REMOVED);
+ addEventListener(moveNodeListener, NODE_MOVED);
+ superuser.move(n2.getPath(), testRoot + "/" + nodeName2);
+ testRootNode.save();
+ Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] moved = moveNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(addNodeListener);
+ removeEventListener(removeNodeListener);
+ removeEventListener(moveNodeListener);
+ checkNodeAdded(added, new String[]{nodeName2}, null);
+ checkNodeRemoved(removed, new String[]{nodeName1 + "/" + nodeName2}, null);
+ checkNodeMoved(moved, nodeName1 + "/" + nodeName2, nodeName2);
+ }
+
+ /**
+ * Tests if a node moved triggers the correct events when the former parent
+ * node is removed at the same time.
+ */
+ public void testMoveWithRemove() throws RepositoryException {
+ /**
+ * Initial tree:
+ * + testroot
+ * + nodename1
+ * + nodename2
+ * + nodename3
+ *
+ * After move and remove:
+ * + testroot
+ * + nodename3
+ * + nodename2
+ */
+ Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+ Node n2 = n1.addNode(nodeName2, testNodeType);
+ Node n3 = testRootNode.addNode(nodeName3, testNodeType);
+ testRootNode.save();
+ EventResult addNodeListener = new EventResult(log);
+ EventResult removeNodeListener = new EventResult(log);
+ EventResult moveNodeListener = new EventResult(log);
+ addEventListener(addNodeListener, Event.NODE_ADDED);
+ addEventListener(removeNodeListener, Event.NODE_REMOVED);
+ addEventListener(moveNodeListener, NODE_MOVED);
+ // move n2
+ superuser.move(n2.getPath(), n3.getPath() + "/" + nodeName2);
+ // remove n1
+ n1.remove();
+ testRootNode.save();
+ Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] moved = moveNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(addNodeListener);
+ removeEventListener(removeNodeListener);
+ removeEventListener(moveNodeListener);
+ checkNodeAdded(added, new String[]{nodeName3 + "/" + nodeName2}, null);
+ checkNodeRemoved(removed, new String[]{nodeName1 + "/" + nodeName2, nodeName1}, null);
+ checkNodeMoved(moved, nodeName1 + "/" + nodeName2, nodeName3 + "/" + nodeName2);
+ }
+
+ /**
+ * TODO: move to base class once JSR 283 is final
+ * Checks <code>Events</code> for paths. All <code>relPaths</code> are
+ * relative to {@link #testRoot}.
+ *
+ * @param events the <code>Event</code>s.
+ * @param from the source path where the node was moved from.
+ * @param to the destination path where the node was moved to.
+ * @throws RepositoryException if an error occurs while retrieving the nodes
+ * from event instances.
+ */
+ protected void checkNodeMoved(Event[] events, String from, String to)
+ throws RepositoryException {
+ checkNodes(events, new String[]{to}, null, NODE_MOVED);
+ assertEquals("Wrong number of events", 1, events.length);
+ Map info = getInfo(events[0]);
+ checkInfoEntry(info, SRC_ABS_PATH, testRoot + "/" + from);
+ checkInfoEntry(info, DEST_ABS_PATH, testRoot + "/" + to);
+ }
+
+ /**
+ * TODO: move to base class once JSR 283 is final
+ * Checks if the info map contains the given <code>key</code> with the
+ * <code>expected</code> value.
+ *
+ * @param info the event info map.
+ * @param key the name of the key.
+ * @param expected the expected value.
+ */
+ protected void checkInfoEntry(Map info, String key, String expected) {
+ String value = (String) info.get(key);
+ assertNotNull("Missing event info key: " + key, value);
+ assertEquals("Wrong event info value for: " + key, expected, value);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeMovedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeReorderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeReorderTest.java?rev=765328&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeReorderTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeReorderTest.java Wed Apr 15 19:43:01 2009
@@ -0,0 +1,318 @@
+/*
+ * 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.api.jsr283.observation;
+
+import java.util.Map;
+
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.test.api.observation.EventResult;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.observation.Event;
+
+/**
+ * TODO: sync with NodeReorderTest in jackrabbit-jcr-tests once JSR 283 is final.
+ *
+ * Tests if {@link javax.jcr.Node#orderBefore(String, String)} operations trigger
+ * the appropriate observation events.
+ * <p/>
+ * @tck.config testroot must allow orderable child nodes of type
+ * <code>nodetype</code>, otherwise the test cases throw a
+ * {@link NotExecutableException}. Some tests are only executed if the node
+ * at <code>testroot</code> support same name sibling child nodes.
+ * @tck.config nodetype node type that allows child nodes of the same type.
+ * @tck.config nodename1 child node name of type <code>nodetype</code>
+ * @tck.config nodename2 child node name of type <code>nodetype</code>
+ * @tck.config nodename3 child node name of type <code>nodetype</code>
+ *
+ * @test
+ * @sources NodeReorderTest.java
+ * @executeClass org.apache.jackrabbit.test.api.observation.NodeReorderTest
+ * @keywords observation
+ */
+public class NodeReorderTest extends AbstractObservationTest {
+
+ /**
+ * The key <code>srcChildRelPath</code> in the info map.
+ */
+ private static final String SRC_CHILD_REL_PATH = "srcChildRelPath";
+
+ /**
+ * The key <code>destChildRelPath</code> in the info map.
+ */
+ private static final String DEST_CHILD_REL_PATH = "destChildRelPath";
+
+ /**
+ * Tests if reordering a child node triggers a {@link Event#NODE_REMOVED}
+ * and a {@link Event#NODE_ADDED} event.
+ */
+ public void testNodeReorder()
+ throws RepositoryException, NotExecutableException {
+ if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+ throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+ }
+
+ /**
+ * Initial tree:
+ * + testroot
+ * + nodename1
+ * + nodename2
+ * + nodename3
+ *
+ * After reorder:
+ * + testroot
+ * + nodename1
+ * + nodename3
+ * + nodename2
+ */
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.addNode(nodeName2, testNodeType);
+ testRootNode.addNode(nodeName3, testNodeType);
+ testRootNode.save();
+ EventResult addNodeListener = new EventResult(log);
+ EventResult removeNodeListener = new EventResult(log);
+ EventResult moveNodeListener = new EventResult(log);
+ addEventListener(addNodeListener, Event.NODE_ADDED);
+ addEventListener(removeNodeListener, Event.NODE_REMOVED);
+ addEventListener(moveNodeListener, NODE_MOVED);
+ testRootNode.orderBefore(nodeName3, nodeName2);
+ testRootNode.save();
+ Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] moved = moveNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(addNodeListener);
+ removeEventListener(removeNodeListener);
+ removeEventListener(moveNodeListener);
+ // either
+ // 1) nodename2 has been reordered to the end
+ // or:
+ // 2) nodename3 has been reordered before nodename2
+ // that is, the following event sets are correct:
+ // 1) nodename2:remove, nodename2:add
+ // or:
+ // 2) nodename3:remove, nodename3:add
+
+ // if true, check for option 1)
+ boolean reorderEnd = false;
+ for (int i = 0; i < added.length; i++) {
+ if (added[i].getPath().endsWith(nodeName2)) {
+ reorderEnd = true;
+ break;
+ }
+ }
+ if (reorderEnd) {
+ checkNodeAdded(added, new String[]{nodeName2}, null);
+ checkNodeRemoved(removed, new String[]{nodeName2}, null);
+ checkNodeReordered(moved, nodeName2, nodeName2, null);
+ } else {
+ checkNodeAdded(added, new String[]{nodeName3}, null);
+ checkNodeRemoved(removed, new String[]{nodeName3}, null);
+ checkNodeReordered(moved, nodeName3, nodeName3, nodeName2);
+ }
+ }
+
+ /**
+ * Tests if reordering a child node triggers a {@link Event#NODE_REMOVED}
+ * and a {@link Event#NODE_ADDED} event with same name siblings.
+ */
+ public void testNodeReorderSameName()
+ throws RepositoryException, NotExecutableException {
+ if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+ throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+ }
+
+ /**
+ * Initial tree:
+ * + testroot
+ * + nodename1[1]
+ * + nodename1[2]
+ * + nodename1[3]
+ *
+ * After reorder:
+ * + testroot
+ * + nodename1[1]
+ * + nodename1[2] (was 3)
+ * + nodename1[3] (was 2)
+ */
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ if (!n.getDefinition().allowsSameNameSiblings()) {
+ throw new NotExecutableException("Node at " + testRoot + " does not allow same name siblings with name " + nodeName1);
+ }
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.save();
+ EventResult addNodeListener = new EventResult(log);
+ EventResult removeNodeListener = new EventResult(log);
+ EventResult moveNodeListener = new EventResult(log);
+ addEventListener(addNodeListener, Event.NODE_ADDED);
+ addEventListener(removeNodeListener, Event.NODE_REMOVED);
+ addEventListener(moveNodeListener, NODE_MOVED);
+ testRootNode.orderBefore(nodeName1 + "[3]", nodeName1 + "[2]");
+ //testRootNode.orderBefore(nodeName1 + "[2]", null);
+ testRootNode.save();
+ Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] moved = moveNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(addNodeListener);
+ removeEventListener(removeNodeListener);
+ removeEventListener(moveNodeListener);
+ // either
+ // 1) nodename1[2] has been reordered to the end
+ // or:
+ // 2) nodename1[3] has been reordered before nodename1[2]
+ // that is, the following event sets are correct:
+ // 1) nodename1[2]:remove, nodename1[3]:add
+ // or:
+ // 2) nodename1[3]:remove, nodename1[2]:add
+
+ // if true, check for option 1)
+ boolean reorderEnd = false;
+ for (int i = 0; i < added.length; i++) {
+ if (added[i].getPath().endsWith(nodeName1 + "[3]")) {
+ reorderEnd = true;
+ break;
+ }
+ }
+ if (reorderEnd) {
+ checkNodeAdded(added, new String[]{nodeName1 + "[3]"}, null);
+ checkNodeRemoved(removed, new String[]{nodeName1 + "[2]"}, null);
+ checkNodeReordered(moved, nodeName1 + "[2]", nodeName1 + "[3]", null);
+ } else {
+ checkNodeAdded(added, new String[]{nodeName1 + "[2]"}, null);
+ checkNodeRemoved(removed, new String[]{nodeName1 + "[3]"}, null);
+ checkNodeReordered(moved, nodeName1 + "[3]", nodeName1 + "[2]", nodeName1 + "[2]");
+ }
+ }
+
+ /**
+ * Tests if reordering a child node triggers a {@link Event#NODE_REMOVED}
+ * and a {@link Event#NODE_ADDED} event with same name siblings. Furthermore
+ * a node is removed in the same save scope.
+ */
+ public void testNodeReorderSameNameWithRemove()
+ throws RepositoryException, NotExecutableException {
+ if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+ throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+ }
+
+ /**
+ * Initial tree:
+ * + testroot
+ * + nodename1[1]
+ * + nodename2
+ * + nodename1[2]
+ * + nodename1[3]
+ * + nodename3
+ *
+ * After reorder:
+ * + testroot
+ * + nodename1[1]
+ * + nodename2
+ * + nodename1[2] (was 3)
+ * + nodename1[3] (was 2)
+ */
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ if (!n.getDefinition().allowsSameNameSiblings()) {
+ throw new NotExecutableException("Node at " + testRoot + " does not allow same name siblings with name " + nodeName1);
+ }
+ testRootNode.addNode(nodeName2, testNodeType);
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.addNode(nodeName1, testNodeType);
+ testRootNode.addNode(nodeName3, testNodeType);
+ testRootNode.save();
+ EventResult addNodeListener = new EventResult(log);
+ EventResult removeNodeListener = new EventResult(log);
+ EventResult moveNodeListener = new EventResult(log);
+ addEventListener(addNodeListener, Event.NODE_ADDED);
+ addEventListener(removeNodeListener, Event.NODE_REMOVED);
+ addEventListener(moveNodeListener, NODE_MOVED);
+ testRootNode.orderBefore(nodeName1 + "[2]", null);
+ testRootNode.getNode(nodeName3).remove();
+ testRootNode.save();
+ Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ Event[] moved = moveNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+ removeEventListener(addNodeListener);
+ removeEventListener(removeNodeListener);
+ removeEventListener(moveNodeListener);
+ // either
+ // 1) nodename1[2] has been reordered to the end
+ // or:
+ // 2) nodename1[3] has been reordered before nodename1[2]
+ //
+ // that is, the following event sets are correct:
+ // 1) nodename1[2]:remove, nodename1[3]:add, nodename3:remove
+ // or:
+ // 2) nodename1[3]:remove, nodename1[2]:add, nodename3:remove
+
+ // if true, check for option 1)
+ boolean reorderEnd = false;
+ for (int i = 0; i < added.length; i++) {
+ if (added[i].getPath().endsWith(nodeName1 + "[3]")) {
+ reorderEnd = true;
+ break;
+ }
+ }
+ if (reorderEnd) {
+ checkNodeAdded(added, new String[]{nodeName1 + "[3]"}, null);
+ checkNodeRemoved(removed, new String[]{nodeName1 + "[2]", nodeName3}, null);
+ checkNodeReordered(moved, nodeName1 + "[2]", nodeName1 + "[3]", null);
+ } else {
+ checkNodeAdded(added, new String[]{nodeName1 + "[2]"}, null);
+ checkNodeRemoved(removed, new String[]{nodeName1 + "[3]", nodeName3}, null);
+ checkNodeReordered(moved, nodeName1 + "[3]", nodeName1 + "[2]", nodeName1 + "[2]");
+ }
+ }
+
+ /**
+ * TODO: move to base class once JSR 283 is final
+ * Checks <code>Events</code> for paths. All <code>relPaths</code> are
+ * relative to {@link #testRoot}.
+ *
+ * @param events the <code>Event</code>s.
+ * @param src the source child path where the node was reordered from.
+ * @param dest the destination child path where the node was reordered to.
+ * @param before the destination child path where the node was reordered before.
+ * @throws RepositoryException if an error occurs while retrieving the nodes
+ * from event instances.
+ */
+ protected void checkNodeReordered(Event[] events, String src,
+ String dest, String before)
+ throws RepositoryException {
+ checkNodes(events, new String[]{dest}, null, NODE_MOVED);
+ assertEquals("Wrong number of events", 1, events.length);
+ Map info = getInfo(events[0]);
+ checkInfoEntry(info, SRC_CHILD_REL_PATH, src);
+ checkInfoEntry(info, DEST_CHILD_REL_PATH, before);
+ }
+
+ /**
+ * TODO: move to base class once JSR 283 is final
+ * Checks if the info map contains the given <code>key</code> with the
+ * <code>expected</code> value.
+ *
+ * @param info the event info map.
+ * @param key the name of the key.
+ * @param expected the expected value.
+ */
+ protected void checkInfoEntry(Map info, String key, String expected) {
+ assertTrue("Missing event info key: " + key, info.containsKey(key));
+ assertEquals("Wrong event info value for: " + key,
+ expected, (String) info.get(key));
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/observation/NodeReorderTest.java
------------------------------------------------------------------------------
svn:eol-style = native