You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2008/10/15 14:59:22 UTC
svn commit: r704898 [4/4] - in /jackrabbit/branches/1.5: ./
jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/
jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/
jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit...
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java Wed Oct 15 05:59:19 2008
@@ -73,6 +73,8 @@
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.lock.LockException;
import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
import java.io.InputStream;
/**
@@ -139,17 +141,15 @@
public void save(ItemState state) throws ReferentialIntegrityException,
InvalidItemStateException, RepositoryException {
// shortcut, if no modifications are present
- if (!hasPendingChanges()) {
+ if (!transientStateMgr.hasPendingChanges()) {
return;
}
-
// collect the changes to be saved
- ChangeLog changeLog = getChangeLog(state, true);
+ ChangeLog changeLog = transientStateMgr.getChangeLog(state, true);
if (!changeLog.isEmpty()) {
// only pass changelog if there are transient modifications available
// for the specified item and its decendants.
workspaceItemStateMgr.execute(changeLog);
-
// remove states and operations just processed from the transient ISM
transientStateMgr.dispose(changeLog);
// now its save to clear the changeLog
@@ -168,20 +168,17 @@
* another item needs to be canceled as well in another sub-tree.
*/
public void undo(ItemState itemState) throws ConstraintViolationException, RepositoryException {
- try {
- ChangeLog changeLog = getChangeLog(itemState, false);
- if (!changeLog.isEmpty()) {
- // let changelog revert all changes
- changeLog.undo();
- // remove transient states and related operations from the t-statemanager
- transientStateMgr.dispose(changeLog);
- changeLog.reset();
- }
- } catch (InvalidItemStateException e) {
- // should never get here
- String msg = "Unable to undo item.";
- log.debug(msg);
- throw new RepositoryException(e);
+ // short cut
+ if (!transientStateMgr.hasPendingChanges()) {
+ return;
+ }
+ ChangeLog changeLog = transientStateMgr.getChangeLog(itemState, false);
+ if (!changeLog.isEmpty()) {
+ // let changelog revert all changes
+ changeLog.undo();
+ // remove transient states and related operations from the t-statemanager
+ transientStateMgr.dispose(changeLog);
+ changeLog.reset();
}
}
@@ -262,7 +259,8 @@
NodeState parent = operation.getParentState();
ItemDefinitionProvider defProvider = mgrProvider.getItemDefinitionProvider();
QNodeDefinition def = defProvider.getQNodeDefinition(parent.getAllNodeTypeNames(), operation.getNodeName(), operation.getNodeTypeName());
- addNodeState(parent, operation.getNodeName(), operation.getNodeTypeName(), operation.getUuid(), def, options);
+ List newStates = addNodeState(parent, operation.getNodeName(), operation.getNodeTypeName(), operation.getUuid(), def, options);
+ operation.addedState(newStates);
transientStateMgr.addOperation(operation);
}
@@ -336,11 +334,9 @@
| ItemStateValidator.CHECK_VERSIONING
| ItemStateValidator.CHECK_CONSTRAINTS;
removeItemState(state, options);
- // unless new state got removed remember operation and mark parent modified.
- if (!Status.isTerminal(state.getStatus())) {
- transientStateMgr.addOperation(operation);
- operation.getParentState().markModified();
- }
+
+ transientStateMgr.addOperation(operation);
+ operation.getParentState().markModified();
}
/**
@@ -351,11 +347,12 @@
// NOTE: nodestate is only modified upon save of the changes!
Name[] mixinNames = operation.getMixinNames();
NodeState nState = operation.getNodeState();
- NodeEntry nEntry = (NodeEntry) nState.getHierarchyEntry();
+ NodeEntry nEntry = nState.getNodeEntry();
- // new array of mixinNames to be set on the nodestate (and corresponding property state)
+ // assert the existence of the property entry and set the array of
+ // mixinNames to be set on the corresponding property state
PropertyEntry mixinEntry = nEntry.getPropertyEntry(NameConstants.JCR_MIXINTYPES);
- if (mixinNames != null && mixinNames.length > 0) {
+ if (mixinNames.length > 0) {
// update/create corresponding property state
if (mixinEntry != null) {
// execute value of existing property
@@ -372,22 +369,16 @@
}
nState.markModified();
transientStateMgr.addOperation(operation);
- } else {
+ } else if (mixinEntry != null) {
// remove the jcr:mixinTypes property state if already present
- if (mixinEntry != null) {
- PropertyState pState = mixinEntry.getPropertyState();
- boolean newMixinState = pState.getStatus() == Status.NEW;
- int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_VERSIONING;
- removeItemState(pState, options);
- // only added the remove-mixin operation if it doesn't revert
- // a previous 'add-mixin' (which has been removed automatically
- // upon notification of removing the prop-state).
- if (!newMixinState) {
- nState.markModified();
- transientStateMgr.addOperation(operation);
- }
- }
- }
+ PropertyState pState = mixinEntry.getPropertyState();
+ boolean newMixinState = pState.getStatus() == Status.NEW;
+ int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_VERSIONING;
+ removeItemState(pState, options);
+
+ nState.markModified();
+ transientStateMgr.addOperation(operation);
+ } // else: empty Name array and no mixin-prop-entry (should not occur)
}
/**
@@ -538,40 +529,6 @@
//--------------------------------------------< Internal State Handling >---
/**
*
- * @param itemState
- * @param throwOnStale Throws InvalidItemStateException if either the given
- * <code>ItemState</code> or any of its decendants is stale and the flag is true.
- * @return
- * @throws InvalidItemStateException if a stale <code>ItemState</code> is
- * encountered while traversing the state hierarchy. The <code>changeLog</code>
- * might have been populated with some transient item states. A client should
- * therefore not reuse the <code>changeLog</code> if such an exception is thrown.
- * @throws RepositoryException if <code>state</code> is a new item state.
- */
- private ChangeLog getChangeLog(ItemState itemState, boolean throwOnStale) throws InvalidItemStateException, ConstraintViolationException, RepositoryException {
- // build changelog for affected and decendant states only
- ChangeLog changeLog = new ChangeLog(itemState);
- // fail-fast test: check status of this item's state
- if (itemState.getStatus() == Status.NEW) {
- String msg = "Cannot save/revert an item with status NEW (" +itemState+ ").";
- log.debug(msg);
- throw new RepositoryException(msg);
- }
- if (throwOnStale && Status.isStale(itemState.getStatus())) {
- String msg = "Attempt to save/revert an item, that has been externally modified (" +itemState+ ").";
- log.debug(msg);
- throw new InvalidItemStateException(msg);
- }
- // collect transient/stale states that should be persisted or reverted
- itemState.getHierarchyEntry().collectStates(changeLog, throwOnStale);
-
- changeLog.collectOperations(transientStateMgr.getOperations());
- changeLog.checkIsSelfContained();
- return changeLog;
- }
-
- /**
- *
* @param parent
* @param propertyName
* @param propertyType
@@ -589,17 +546,17 @@
* @throws VersionException
* @throws RepositoryException
*/
- private void addPropertyState(NodeState parent, Name propertyName,
+ private PropertyState addPropertyState(NodeState parent, Name propertyName,
int propertyType, QValue[] values,
QPropertyDefinition pDef, int options)
throws LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
validator.checkAddProperty(parent, propertyName, pDef, options);
// create property state
- transientStateMgr.createNewPropertyState(propertyName, parent, pDef, values, propertyType);
+ return transientStateMgr.createNewPropertyState(propertyName, parent, pDef, values, propertyType);
}
- private void addNodeState(NodeState parent, Name nodeName, Name nodeTypeName,
+ private List addNodeState(NodeState parent, Name nodeName, Name nodeTypeName,
String uuid, QNodeDefinition definition, int options)
throws RepositoryException, ConstraintViolationException, AccessDeniedException,
UnsupportedRepositoryOperationException, NoSuchNodeTypeException,
@@ -623,14 +580,17 @@
}
}
+ List addedStates = new ArrayList();
+
// create new nodeState. NOTE, that the uniqueID is not added to the
- // state for consistency between 'addNode' and importXML // TODO review
+ // state for consistency between 'addNode' and importXML
NodeState nodeState = transientStateMgr.createNewNodeState(nodeName, null, nodeTypeName, definition, parent);
+ addedStates.add(nodeState);
if (uuid != null) {
QValue[] value = getQValues(uuid, qValueFactory);
ItemDefinitionProvider defProvider = mgrProvider.getItemDefinitionProvider();
QPropertyDefinition pDef = defProvider.getQPropertyDefinition(NameConstants.MIX_REFERENCEABLE, NameConstants.JCR_UUID, PropertyType.STRING, false);
- addPropertyState(nodeState, NameConstants.JCR_UUID, PropertyType.STRING, value, pDef, 0);
+ addedStates.add(addPropertyState(nodeState, NameConstants.JCR_UUID, PropertyType.STRING, value, pDef, 0));
}
// add 'auto-create' properties defined in node type
@@ -642,7 +602,7 @@
if (autoValue != null) {
int propOptions = ItemStateValidator.CHECK_NONE;
// execute 'addProperty' without adding operation.
- addPropertyState(nodeState, pd.getName(), pd.getRequiredType(), autoValue, pd, propOptions);
+ addedStates.add(addPropertyState(nodeState, pd.getName(), pd.getRequiredType(), autoValue, pd, propOptions));
}
}
}
@@ -653,8 +613,9 @@
QNodeDefinition nd = nda[i];
// execute 'addNode' without adding the operation.
int opt = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_COLLISION;
- addNodeState(nodeState, nd.getName(), nd.getDefaultPrimaryType(), null, nd, opt);
+ addedStates.addAll(addNodeState(nodeState, nd.getName(), nd.getDefaultPrimaryType(), null, nd, opt));
}
+ return addedStates;
}
private void removeItemState(ItemState itemState, int options) throws RepositoryException {
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java Wed Oct 15 05:59:19 2008
@@ -63,7 +63,7 @@
public static final int MODIFIED = 7;
/**
- * a new state was deleted and is now 'removed'
+ * a new state was removed and is now 'removed'
* or an existing item has been removed by a workspace operation or
* by an external modification.
*/
@@ -137,7 +137,7 @@
*
* @param status the status to check.
* @return <code>true</code> if <code>status</code> indicates that an item
- * state is stale.
+ * state is transiently modified.
*/
public static boolean isTransient(int status) {
return status == EXISTING_MODIFIED || status == EXISTING_REMOVED || status == NEW;
@@ -184,10 +184,10 @@
break;
case STALE_MODIFIED:
case STALE_DESTROYED:
- isValid = (oldStatus == EXISTING_MODIFIED);
+ isValid = (oldStatus == EXISTING_MODIFIED || oldStatus == EXISTING_REMOVED || oldStatus == STALE_MODIFIED);
break;
case REMOVED:
- // external removal always possible -> getNewStatus(int, int)
+ // removal always possible -> getNewStatus(int, int)
isValid = true;
break;
case MODIFIED:
@@ -220,7 +220,6 @@
// temporarily set the state to MODIFIED in order to inform listeners.
newStatus = Status.MODIFIED;
} else if (oldStatus == Status.EXISTING_MODIFIED) {
- // TODO: try to merge changes
newStatus = Status.STALE_MODIFIED;
} else {
// old status is EXISTING_REMOVED (or any other) => ignore.
@@ -229,7 +228,7 @@
}
break;
case Status.REMOVED:
- if (oldStatus == Status.EXISTING_MODIFIED) {
+ if (oldStatus == Status.EXISTING_MODIFIED || oldStatus == Status.STALE_MODIFIED) {
newStatus = Status.STALE_DESTROYED;
} else {
// applies both to NEW or to any other status
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java Wed Oct 15 05:59:19 2008
@@ -23,6 +23,7 @@
import org.apache.jackrabbit.spi.PropertyId;
import org.apache.jackrabbit.spi.QPropertyDefinition;
import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QValue;
import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
@@ -71,12 +72,10 @@
* @inheritDoc
* @see TransientItemStateFactory#createNewPropertyState(PropertyEntry, QPropertyDefinition)
*/
- public PropertyState createNewPropertyState(PropertyEntry entry, QPropertyDefinition definition) {
- PropertyState propState = new PropertyState(entry, this, definition, defProvider);
-
+ public PropertyState createNewPropertyState(PropertyEntry entry, QPropertyDefinition definition, QValue[] values, int propertyType) throws RepositoryException {
+ PropertyState propState = new PropertyState(entry, this, definition, defProvider, values, propertyType);
// notify listeners that a property state has been created
notifyCreated(propState);
-
return propState;
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java Wed Oct 15 05:59:19 2008
@@ -21,6 +21,9 @@
import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
import org.apache.jackrabbit.spi.QNodeDefinition;
import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QValue;
+
+import javax.jcr.RepositoryException;
/**
* <code>TransientItemStateFactory</code> extends the item state factory and
@@ -46,8 +49,12 @@
*
* @param entry
* @param definition
+ * @param values
+ * @param propertyType
* @return the created <code>PropertyState</code>.
*/
public PropertyState createNewPropertyState(PropertyEntry entry,
- QPropertyDefinition definition);
+ QPropertyDefinition definition,
+ QValue[] values, int propertyType)
+ throws RepositoryException;
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Wed Oct 15 05:59:19 2008
@@ -16,19 +16,26 @@
*/
package org.apache.jackrabbit.jcr2spi.state;
-import org.apache.jackrabbit.jcr2spi.operation.Operation;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.operation.Operation;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.QNodeDefinition;
import org.apache.jackrabbit.spi.QPropertyDefinition;
import org.apache.jackrabbit.spi.QValue;
-import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemExistsException;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.ConstraintViolationException;
+import java.util.Collection;
import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
/**
* <code>TransientItemStateManager</code> adds support for transient changes on
@@ -47,23 +54,40 @@
private static final Logger log = LoggerFactory.getLogger(TransientItemStateManager.class);
/**
- * The change log which keeps track of changes and maintains hard references
- * to changed item states.
+ * Added states
+ */
+ private final Set addedStates = new LinkedHashSet();
+
+ /**
+ * Modified states
+ */
+ private final Set modifiedStates = new LinkedHashSet();
+
+ /**
+ * Removed states
*/
- private final ChangeLog changeLog;
+ private final Set removedStates = new LinkedHashSet();
+ /**
+ * Stale states
+ */
+ private final Set staleStates = new LinkedHashSet();
+
+ /**
+ * Set of operations
+ */
+ private Set operations = new LinkedHashSet();
/**
*
*/
TransientItemStateManager() {
- this.changeLog = new ChangeLog(null);
}
/**
* @return the operations that have been recorded until now.
*/
Iterator getOperations() {
- return changeLog.getOperations();
+ return operations.iterator();
}
/**
@@ -73,14 +97,121 @@
* @param operation
*/
void addOperation(Operation operation) {
- changeLog.addOperation(operation);
+ operations.add(operation);
}
/**
* @return <code>true</code> if this transient ISM has pending changes.
*/
boolean hasPendingChanges() {
- return !changeLog.isEmpty();
+ return !operations.isEmpty();
+ }
+
+ /**
+ * Create the change log for the tree starting at <code>target</code>. This
+ * includes a check if the ChangeLog to be created is totally 'self-contained'
+ * and independant; items within the scope of this update operation (i.e.
+ * below the target) must not have dependencies outside of this tree (e.g.
+ * moving a node requires that the target node including both old and new
+ * parents are saved).
+ *
+ * @param target
+ * @param throwOnStale Throws InvalidItemStateException if either the given
+ * <code>ItemState</code> or any of its decendants is stale and the flag is true.
+ * @return
+ * @throws InvalidItemStateException if a stale <code>ItemState</code> is
+ * encountered while traversing the state hierarchy. The <code>changeLog</code>
+ * might have been populated with some transient item states. A client should
+ * therefore not reuse the <code>changeLog</code> if such an exception is thrown.
+ * @throws RepositoryException if <code>state</code> is a new item state.
+ */
+ ChangeLog getChangeLog(ItemState target, boolean throwOnStale) throws InvalidItemStateException, ConstraintViolationException, RepositoryException {
+ // fail-fast test: check status of this item's state
+ if (target.getStatus() == Status.NEW) {
+ String msg = "Cannot save/revert an item with status NEW (" +target+ ").";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ if (throwOnStale && Status.isStale(target.getStatus())) {
+ String msg = "Attempt to save/revert an item, that has been externally modified (" +target+ ").";
+ log.debug(msg);
+ throw new InvalidItemStateException(msg);
+ }
+
+ Set ops = new LinkedHashSet();
+ Set affectedStates = new LinkedHashSet();
+
+ HierarchyEntry he = target.getHierarchyEntry();
+ if (he.getParent() == null) {
+ // the root entry -> the complete change log can be used for
+ // simplicity. collecting ops, states can be omitted.
+ if (throwOnStale && !staleStates.isEmpty()) {
+ String msg = "Cannot save changes: States has been modified externally.";
+ log.debug(msg);
+ throw new InvalidItemStateException(msg);
+ } else {
+ affectedStates.addAll(staleStates);
+ }
+ ops.addAll(operations);
+ affectedStates.addAll(addedStates);
+ affectedStates.addAll(modifiedStates);
+ affectedStates.addAll(removedStates);
+ } else {
+ // not root entry:
+ // - check if there is a stale state in the scope (save only)
+ if (throwOnStale) {
+ for (Iterator it = staleStates.iterator(); it.hasNext();) {
+ ItemState state = (ItemState) it.next();
+ if (containedInTree(target, state)) {
+ String msg = "Cannot save changes: States has been modified externally.";
+ log.debug(msg);
+ throw new InvalidItemStateException(msg);
+ }
+ }
+ }
+ // - collect all affected states within the scope of save/undo
+ Iterator[] its = new Iterator[] {
+ addedStates.iterator(),
+ removedStates.iterator(),
+ modifiedStates.iterator()
+ };
+ IteratorChain chain = new IteratorChain(its);
+ if (!throwOnStale) {
+ chain.addIterator(staleStates.iterator());
+ }
+ while (chain.hasNext()) {
+ ItemState state = (ItemState) chain.next();
+ if (containedInTree(target, state)) {
+ affectedStates.add(state);
+ }
+ }
+ // - collect the set of operations and
+ // check if the affected states listed by the operations are all
+ // listed in the modified,removed or added states collected by this
+ // changelog.
+ for (Iterator it = operations.iterator(); it.hasNext();) {
+ Operation op = (Operation) it.next();
+ Collection opStates = op.getAffectedItemStates();
+ for (Iterator osIt = opStates.iterator(); osIt.hasNext();) {
+ ItemState state = (ItemState) osIt.next();
+ if (affectedStates.contains(state)) {
+ // operation needs to be included
+ if (!affectedStates.containsAll(opStates)) {
+ // incomplete changelog: need to save a parent as well
+ String msg = "ChangeLog is not self contained.";
+ throw new ConstraintViolationException(msg);
+ }
+ // no violation: add operation an stop iteration over
+ // all affected states present in the operation.
+ ops.add(op);
+ break;
+ }
+ }
+ }
+ }
+
+ ChangeLog cl = new ChangeLog(target, ops, affectedStates);
+ return cl;
}
/**
@@ -99,15 +230,14 @@
NodeState createNewNodeState(Name nodeName, String uniqueID, Name nodeTypeName,
QNodeDefinition definition, NodeState parent)
throws RepositoryException {
- NodeState nodeState = ((NodeEntry) parent.getHierarchyEntry()).addNewNodeEntry(nodeName, uniqueID, nodeTypeName, definition);
+ NodeEntry ne = ((NodeEntry) parent.getHierarchyEntry()).addNewNodeEntry(nodeName, uniqueID, nodeTypeName, definition);
try {
parent.markModified();
} catch (RepositoryException e) {
- nodeState.getHierarchyEntry().remove();
+ ne.remove();
throw e;
}
-
- return nodeState;
+ return ne.getNodeState();
}
/**
@@ -129,15 +259,14 @@
throws ItemExistsException, ConstraintViolationException, RepositoryException {
// NOTE: callers must make sure, the property type is not 'undefined'
NodeEntry nodeEntry = (NodeEntry) parent.getHierarchyEntry();
- PropertyState propState = nodeEntry.addNewPropertyEntry(propName, definition);
+ PropertyEntry pe = nodeEntry.addNewPropertyEntry(propName, definition, values, propertyType);
try {
- propState.setValues(values, propertyType);
parent.markModified();
} catch (RepositoryException e) {
- propState.getHierarchyEntry().remove();
+ pe.remove();
throw e;
}
- return propState;
+ return pe.getPropertyState();
}
/**
@@ -145,19 +274,74 @@
* transiently modified item states.
*/
void dispose() {
- changeLog.reset();
+ addedStates.clear();
+ modifiedStates.clear();
+ removedStates.clear();
+ staleStates.clear();
+ // also clear all operations
+ operations.clear();
}
/**
- * Remove the states and operations listed in the changeLog from the
- * internal changeLog.
+ * Remove the states and operations listed in the changeLog from internal
+ * list of modifications.
*
* @param subChangeLog
*/
void dispose(ChangeLog subChangeLog) {
- changeLog.removeAll(subChangeLog);
+ Set affectedStates = subChangeLog.getAffectedStates();
+ addedStates.removeAll(affectedStates);
+ modifiedStates.removeAll(affectedStates);
+ removedStates.removeAll(affectedStates);
+ staleStates.removeAll(affectedStates);
+
+ operations.removeAll(subChangeLog.getOperations());
+ }
+
+ /**
+ * A state has been removed. If the state is not a new state
+ * (not in the collection of added ones), then remove
+ * it from the modified states collection and add it to the
+ * removed states collection.
+ *
+ * @param state state that has been removed
+ */
+ private void removed(ItemState state) {
+ if (!addedStates.remove(state)) {
+ modifiedStates.remove(state);
+ }
+ removedStates.add(state);
}
+ /**
+ *
+ * @param parent
+ * @param state
+ * @return
+ */
+ private static boolean containedInTree(ItemState parent, ItemState state) {
+ HierarchyEntry he = state.getHierarchyEntry();
+ HierarchyEntry pHe = parent.getHierarchyEntry();
+ // short cuts first
+ if (he == pHe || he.getParent() == pHe) {
+ return true;
+ }
+ if (!parent.isNode() || he == pHe.getParent()) {
+ return false;
+ }
+ // none of the simple cases: walk up hierarchy
+ HierarchyEntry pe = he.getParent();
+ while (pe != null) {
+ if (pe == pHe) {
+ return true;
+ }
+ pe = pe.getParent();
+ }
+
+ // state isn't descendant of 'parent'
+ return false;
+ }
+
//-----------------------------------------< ItemStateLifeCycleListener >---
/**
* Depending on status of the given state adapt change log.
@@ -168,28 +352,77 @@
* @see ItemStateLifeCycleListener#statusChanged(ItemState, int)
*/
public void statusChanged(ItemState state, int previousStatus) {
- if (changeLog.isEmpty()) {
- return;
- }
+ /*
+ Update the collections of states that were transiently modified.
+ NOTE: cleanup of operations is omitted here. this is expected to
+ occur upon {@link ChangeLog#save()} and {@link ChangeLog#undo()}.
+ External modifications in contrast that clash with transient modifications
+ render the corresponding states stale.
+ */
switch (state.getStatus()) {
- case Status.EXISTING:
+ case (Status.EXISTING):
+ switch (previousStatus) {
+ case Status.EXISTING_MODIFIED:
+ // was modified and got persisted or reverted
+ modifiedStates.remove(state);
+ break;
+ case Status.EXISTING_REMOVED:
+ // was transiently removed and is now reverted
+ removedStates.remove(state);
+ break;
+ case Status.STALE_MODIFIED:
+ // was modified and stale and is now reverted
+ staleStates.remove(state);
+ break;
+ case Status.NEW:
+ // was new and has been saved now
+ addedStates.remove(state);
+ break;
+ //default:
+ // INVALIDATED, MODIFIED ignore. no effect to transient modifications.
+ // any other status change is invalid -> see Status#isValidStatusChange(int, int
+ }
+ break;
case Status.EXISTING_MODIFIED:
- case Status.EXISTING_REMOVED:
- case Status.REMOVED:
- changeLog.statusChanged(state, previousStatus);
+ // transition from EXISTING to EXISTING_MODIFIED
+ modifiedStates.add(state);
+ break;
+ case (Status.EXISTING_REMOVED):
+ // transition from EXISTING or EXISTING_MODIFIED to EXISTING_REMOVED
+ removed(state);
+ break;
+ case (Status.REMOVED):
+ switch (previousStatus) {
+ case Status.EXISTING_REMOVED:
+ // was transiently removed and removal was persisted.
+ // -> ignore
+ break;
+ case Status.NEW:
+ // a new entry was removed again: remember as removed
+ // in order to keep the operations and the affected
+ // states in sync
+ removed(state);
+ break;
+ }
break;
case Status.STALE_DESTROYED:
case Status.STALE_MODIFIED:
- // state is now stale. keep in modified. wait until refreshed
+ /**
+ state is stale due to external modification -> move it to
+ the collection of stale item states.
+ validation omitted for only 'existing_modified' states can
+ become stale see {@link Status#isValidStatusChange(int, int)}
+ */
+ modifiedStates.remove(state);
+ staleStates.add(state);
+ break;
case Status.MODIFIED:
- // MODIFIED is only possible on EXISTING states -> thus, there
- // must not be any transient modifications for that state.
- // we ignore it.
case Status.INVALIDATED:
- // -> nothing to do here.
+ // MODIFIED, INVALIDATED: ignore.
+ log.debug("Item " + state.getName() + " changed status from " + Status.getName(previousStatus) + " to " + Status.getName(state.getStatus()) + ".");
break;
default:
- log.error("ItemState has invalid status: " + state.getStatus());
+ log.error("ItemState "+ state.getName() + " has invalid status: " + state.getStatus());
}
}
@@ -200,7 +433,7 @@
public void created(ItemState state) {
// new state has been created
if (state.getStatus() == Status.NEW) {
- changeLog.added(state);
+ addedStates.add(state);
}
}
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java Wed Oct 15 05:59:19 2008
@@ -145,7 +145,9 @@
public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws ItemNotFoundException, RepositoryException {
try {
PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
- return createDeepPropertyState(info, anyParent, null);
+ PropertyState propState = createDeepPropertyState(info, anyParent, null);
+ assertValidState(propState, info);
+ return propState;
} catch (PathNotFoundException e) {
throw new ItemNotFoundException(e.getMessage());
}
@@ -210,7 +212,7 @@
// the given NodeEntry -> retrieve NodeState before executing
// validation check.
nodeState = createDeepNodeState(first, entry, infos);
- assertMatchingPath(first, nodeState.getNodeEntry());
+ assertValidState(nodeState, first);
} else {
// 'isDeep' == false -> the given NodeEntry must match to the
// first ItemInfo retrieved from the iterator.
@@ -261,9 +263,10 @@
parent.setUniqueID(uniqueID);
}
- // now build the nodestate itself
- NodeState state = new NodeState(entry, info, this, definitionProvider);
- state.setMixinTypeNames(info.getMixins());
+ if (Status.isTransient(entry.getStatus()) || Status.isStale(entry.getStatus())) {
+ log.debug("Node has pending changes; omit resetting the state.");
+ return entry.getNodeState();
+ }
// update NodeEntry from the information present in the NodeInfo (prop entries)
List propNames = new ArrayList();
@@ -273,7 +276,7 @@
propNames.add(propertyName);
}
try {
- entry.addPropertyEntries(propNames);
+ entry.setPropertyEntries(propNames);
} catch (ItemExistsException e) {
// should not get here
log.warn("Internal error", e);
@@ -286,8 +289,18 @@
entry.setNodeEntries(childInfos);
}
- notifyCreated(state);
- return state;
+ // now build or update the nodestate itself
+ NodeState tmp = new NodeState(entry, info, this, definitionProvider);
+ entry.setItemState(tmp);
+
+ NodeState nState = entry.getNodeState();
+ if (nState == tmp) {
+ // tmp state was used as resolution for the given entry i.e. the
+ // entry was not available before. otherwise the 2 states were
+ // merged. see HierarchyEntryImpl#setItemState
+ notifyCreated(nState);
+ }
+ return nState;
}
/**
@@ -298,7 +311,8 @@
* @param entry
* @return the new <code>PropertyState</code>.
*/
- private PropertyState createPropertyState(PropertyInfo info, PropertyEntry entry) {
+ private PropertyState createPropertyState(PropertyInfo info, PropertyEntry entry)
+ throws RepositoryException {
// make sure uuid part of id is correct
String uniqueID = info.getId().getUniqueID();
if (uniqueID != null) {
@@ -307,11 +321,23 @@
parent.setUniqueID(uniqueID);
}
- // build the PropertyState
- PropertyState state = new PropertyState(entry, info, this, definitionProvider);
-
- notifyCreated(state);
- return state;
+ if (Status.isTransient(entry.getStatus()) || Status.isStale(entry.getStatus())) {
+ log.debug("Property has pending changes; omit resetting the state.");
+ return entry.getPropertyState();
+ }
+
+ // now build or update the nodestate itself
+ PropertyState tmp = new PropertyState(entry, info, this, definitionProvider);
+ entry.setItemState(tmp);
+
+ PropertyState pState = entry.getPropertyState();
+ if (pState == tmp) {
+ // tmp state was used as resolution for the given entry i.e. the
+ // entry was not available before. otherwise the 2 states were
+ // merged. see HierarchyEntryImpl#setItemState
+ notifyCreated(pState);
+ }
+ return pState;
}
/**
@@ -326,10 +352,15 @@
// node for nodeId exists -> build missing entries in hierarchy
// Note, that the path contained in NodeId does not reveal which
// entries are missing -> calculate relative path.
- Path anyParentPath = anyParent.getPath();
+ Path anyParentPath = anyParent.getWorkspacePath();
Path relPath = anyParentPath.computeRelativePath(info.getPath());
Path.Element[] missingElems = relPath.getElements();
+ if (startsWithIllegalElement(missingElems)) {
+ log.error("Relative path to NodeEntry starts with illegal element -> ignore NodeInfo with path " + info.getPath());
+ return null;
+ }
+
NodeEntry entry = anyParent;
for (int i = 0; i < missingElems.length; i++) {
Name name = missingElems[i].getName();
@@ -360,8 +391,16 @@
Path anyParentPath = anyParent.getWorkspacePath();
Path relPath = anyParentPath.computeRelativePath(info.getPath());
Path.Element[] missingElems = relPath.getElements();
- NodeEntry entry = anyParent;
+ // make sure the missing elements don't start with . or .. in which
+ // case the info is not within the tree as it is expected
+ // (see also JCR-1797)
+ if (startsWithIllegalElement(missingElems)) {
+ log.error("Relative path to PropertyEntry starts with illegal element -> ignore PropertyInfo with path " + info.getPath());
+ return null;
+ }
+
+ NodeEntry entry = anyParent;
int i = 0;
// NodeEntries except for the very last 'missingElem'
while (i < missingElems.length - 1) {
@@ -402,6 +441,23 @@
}
/**
+ * Validation check: make sure the state is not null (was really created)
+ * and matches with the specified ItemInfo (path).
+ *
+ * @param state
+ * @param info
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ private static void assertValidState(ItemState state, ItemInfo info)
+ throws ItemNotFoundException, RepositoryException {
+ if (state == null) {
+ throw new ItemNotFoundException("HierarchyEntry does not belong to any existing ItemInfo. No ItemState was created.");
+ }
+ assertMatchingPath(info, state.getHierarchyEntry());
+ }
+
+ /**
* Validation check: Path of the given ItemInfo must match to the Path of
* the HierarchyEntry. This is required for Items that are identified by
* a uniqueID that may move within the hierarchy upon restore or clone.
@@ -421,6 +477,22 @@
}
/**
+ * Returns true if the given <code>missingElems</code> start with a parent (..),
+ * a current (.) or the root element, in which case the info is not within
+ * the tree as it is expected.
+ * See also #JCR-1797 for the corresponding enhancement request.
+ *
+ * @param missingElems
+ * @return
+ */
+ private static boolean startsWithIllegalElement(Path.Element[] missingElems) {
+ if (missingElems.length > 0) {
+ return !missingElems[0].denotesName();
+ }
+ return false;
+ }
+
+ /**
* @param entry
* @param degree
* @return the ancestor entry at the specified degree.
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java Wed Oct 15 05:59:19 2008
@@ -65,9 +65,8 @@
try {
return safeGetJCRPath(itemState.getHierarchyEntry().getPath(), pathResolver);
} catch (RepositoryException e) {
- ItemId id = itemState.getId();
- log.error("failed to convert " + id + " to JCR path.");
- return id.toString();
+ log.error("failed to convert " + itemState.toString() + " to JCR path.");
+ return itemState.toString();
}
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java Wed Oct 15 05:59:19 2008
@@ -16,13 +16,11 @@
*/
package org.apache.jackrabbit.jcr2spi.util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
import org.apache.jackrabbit.jcr2spi.state.PropertyState;
import org.apache.jackrabbit.jcr2spi.state.Status;
-import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.QValue;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
@@ -33,8 +31,6 @@
*/
public class StateUtility {
- private static Logger log = LoggerFactory.getLogger(StateUtility.class);
-
/**
*
* @param ps
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java Wed Oct 15 05:59:19 2008
@@ -453,19 +453,14 @@
Operation an = AddNode.create(parent, nodeInfo.getName(), ntName, nodeInfo.getUUID());
stateMgr.execute(an);
// retrieve id of state that has been created during execution of AddNode
- NodeState childState;
- List cne = parent.getNodeEntry().getNodeEntries(nodeInfo.getName());
- if (def.allowsSameNameSiblings()) {
- // TODO TOBEFIXED find proper solution. problem with same-name-siblings
- childState = ((NodeEntry)cne.get(cne.size()-1)).getNodeState();
- } else {
- childState = ((NodeEntry)cne.get(0)).getNodeState();
- }
+ NodeState childState = (NodeState) ((AddNode) an).getAddedStates().get(0);
// and set mixin types
- // TODO: missing validation
- Operation sm = SetMixin.create(childState, nodeInfo.getMixinNames());
- stateMgr.execute(sm);
+ Name[] mixinNames = nodeInfo.getMixinNames();
+ if (mixinNames != null && mixinNames.length > 0) {
+ Operation sm = SetMixin.create(childState, nodeInfo.getMixinNames());
+ stateMgr.execute(sm);
+ }
return childState;
}
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/HierarchyNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/HierarchyNodeTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/HierarchyNodeTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/HierarchyNodeTest.java Wed Oct 15 05:59:19 2008
@@ -88,7 +88,11 @@
public void testGetProperties() throws RepositoryException {
Session readSession = helper.getReadOnlySession();
- dump((Node) readSession.getItem(fileNode.getPath()));
+ try {
+ dump((Node) readSession.getItem(fileNode.getPath()));
+ } finally {
+ readSession.logout();
+ }
}
/** Recursively outputs the contents of the given node. */
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveNewTreeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveNewTreeTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveNewTreeTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveNewTreeTest.java Wed Oct 15 05:59:19 2008
@@ -22,6 +22,9 @@
import javax.jcr.RepositoryException;
import javax.jcr.Item;
import javax.jcr.PathNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
/**
* <code>MoveTreeTest</code>...
@@ -46,7 +49,6 @@
assertTrue("Moving a node must move all child items as well.", ancestor.isSame(destParentNode));
ancestor = grandChildNode.getAncestor(degree);
assertTrue("Moving a node must move all child items as well.", ancestor.isSame(destParentNode));
-
}
public void testTreeEntries() throws RepositoryException {
@@ -109,4 +111,23 @@
// OK
}
}
+
+ public void testRefreshMovedTree() throws RepositoryException {
+ testRootNode.refresh(true);
+ String msg = "Refresh must not revert a moved tree.";
+
+ assertFalse(msg, superuser.itemExists(srcPath + "/" + nodeName2 + "/" + nodeName3));
+ int degree = destParentNode.getDepth();
+
+ List l = new ArrayList();
+ l.add(childNode);
+ l.add(childProperty);
+ l.add(grandChildNode);
+
+ for (Iterator it = l.iterator(); it.hasNext();) {
+ Item item = (Item) it.next();
+ assertTrue(msg, item.isNew());
+ assertTrue(msg, childNode.getAncestor(degree).isSame(destParentNode));
+ }
+ }
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/NodeOrderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/NodeOrderTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/NodeOrderTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/NodeOrderTest.java Wed Oct 15 05:59:19 2008
@@ -109,4 +109,20 @@
another.logout();
}
}
+
+ /**
+ * Test if the order of Nodes is the same when accessed through another
+ * <code>Session</code> after having accessed some of the nodes individually.
+ */
+ public void testOrderAfterIndividualAccess2() throws RepositoryException {
+ Session another = helper.getReadOnlySession();
+ try {
+ Node n2 = (Node) another.getItem(children[3].getPath());
+ Node n3 = (Node) another.getItem(children[1].getPath());
+ NodeIterator it = ((Node) another.getItem(testRootNode.getPath())).getNodes();
+ checkOrder(it, children);
+ } finally {
+ another.logout();
+ }
+ }
}
\ No newline at end of file
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshMovedTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshMovedTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshMovedTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshMovedTest.java Wed Oct 15 05:59:19 2008
@@ -80,19 +80,22 @@
*/
public void testRefreshOtherSession() throws RepositoryException {
Session readSession = helper.getReadOnlySession();
- Node anotherNode = (Node) readSession.getItem(srcPath);
-
- // workspace move
- testRootNode.getSession().getWorkspace().move(srcPath, destinationPath);
-
- readSession.refresh(false);
try {
- String p = anotherNode.getPath();
- // unless InvalidItemStateException is thrown the node must have
- // been 'moved' to its new position.
- assertTrue("Upon refresh of a node moved by another session it must be moved to the new destination (or removed).", p.equals(destinationPath));
- } catch (InvalidItemStateException e) {
- // ok as well.
+ Node anotherNode = (Node) readSession.getItem(srcPath);
+ // workspace move
+ testRootNode.getSession().getWorkspace().move(srcPath, destinationPath);
+
+ readSession.refresh(false);
+ try {
+ String p = anotherNode.getPath();
+ // unless InvalidItemStateException is thrown the node must have
+ // been 'moved' to its new position.
+ assertTrue("Upon refresh of a node moved by another session it must be moved to the new destination (or removed).", p.equals(destinationPath));
+ } catch (InvalidItemStateException e) {
+ // ok as well.
+ }
+ } finally {
+ readSession.logout();
}
}
}
\ No newline at end of file
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshTrueTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshTrueTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshTrueTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshTrueTest.java Wed Oct 15 05:59:19 2008
@@ -16,18 +16,16 @@
*/
package org.apache.jackrabbit.jcr2spi;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.jackrabbit.test.NotExecutableException;
-import org.apache.jackrabbit.test.AbstractJCRTest;
-import javax.jcr.Value;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
-import javax.jcr.InvalidItemStateException;
-import javax.jcr.version.VersionException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.lock.LockException;
+import javax.jcr.Value;
/**
* <code>RefreshTrue</code>...
@@ -52,6 +50,22 @@
super.tearDown();
}
+ public void testNewNode() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName2);
+ Property p = n.setProperty(propertyName1, testValue);
+ testRootNode.refresh(true);
+
+ // n must still be new and accessible
+ String msg = "Refresh 'true' must not affect the new Node/Property.";
+ assertTrue(msg, testRootNode.hasNode(nodeName2));
+ assertTrue(msg, n.isNew());
+ assertTrue(msg, n.hasProperty(propertyName1));
+
+ // p must still be accessible
+ p.getString();
+ assertTrue(msg, p.isSame(n.getProperty(propertyName1)));
+ }
+
public void testNewProperty() throws RepositoryException {
Property p = testRootNode.setProperty(propertyName1, testValue);
testRootNode.refresh(true);
@@ -63,7 +77,7 @@
assertTrue("Refresh 'true' must not affect a new Property.", p.isSame(pAgain));
}
- public void testRemovedProperty() throws RepositoryException, LockException, ConstraintViolationException, VersionException {
+ public void testRemovedProperty() throws RepositoryException {
Property p = testRootNode.setProperty(propertyName1, testValue);
testRootNode.save();
@@ -79,4 +93,30 @@
}
assertFalse("Refresh 'true' must not revert removal of an item.", testRootNode.hasProperty(propertyName1));
}
+
+ public void testRemovedNewItem() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName2);
+ Property p = n.setProperty(propertyName1, testValue);
+ n.remove();
+
+ testRootNode.refresh(true);
+
+ // n must still be new and accessible
+ String msg = "Refresh 'true' must revert the removal of new a Node/Property.";
+ assertFalse(msg, testRootNode.hasNode(nodeName2));
+ assertFalse(msg, n.isNew() && n.isModified());
+ assertFalse(msg, p.isNew() && p.isModified());
+ try {
+ n.hasProperty(propertyName1);
+ fail(msg);
+ } catch (InvalidItemStateException e) {
+ // success
+ }
+ try {
+ p.getString();
+ fail(msg);
+ } catch (InvalidItemStateException e) {
+ // success
+ }
+ }
}
\ No newline at end of file
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RemoveNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RemoveNodeTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RemoveNodeTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RemoveNodeTest.java Wed Oct 15 05:59:19 2008
@@ -134,12 +134,12 @@
childNode.remove();
superuser.save();
- // try to remove already deleted node with session 2
+ // try to remove already removed node with session 2
try {
childNode2.refresh(false);
childNode2.remove();
otherSession.save();
- fail("Removing a node already deleted by other session should throw an InvalidItemStateException!");
+ fail("Removing a node already removed by other session should throw an InvalidItemStateException!");
} catch (InvalidItemStateException e) {
//ok, works as expected
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ReorderMoveTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ReorderMoveTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ReorderMoveTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ReorderMoveTest.java Wed Oct 15 05:59:19 2008
@@ -129,11 +129,19 @@
// reorder
srcParent.orderBefore(getRelPath(children[0]), null);
testOrder(srcParent, new Node[] {children[3], children[0]});
+ assertTrue(srcParent.hasNode(snsName+"[1]"));
+ assertTrue(srcParent.hasNode(snsName+"[2]"));
+ assertFalse(srcParent.hasNode(snsName+"[3]"));
assertFalse(srcParent.hasNode(snsName+"[4]"));
+ assertFalse(srcParent.hasNode(snsName+"[5]"));
testRootNode.save();
testOrder(srcParent, new Node[] {children[3], children[0]});
+ assertTrue(srcParent.hasNode(snsName+"[1]"));
+ assertTrue(srcParent.hasNode(snsName+"[2]"));
+ assertFalse(srcParent.hasNode(snsName+"[3]"));
assertFalse(srcParent.hasNode(snsName+"[4]"));
+ assertFalse(srcParent.hasNode(snsName+"[5]"));
// check if move have been successfull
assertEquals(children[2].getPath(), destPath);
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RevertMoveTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RevertMoveTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RevertMoveTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RevertMoveTest.java Wed Oct 15 05:59:19 2008
@@ -67,5 +67,9 @@
assertFalse("Reverting the move operation must remove the node at destination path.", testRootNode.getSession().itemExists(destinationPath));
assertTrue("Reverting the move operation must re-add the node at its original position.", testRootNode.getSession().itemExists(srcPath));
assertTrue("Reverting the move operation must re-add the node at its original position.", srcPath.equals(moveNode.getPath()));
+
+ assertFalse("The former destination must not be modified.", destParentNode.isModified());
+ assertFalse("The parent must not be modified.", srcParentNode.isModified());
+ assertFalse("The move-node must not be modified.", moveNode.isModified());
}
}
\ No newline at end of file
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java Wed Oct 15 05:59:19 2008
@@ -34,14 +34,21 @@
TestSuite suite = new TestSuite("jcr2spi tests");
suite.addTestSuite(AccessByRelativePathTest.class);
+
+ // get node(s)
suite.addTestSuite(SNSIndexTest.class);
suite.addTestSuite(NodeOrderTest.class);
// set/add property
+ suite.addTestSuite(GetPropertyTest.class);
+ suite.addTestSuite(AddPropertyTest.class);
suite.addTestSuite(AddNewPropertyTest.class);
suite.addTestSuite(SingleValuedPropertyTest.class);
suite.addTestSuite(MultiValuedPropertyTest.class);
+ // change mixin types
+ suite.addTestSuite(MixinModificationTest.class);
+
// move
suite.addTestSuite(MoveTest.class);
suite.addTestSuite(MoveReferenceableTest.class);
@@ -51,6 +58,8 @@
suite.addTestSuite(MoveMultipleTest.class);
//suite.addTestSuite(WorkspaceMoveTest.class); // see JCR-1276
suite.addTestSuite(RevertMoveTest.class);
+ suite.addTestSuite(MoveToNewTest.class);
+ suite.addTestSuite(MoveCombinedTest.class);
// refresh
suite.addTestSuite(RefreshFalseTest.class);
@@ -62,6 +71,7 @@
suite.addTestSuite(RemovePropertyTest.class);
suite.addTestSuite(RemoveReferenceableNodeTest.class);
suite.addTestSuite(RemoveSNSTest.class);
+ suite.addTestSuite(RemoveMovedNodeTest.class);
// rename
suite.addTestSuite(RenameTest.class);
@@ -75,7 +85,7 @@
suite.addTestSuite(ReorderNewAndSavedTest.class);
suite.addTestSuite(ReorderMixedTest.class);
suite.addTestSuite(ReorderMoveTest.class);
-
+
// update
suite.addTestSuite(UpdateTest.class);
@@ -83,6 +93,7 @@
suite.addTestSuite(ReplaceNodeTest.class);
suite.addTestSuite(HierarchyNodeTest.class);
suite.addTestSuite(LazyItemIteratorTest.class);
+ suite.addTestSuite(ExternalModificationTest.class);
return suite;
}
Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/nodetype/AddMixinTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/nodetype/AddMixinTest.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/nodetype/AddMixinTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/nodetype/AddMixinTest.java Wed Oct 15 05:59:19 2008
@@ -118,6 +118,26 @@
}
assertTrue("Adding 2 mixins at once -> both must be present.", node.isNodeType(mixReferenceable) && node.isNodeType(mixLockable));
+ }
+
+ /**
+ * Implementation specific test adding a new Node with a nodeType, that has
+ * a mixin-supertype. The mixin must only take effect upon save.
+ *
+ * @throws NotExecutableException
+ * @throws RepositoryException
+ */
+ public void testAddMultipleAtOnce2() throws NotExecutableException, RepositoryException {
+ Node node;
+ try {
+ node = testRootNode.addNode(nodeName1, testNodeType);
+ node.addMixin(mixReferenceable);
+ node.addMixin(mixLockable);
+ testRootNode.save();
+ } catch (RepositoryException e) {
+ throw new NotExecutableException();
+ }
+
List mixins = Arrays.asList(node.getMixinNodeTypes());
assertTrue("Adding 2 mixins at once -> both must be present.", mixins.contains(ntMgr.getNodeType(mixReferenceable)) && mixins.contains(ntMgr.getNodeType(mixLockable)));
}
Modified: jackrabbit/branches/1.5/jackrabbit-spi2jcr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-spi2jcr/pom.xml?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-spi2jcr/pom.xml (original)
+++ jackrabbit/branches/1.5/jackrabbit-spi2jcr/pom.xml Wed Oct 15 05:59:19 2008
@@ -68,7 +68,6 @@
<value>
org.apache.jackrabbit.jcr2spi.name.NamespaceRegistryTest#testReRegisteredNamespaceVisibility
org.apache.jackrabbit.jcr2spi.name.NamespaceRegistryTest#testRegisteredNamespaceVisibility
- org.apache.jackrabbit.jcr2spi.ReorderMoveTest#testRevertMoveAndReorderSNS
org.apache.jackrabbit.jcr2spi.ReorderMoveTest#testRevertMoveReorderedSNS
org.apache.jackrabbit.value.BinaryValueTest#testBinaryValueEquals
</value>
Modified: jackrabbit/branches/1.5/jackrabbit-spi2jcr/src/test/java/org/apache/jackrabbit/spi2jcr/RepositoryStubImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-spi2jcr/src/test/java/org/apache/jackrabbit/spi2jcr/RepositoryStubImpl.java?rev=704898&r1=704897&r2=704898&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-spi2jcr/src/test/java/org/apache/jackrabbit/spi2jcr/RepositoryStubImpl.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-spi2jcr/src/test/java/org/apache/jackrabbit/spi2jcr/RepositoryStubImpl.java Wed Oct 15 05:59:19 2008
@@ -80,8 +80,7 @@
// TODO: make configurable
BatchReadConfig brconfig = new BatchReadConfig();
- brconfig.setDepth(NameConstants.NT_FILE, BatchReadConfig.DEPTH_INFINITE);
- brconfig.setDepth(NameConstants.NT_RESOURCE, BatchReadConfig.DEPTH_INFINITE);
+ brconfig.setDepth(NameConstants.NT_UNSTRUCTURED, BatchReadConfig.DEPTH_INFINITE);
return new RepositoryServiceImpl(jackrabbitRepo, brconfig);
}