Index: src/test/java/org/apache/jackrabbit/core/NodeImplTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/core/NodeImplTest.java (Revision 800328)
+++ src/test/java/org/apache/jackrabbit/core/NodeImplTest.java (Arbeitskopie)
@@ -18,14 +18,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.uuid.UUID;
import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicyIterator;
import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
import org.apache.jackrabbit.api.jsr283.security.Privilege;
import org.apache.jackrabbit.core.security.authorization.JackrabbitAccessControlList;
+import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.RepositoryException;
@@ -125,4 +128,31 @@
changeReadPermission(principal, n, true);
}
}
+
+ public void testAddNodeUuid() throws RepositoryException, NotExecutableException {
+ String uuid = "f81d4fae-7dec-11d0-a765-00a0c91e6bf6";
+ Node n = testRootNode.addNode(nodeName1);
+ Node testNode = ((NodeImpl) n).addNodeWithUuid(nodeName2, uuid);
+ testNode.addMixin(JcrConstants.MIX_REFERENCEABLE);
+ testRootNode.save();
+ assertEquals("Node UUID should be: "+uuid, uuid, testNode.getUUID());
+ }
+
+ public void testAddNodeUuidCollision() throws RepositoryException, NotExecutableException {
+ String uuid = "f81d4fae-7dec-11d0-a765-00a0c91e6bf6";
+ Node n = testRootNode.addNode(nodeName1);
+ Node testNode1 = ((NodeImpl) n).addNodeWithUuid(nodeName2, uuid);
+ testNode1.addMixin(JcrConstants.MIX_REFERENCEABLE);
+ testRootNode.save();
+ boolean collisionDetected = false;
+
+ try {
+ Node testNode2 = ((NodeImpl) n).addNodeWithUuid(nodeName2, uuid);
+ testNode1.addMixin(JcrConstants.MIX_REFERENCEABLE);
+ testRootNode.save();
+ } catch (ItemExistsException iee) {
+ collisionDetected = true;
+ }
+ assertTrue("Node collision detected: "+uuid, collisionDetected);
+ }
}
\ No newline at end of file
Index: src/main/java/org/apache/jackrabbit/core/NodeImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/NodeImpl.java (Revision 800328)
+++ src/main/java/org/apache/jackrabbit/core/NodeImpl.java (Arbeitskopie)
@@ -2129,30 +2129,75 @@
* {@inheritDoc}
*/
public synchronized Node addNode(String relPath)
- throws ItemExistsException, PathNotFoundException, VersionException,
- ConstraintViolationException, LockException, RepositoryException {
- // check state of this instance
- sanityCheck();
+ throws RepositoryException {
+ return addNodeWithUuid(relPath, null, null);
+ }
- return internalAddNode(relPath, null);
+ /**
+ * Same as {@link Node#addNode(String)} except
+ * this method takes an additional uuid argument.
+ * Important Notice: Use this method with caution!
+ * @param relPath path of the new node
+ * @param uuid uuid of the new node or null
+ * @return the newly added node
+ * @throws RepositoryException if the node can not be added
+ */
+ public synchronized Node addNodeWithUuid(String relPath, String uuid)
+ throws RepositoryException {
+ return addNodeWithUuid(relPath, null, uuid);
}
/**
* {@inheritDoc}
*/
public synchronized Node addNode(String relPath, String nodeTypeName)
- throws ItemExistsException, PathNotFoundException,
- NoSuchNodeTypeException, VersionException,
- ConstraintViolationException, LockException, RepositoryException {
+ throws RepositoryException {
+ return addNodeWithUuid(relPath, nodeTypeName, null);
+ }
+
+ /**
+ * Same as {@link Node#addNode(String, String)} except
+ * this method takes an additional uuid argument.
+ * Important Notice: Use this method with caution!
+ * @param relPath path of the new node
+ * @param nodeTypeName name of the new node's node type or null
+ * if it should be determined automatically
+ * @param uuid uuid of the new node or null
+ * @return the newly added node
+ * @throws RepositoryException if the node can not be added
+ */
+ public synchronized Node addNodeWithUuid(
+ String relPath, String nodeTypeName, String uuid)
+ throws RepositoryException {
// check state of this instance
sanityCheck();
- NodeTypeImpl nt = (NodeTypeImpl) session.getNodeTypeManager().getNodeType(nodeTypeName);
- if (nt.isMixin()) {
- throw new RepositoryException(nodeTypeName + ": not a primary node type");
+ NodeId id = null;
+ if (uuid != null) {
+ //if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ // throw new UnsupportedRepositoryOperationException();
+ //}
+ // Test for existing UUID
+ // @see SessionImporter.startNode(NodeInfo nodeInfo, List propInfos)
+ try {
+ session.getNodeByUUID(uuid);
+ throw new ItemExistsException(
+ "A node with this UUID already exists: " + uuid);
+ } catch (ItemNotFoundException infe) {
+ id = new NodeId(new UUID(uuid));
+ }
}
- return internalAddNode(relPath, nt);
+ NodeType nt = null;
+ if (nodeTypeName != null) {
+ nt = session.getNodeTypeManager().getNodeType(nodeTypeName);
+ if (nt.isMixin()) {
+ throw new RepositoryException(
+ "Not a primary node type: " + nodeTypeName);
+ }
+ }
+
+ return internalAddNode(relPath, (NodeTypeImpl) nt, id);
}
/**
@@ -3297,9 +3342,11 @@
/**
* {@inheritDoc}
*/
- public Version checkin()
- throws VersionException, UnsupportedRepositoryOperationException,
- InvalidItemStateException, LockException, RepositoryException {
+ public Version checkin() throws RepositoryException {
+ return checkin(null);
+ }
+
+ public Version checkin(Calendar cal) throws RepositoryException {
// check state of this instance
sanityCheck();
@@ -3317,7 +3364,7 @@
int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_PENDING_CHANGES_ON_NODE;
session.getValidator().checkModify(this, options, Permission.VERSION_MNGMT);
- Version v = session.getVersionManager().checkin(this);
+ Version v = session.getVersionManager().checkin(this, cal);
boolean success = false;
try {
internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(false));
@@ -4291,7 +4338,7 @@
} else {
// with simple versioning, the node is checked in automatically,
// thus not allowing any branches
- session.getVersionManager().checkin(this);
+ session.getVersionManager().checkin(this, null);
}
// 3. N's jcr:isCheckedOut property is set to false.
internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(false));
Index: src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java (Revision 800328)
+++ src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java (Arbeitskopie)
@@ -53,6 +53,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -276,7 +277,7 @@
* This method must not be synchronized since it could cause deadlocks with
* item-reading listeners in the observation thread.
*/
- public Version checkin(final NodeImpl node) throws RepositoryException {
+ public Version checkin(final NodeImpl node, final Calendar cal) throws RepositoryException {
InternalVersion version = (InternalVersion)
escFactory.doSourced((SessionImpl) node.getSession(), new SourcedTarget() {
public Object run() throws RepositoryException {
@@ -286,11 +287,11 @@
// the property
String histUUID = node.getProperty(NameConstants.JCR_VERSIONHISTORY).getString();
vh = getVersionHistory(NodeId.valueOf(histUUID));
- return checkin((InternalVersionHistoryImpl) vh, node, false);
+ return checkin((InternalVersionHistoryImpl) vh, node, false, cal);
} else {
// in simple versioning the history id needs to be calculated
vh = getVersionHistoryOfNode(node.getNodeId());
- return checkin((InternalVersionHistoryImpl) vh, node, true);
+ return checkin((InternalVersionHistoryImpl) vh, node, true, cal);
}
}
});
Index: src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java (Revision 800328)
+++ src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java (Arbeitskopie)
@@ -16,6 +16,8 @@
*/
package org.apache.jackrabbit.core.version;
+import java.util.Calendar;
+
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -424,17 +426,19 @@
* @param history the version history
* @param node node to checkin
* @param simple flag indicates simple versioning
+ * @param cal create time of the new version, or null
* @return internal version
* @throws javax.jcr.RepositoryException if an error occurs
* @see javax.jcr.Node#checkin()
*/
protected InternalVersion checkin(InternalVersionHistoryImpl history,
- NodeImpl node, boolean simple)
+ NodeImpl node, boolean simple, Calendar cal)
throws RepositoryException {
WriteOperation operation = startWriteOperation();
try {
String versionName = calculateCheckinVersionName(history, node, simple);
- InternalVersionImpl v = history.checkin(NameFactoryImpl.getInstance().create("", versionName), node);
+ InternalVersionImpl v = history.checkin(
+ NameFactoryImpl.getInstance().create("", versionName), node, cal);
operation.save();
return v;
} catch (ItemStateException e) {
Index: src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java (Revision 800328)
+++ src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java (Arbeitskopie)
@@ -16,6 +16,7 @@
*/
package org.apache.jackrabbit.core.version;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -159,7 +160,7 @@
/**
* {@inheritDoc}
*/
- public Version checkin(NodeImpl node) throws RepositoryException {
+ public Version checkin(NodeImpl node, Calendar cal) throws RepositoryException {
if (isInXA()) {
InternalVersionHistory vh;
InternalVersion version;
@@ -168,15 +169,15 @@
// the property
String histUUID = node.getProperty(NameConstants.JCR_VERSIONHISTORY).getString();
vh = getVersionHistory(NodeId.valueOf(histUUID));
- version = checkin((InternalVersionHistoryImpl) vh, node, false);
+ version = checkin((InternalVersionHistoryImpl) vh, node, false, cal);
} else {
// in simple versioning the history id needs to be calculated
vh = getVersionHistoryOfNode(node.getNodeId());
- version = checkin((InternalVersionHistoryImpl) vh, node, true);
+ version = checkin((InternalVersionHistoryImpl) vh, node, true, cal);
}
return (Version) ((SessionImpl) node.getSession()).getNodeById(version.getId());
}
- return vMgr.checkin(node);
+ return vMgr.checkin(node, cal);
}
/**
@@ -394,14 +395,14 @@
* Before modifying version history given, make a local copy of it.
*/
protected InternalVersion checkin(InternalVersionHistoryImpl history,
- NodeImpl node, boolean simple)
+ NodeImpl node, boolean simple, Calendar cal)
throws RepositoryException {
if (history.getVersionManager() != this) {
history = makeLocalCopy(history);
xaItems.put(history.getId(), history);
}
- InternalVersion version = super.checkin(history, node, simple);
+ InternalVersion version = super.checkin(history, node, simple, cal);
NodeId frozenNodeId = version.getFrozenNodeId();
InternalVersionItem frozenNode = createInternalVersionItem(frozenNodeId);
if (frozenNode != null) {
Index: src/main/java/org/apache/jackrabbit/core/version/VersionManager.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/version/VersionManager.java (Revision 800328)
+++ src/main/java/org/apache/jackrabbit/core/version/VersionManager.java (Arbeitskopie)
@@ -16,6 +16,8 @@
*/
package org.apache.jackrabbit.core.version;
+import java.util.Calendar;
+
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.state.NodeState;
@@ -61,10 +63,11 @@
* newly created version objects.
*
* @param node node to checkin
+ * @param cal create time of the new version, or null
* @return the newly created version
* @throws RepositoryException if an error occurs
*/
- Version checkin(NodeImpl node) throws RepositoryException;
+ Version checkin(NodeImpl node, Calendar cal) throws RepositoryException;
/**
* Removes the specified version from the given version history.
Index: src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java (Revision 800328)
+++ src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java (Arbeitskopie)
@@ -489,12 +489,12 @@
*
* @param name new version name
* @param src source node to version
+ * @param cal create time of the new version, or null
* @return the newly created version
* @throws RepositoryException if an error occurs
*/
- InternalVersionImpl checkin(Name name, NodeImpl src)
+ InternalVersionImpl checkin(Name name, NodeImpl src, Calendar cal)
throws RepositoryException {
-
// copy predecessors from src node
InternalValue[] predecessors;
if (src.hasProperty(NameConstants.JCR_PREDECESSORS)) {
@@ -527,7 +527,10 @@
NodeStateEx vNode = node.addNode(name, NameConstants.NT_VERSION, versionId, true);
// initialize 'created', 'predecessors' and 'successors'
- vNode.setPropertyValue(NameConstants.JCR_CREATED, InternalValue.create(getCurrentTime()));
+ if (cal == null) {
+ cal = getCurrentTime();
+ }
+ vNode.setPropertyValue(NameConstants.JCR_CREATED, InternalValue.create(cal));
vNode.setPropertyValues(NameConstants.JCR_PREDECESSORS, PropertyType.REFERENCE, predecessors);
vNode.setPropertyValues(NameConstants.JCR_SUCCESSORS, PropertyType.REFERENCE, InternalValue.EMPTY_ARRAY);