Author: jukka Date: Tue Oct 31 02:37:18 2006 New Revision: 469441 URL: http://svn.apache.org/viewvc?view=rev&rev=469441 Log: JCR-569: Reverted the WorkspaceImporter rewrite, see the recently added WorkspaceImporterTest regression. Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?view=diff&rev=469441&r1=469440&r2=469441 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Tue Oct 31 02:37:18 2006 @@ -16,23 +16,6 @@ */ package org.apache.jackrabbit.core.xml; -import java.util.Iterator; -import java.util.List; -import java.util.Stack; - -import javax.jcr.AccessDeniedException; -import javax.jcr.ImportUUIDBehavior; -import javax.jcr.ItemExistsException; -import javax.jcr.ItemNotFoundException; -import javax.jcr.PathNotFoundException; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; -import javax.jcr.ValueFormatException; -import javax.jcr.lock.LockException; -import javax.jcr.nodetype.ConstraintViolationException; -import javax.jcr.version.VersionException; -import javax.jcr.version.VersionHistory; - import org.apache.jackrabbit.core.BatchedItemOperations; import org.apache.jackrabbit.core.HierarchyManager; import org.apache.jackrabbit.core.NodeId; @@ -56,23 +39,36 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.jcr.ImportUUIDBehavior; +import javax.jcr.ItemExistsException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.PathNotFoundException; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.version.VersionException; +import javax.jcr.version.VersionHistory; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + /** - * WorkspaceImporter. It imports the content submitted to it - * by the Content Handler - * + * WorkspaceImporter ... */ public class WorkspaceImporter implements Importer { private static Logger log = LoggerFactory.getLogger(WorkspaceImporter.class); + private final NodeState importTarget; + private final WorkspaceImpl wsp; private final NodeTypeRegistry ntReg; private final HierarchyManager hierMgr; private final BatchedItemOperations itemOps; + private final int uuidBehavior; - //It is not useful anymore: we never abort: we raise an exception. - // I suggest to delete it. Do you see any issue with this? - private boolean aborted = false; + private boolean aborted; private Stack parents; /** @@ -81,31 +77,12 @@ */ private final ReferenceChangeTracker refTracker; - // Unused for now. It will be used in the next iteration on JIRA - private boolean raw = false; - - /** - * True if we skip the tree with current node as root - */ - private boolean skip = false; - /** - * Used to find when stopping skipping - */ - private NodeInfo skipNode; - - /** - * True if this node already exist - */ - private NodeState existing = null; - private WorkspaceImpl wsp; - - /** - * Creates a new sWorkspaceImporter instance. + * Creates a new WorkspaceImporter instance. * * @param parentPath target path where to add the imported subtree - * @param wsp the workspace we want to import content to - * @param ntReg the NodeTypeRegistry of the repository + * @param wsp + * @param ntReg * @param uuidBehavior flag that governs how incoming UUIDs are handled * @throws PathNotFoundException if no node exists at * parentPath or if the @@ -121,195 +98,108 @@ * @throws RepositoryException if another error occurs */ public WorkspaceImporter(Path parentPath, - WorkspaceImpl wsp, - NodeTypeRegistry ntReg, - int uuidBehavior) - throws PathNotFoundException, ConstraintViolationException, - VersionException, LockException, RepositoryException { + WorkspaceImpl wsp, + NodeTypeRegistry ntReg, + int uuidBehavior) + throws PathNotFoundException, ConstraintViolationException, + VersionException, LockException, RepositoryException { + SessionImpl ses = (SessionImpl) wsp.getSession(); itemOps = new BatchedItemOperations(wsp.getItemStateManager(), ntReg, ses.getLockManager(), ses, wsp.getHierarchyManager(), ses.getNamespaceResolver()); + hierMgr = wsp.getHierarchyManager(); - this.hierMgr = wsp.getHierarchyManager(); - //Perform preliminary checks + // perform preliminary checks itemOps.verifyCanWrite(parentPath); importTarget = itemOps.getNodeState(parentPath); + this.wsp = wsp; this.ntReg = ntReg; this.uuidBehavior = uuidBehavior; + aborted = false; + refTracker = new ReferenceChangeTracker(); + parents = new Stack(); parents.push(importTarget); } /** - * Performs some checks to know if the node is importable or not. - * If it is a serious issue, raises an exception, else return false. - * this subtree. - *
- * Performs also if needed some remapping. - * - * @param parent the parent NodeState - * @param nodeInfo NodeInfo passed by the ContentHandler - * @param propInfo PropInfo passed by the ContentHandler - * @return true if the node is fine; else false - * @throws RepositoryException if some constraints checks are not OK - * @throws ItemExistsException if the item exist - * @throws ItemNotFoundException if some constraints checks are not OK (shouldn't happen) - * @throws LockException if some constraints checks are not OK - * @throws VersionException if some constraints checks are not OK - * @throws AccessDeniedException if some constraints checks are not OK - * @throws ConstraintViolationException if some constraints checks are not OK + * @param parent + * @param conflicting + * @param nodeInfo + * @return + * @throws RepositoryException */ - private boolean checkNode(NodeState parent, NodeInfo nodeInfo, List propInfo) - throws ConstraintViolationException, AccessDeniedException, VersionException, - LockException, ItemNotFoundException, ItemExistsException, RepositoryException { - itemOps.checkAddNode(parent, nodeInfo.getName(), nodeInfo.getNodeTypeName(), - BatchedItemOperations.CHECK_ACCESS - | BatchedItemOperations.CHECK_CONSTRAINTS - | BatchedItemOperations.CHECK_LOCK - | BatchedItemOperations.CHECK_VERSIONING); - - QName nodeName = nodeInfo.getName(); - QName ntName = nodeInfo.getNodeTypeName(); - - if (parent.hasChildNodeEntry(nodeName)) { - // a node with that name already exists... - //No need to check for more than one, since if it - //is the case we can import it. - NodeState.ChildNodeEntry entry = - parent.getChildNodeEntry(nodeName, 1); - NodeId idExisting = entry.getId(); - NodeState existing = (NodeState) itemOps.getItemState(idExisting); - NodeDef def = ntReg.getNodeDef(existing.getDefinitionId()); - if (!def.allowsSameNameSiblings()) { - // existing doesn't allow same-name siblings, - // check for potential conflicts - EffectiveNodeType entExisting = - itemOps.getEffectiveNodeType(existing); - if (!raw && def.isProtected() && entExisting.includesNodeType(ntName)) { - return false; - } + protected NodeState resolveUUIDConflict(NodeState parent, + NodeState conflicting, + NodeInfo nodeInfo) + throws RepositoryException { - if (def.isAutoCreated() && entExisting.includesNodeType(ntName)) { - // this node has already been auto-created, - // no need to create it - this.existing = existing; - } else { - throw new ItemExistsException(itemOps.safeGetJCRPath(existing.getNodeId())); - } + NodeState node; + if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW) { + // create new with new uuid: + // check if new node can be added (check access rights & + // node type constraints only, assume locking & versioning status + // has already been checked on ancestor) + itemOps.checkAddNode(parent, nodeInfo.getName(), + nodeInfo.getNodeTypeName(), + BatchedItemOperations.CHECK_ACCESS + | BatchedItemOperations.CHECK_CONSTRAINTS); + node = itemOps.createNodeState(parent, nodeInfo.getName(), + nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(), null); + // remember uuid mapping + EffectiveNodeType ent = itemOps.getEffectiveNodeType(node); + if (ent.includesNodeType(QName.MIX_REFERENCEABLE)) { + refTracker.mappedUUID(nodeInfo.getId().getUUID(), node.getNodeId().getUUID()); } - } - - if (parent.hasPropertyName(nodeName)) { - /** - * a property with the same name already exists; if this property - * has been imported as well (e.g. through document view import - * where an element can have the same name as one of the attributes - * of its parent element) we have to rename the onflicting property; - * - * see http://issues.apache.org/jira/browse/JCR-61 - */ - PropertyId propId = new PropertyId(parent.getNodeId(), nodeName); - PropertyState conflicting = itemOps.getPropertyState(propId); - if (conflicting.getStatus() == ItemState.STATUS_NEW) { - // assume this property has been imported as well; - // rename conflicting property - // @todo use better reversible escaping scheme to create unique name - QName newName = new QName(nodeName.getNamespaceURI(), nodeName.getLocalName() + "_"); - if (parent.hasPropertyName(newName)) { - newName = new QName(newName.getNamespaceURI(), newName.getLocalName() + "_"); + } else if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW) { + String msg = "a node with uuid " + nodeInfo.getId() + + " already exists!"; + log.debug(msg); + throw new ItemExistsException(msg); + } else if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING) { + // make sure conflicting node is not importTarget or an ancestor thereof + Path p0 = hierMgr.getPath(importTarget.getNodeId()); + Path p1 = hierMgr.getPath(conflicting.getNodeId()); + try { + if (p1.equals(p0) || p1.isAncestorOf(p0)) { + String msg = "cannot remove ancestor node"; + log.debug(msg); + throw new ConstraintViolationException(msg); } - PropertyState newProp = - itemOps.createPropertyState(parent, newName, - conflicting.getType(), conflicting.getValues().length); - newProp.setValues(conflicting.getValues()); - parent.removePropertyName(nodeName); - itemOps.store(parent); - itemOps.destroy(conflicting); + } catch (MalformedPathException mpe) { + // should never get here... + String msg = "internal error: failed to determine degree of relationship"; + log.error(msg, mpe); + throw new RepositoryException(msg, mpe); } - } - - return true; - } - - /** - * Create propoerties on a specific NodeState - * @param myNode the NodeState - * @param propInfos PropInfo - * @throws ItemNotFoundException if issue in the NodeState - * @throws ItemExistsException if issue in the NodeState - * @throws ConstraintViolationException if issue in the NodeState - * @throws ValueFormatException if issue in the NodeState - * @throws RepositoryException if issue in the NodeState - */ - private void createProperties(NodeState myNode, List propInfos) - throws ItemNotFoundException, ItemExistsException, ConstraintViolationException, - ValueFormatException, RepositoryException { - // process properties - Iterator iter = propInfos.iterator(); - while (iter.hasNext()) { - PropInfo pi = (PropInfo) iter.next(); - pi.apply(myNode, itemOps, ntReg, refTracker); - } - } - - /** - * Create the specific NodeState - * @param parent NodeState - * @param nodeInfo NodeInfo - * @return newly create NodeState - * @throws ConstraintViolationException if we cannot create the NodeState - * @throws RepositoryException if we cannot create the NodeState - */ - private NodeState createNode(NodeState parent, NodeInfo nodeInfo) throws ConstraintViolationException, RepositoryException { - - NodeDef def = - itemOps.findApplicableNodeDefinition(nodeInfo.getName(), nodeInfo.getNodeTypeName(), parent); - - // potential uuid conflict - NodeState conflicting = null; - NodeState node; + // remove conflicting: + // check if conflicting can be removed + // (access rights, node type constraints, locking & versioning status) + itemOps.checkRemoveNode(conflicting, + BatchedItemOperations.CHECK_ACCESS + | BatchedItemOperations.CHECK_LOCK + | BatchedItemOperations.CHECK_VERSIONING + | BatchedItemOperations.CHECK_CONSTRAINTS); + // do remove conflicting (recursive) + itemOps.removeNodeState(conflicting); - try { - if (nodeInfo.getId() != null) { - conflicting = itemOps.getNodeState(nodeInfo.getId()); - } - } catch (ItemNotFoundException infe) { - conflicting = null; - } - if (conflicting != null) { - // resolve uuid conflict - node = resolveUUIDConflict(parent, conflicting, nodeInfo); - } - else { + // create new with given uuid: + // check if new node can be added (check access rights & + // node type constraints only, assume locking & versioning status + // has already been checked on ancestor) + itemOps.checkAddNode(parent, nodeInfo.getName(), + nodeInfo.getNodeTypeName(), + BatchedItemOperations.CHECK_ACCESS + | BatchedItemOperations.CHECK_CONSTRAINTS); // do create new node - node = itemOps.createNodeState(parent, nodeInfo.getName(), nodeInfo.getNodeTypeName(), - nodeInfo.getMixinNames(), null, def); - } - return node; - } - - /** - * Resolve UUID conflict if any. - * - * @param parent NodeState - * @param conflicting NodeState - * @param nodeInfo NodeInfo - * @return the new conflicting NodeState - * @throws ItemExistsException - * @throws ConstraintViolationException - * @throws IllegalStateException - * @throws RepositoryException - */ - private NodeState resolveUUIDConflict(NodeState parent, NodeState conflicting, NodeInfo nodeInfo) - throws ItemExistsException, ConstraintViolationException, IllegalStateException, RepositoryException { - NodeState node = null; - switch (uuidBehavior) { - - case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING: + node = itemOps.createNodeState(parent, nodeInfo.getName(), + nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(), + nodeInfo.getId()); + } else if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING) { NodeId parentId = conflicting.getParentId(); if (parentId == null) { String msg = "root node cannot be replaced"; @@ -335,83 +225,34 @@ | BatchedItemOperations.CHECK_CONSTRAINTS); // do remove conflicting (recursive) itemOps.removeNodeState(conflicting); - // do create new node - node = itemOps.createNodeState(parent, nodeInfo.getName(), - nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(), - nodeInfo.getId()); - break; - - case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING: - // make sure conflicting node is not importTarget or an ancestor thereof - Path p0 = hierMgr.getPath(importTarget.getNodeId()); - Path p1 = hierMgr.getPath(conflicting.getNodeId()); - try { - if (p1.equals(p0) || p1.isAncestorOf(p0)) { - String msg = "cannot remove ancestor node"; - log.debug(msg); - throw new ConstraintViolationException(msg); - } - } catch (MalformedPathException mpe) { - // should never get here... - String msg = "internal error: failed to determine degree of relationship"; - log.error(msg, mpe); - throw new RepositoryException(msg, mpe); - } - // remove conflicting: - // check if conflicting can be removed + // create new with given uuid at same location as conflicting: + // check if new node can be added at other location // (access rights, node type constraints, locking & versioning status) - itemOps.checkRemoveNode(conflicting, + itemOps.checkAddNode(parent, nodeInfo.getName(), + nodeInfo.getNodeTypeName(), BatchedItemOperations.CHECK_ACCESS | BatchedItemOperations.CHECK_LOCK | BatchedItemOperations.CHECK_VERSIONING | BatchedItemOperations.CHECK_CONSTRAINTS); - // do remove conflicting (recursive) - itemOps.removeNodeState(conflicting); - - // create new with given uuid: // do create new node node = itemOps.createNodeState(parent, nodeInfo.getName(), nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(), nodeInfo.getId()); - break; - - case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW: - String msg = "a node with uuid " + nodeInfo.getId() - + " already exists!"; + } else { + String msg = "unknown uuidBehavior: " + uuidBehavior; log.debug(msg); - throw new ItemExistsException(msg); - - case ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW: - // create new with new uuid: - // check if new node can be added (check access rights & - // node type constraints only, assume locking & versioning status - // has already been checked on ancestor) - node = itemOps.createNodeState(parent, nodeInfo.getName(), - nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(), null); - // remember uuid mapping - EffectiveNodeType ent = itemOps.getEffectiveNodeType(node); - if (ent.includesNodeType(QName.MIX_REFERENCEABLE)) { - refTracker.mappedUUID(nodeInfo.getId().getUUID(), node.getNodeId().getUUID()); - } - break; - //No need for default case. + throw new RepositoryException(msg); } - return node; - } - /** - * @return true if skip mode is on. - */ - protected boolean isSkipped() { - return skip; + return node; } /** * Post-process imported node (initialize properties with special * semantics etc.) * - * @param node NodeState to postprocess - * @throws RepositoryException if issue when postprocessing a node + * @param node + * @throws RepositoryException */ protected void postProcessNode(NodeState node) throws RepositoryException { /** @@ -478,7 +319,6 @@ } } - //-------------------------------------------------------------< Importer > /** * {@inheritDoc} @@ -499,58 +339,213 @@ * {@inheritDoc} */ public void startNode(NodeInfo nodeInfo, List propInfos) - throws RepositoryException { + throws RepositoryException { if (aborted) { + // the import has been aborted, get outta here... return; } - NodeState parent = (NodeState) parents.peek(); + boolean succeeded = false; + NodeState parent; + try { + // check sanity of workspace/session first + wsp.sanityCheck(); - if (raw && !checkNode(parent, nodeInfo, propInfos)) { - skip = true; - } + parent = (NodeState) parents.peek(); - if (skip) { - return; - } + // process node + + NodeState node = null; + NodeId id = nodeInfo.getId(); + QName nodeName = nodeInfo.getName(); + QName ntName = nodeInfo.getNodeTypeName(); + QName[] mixins = nodeInfo.getMixinNames(); + + if (parent == null) { + // parent node was skipped, skip this child node also + parents.push(null); // push null onto stack for skipped node + succeeded = true; + log.debug("skipping node " + nodeName); + return; + } + if (parent.hasChildNodeEntry(nodeName)) { + // a node with that name already exists... + NodeState.ChildNodeEntry entry = + parent.getChildNodeEntry(nodeName, 1); + NodeId idExisting = entry.getId(); + NodeState existing = (NodeState) itemOps.getItemState(idExisting); + NodeDef def = ntReg.getNodeDef(existing.getDefinitionId()); + + if (!def.allowsSameNameSiblings()) { + // existing doesn't allow same-name siblings, + // check for potential conflicts + EffectiveNodeType entExisting = + itemOps.getEffectiveNodeType(existing); + if (def.isProtected() && entExisting.includesNodeType(ntName)) { + // skip protected node + parents.push(null); // push null onto stack for skipped node + succeeded = true; + log.debug("skipping protected node " + + itemOps.safeGetJCRPath(existing.getNodeId())); + return; + } + if (def.isAutoCreated() && entExisting.includesNodeType(ntName)) { + // this node has already been auto-created, + // no need to create it + node = existing; + } else { + throw new ItemExistsException(itemOps.safeGetJCRPath(existing.getNodeId())); + } + } + } + + if (node == null) { + // there's no node with that name... + if (id == null) { + // no potential uuid conflict, always create new node + + NodeDef def = + itemOps.findApplicableNodeDefinition(nodeName, ntName, parent); + if (def.isProtected()) { + // skip protected node + parents.push(null); // push null onto stack for skipped node + succeeded = true; + log.debug("skipping protected node " + nodeName); + return; + } + + if (parent.hasPropertyName(nodeName)) { + /** + * a property with the same name already exists; if this property + * has been imported as well (e.g. through document view import + * where an element can have the same name as one of the attributes + * of its parent element) we have to rename the onflicting property; + * + * see http://issues.apache.org/jira/browse/JCR-61 + */ + PropertyId propId = new PropertyId(parent.getNodeId(), nodeName); + PropertyState conflicting = itemOps.getPropertyState(propId); + if (conflicting.getStatus() == ItemState.STATUS_NEW) { + // assume this property has been imported as well; + // rename conflicting property + // @todo use better reversible escaping scheme to create unique name + QName newName = new QName(nodeName.getNamespaceURI(), nodeName.getLocalName() + "_"); + if (parent.hasPropertyName(newName)) { + newName = new QName(newName.getNamespaceURI(), newName.getLocalName() + "_"); + } + PropertyState newProp = + itemOps.createPropertyState(parent, newName, + conflicting.getType(), conflicting.getValues().length); + newProp.setValues(conflicting.getValues()); + parent.removePropertyName(nodeName); + itemOps.store(parent); + itemOps.destroy(conflicting); + } + } + + // check if new node can be added (check access rights & + // node type constraints only, assume locking & versioning status + // has already been checked on ancestor) + itemOps.checkAddNode(parent, nodeName, ntName, + BatchedItemOperations.CHECK_ACCESS + | BatchedItemOperations.CHECK_CONSTRAINTS); + // do create new node + node = itemOps.createNodeState(parent, nodeName, ntName, mixins, null, def); + } else { + // potential uuid conflict + NodeState conflicting; - NodeState myNode; - if (existing == null) { - myNode = createNode(parent, nodeInfo); - } - else { - myNode = existing; - existing = null; + try { + conflicting = itemOps.getNodeState(id); + } catch (ItemNotFoundException infe) { + conflicting = null; + } + if (conflicting != null) { + // resolve uuid conflict + node = resolveUUIDConflict(parent, conflicting, nodeInfo); + } else { + // create new with given uuid + + NodeDef def = + itemOps.findApplicableNodeDefinition(nodeName, ntName, parent); + if (def.isProtected()) { + // skip protected node + parents.push(null); // push null onto stack for skipped node + succeeded = true; + log.debug("skipping protected node " + nodeName); + return; + } + + // check if new node can be added (check access rights & + // node type constraints only, assume locking & versioning status + // has already been checked on ancestor) + itemOps.checkAddNode(parent, nodeName, ntName, + BatchedItemOperations.CHECK_ACCESS + | BatchedItemOperations.CHECK_CONSTRAINTS); + // do create new node + node = itemOps.createNodeState(parent, nodeName, ntName, mixins, id, def); + } + } + } + + // process properties + + Iterator iter = propInfos.iterator(); + while (iter.hasNext()) { + PropInfo pi = (PropInfo) iter.next(); + pi.apply(node, itemOps, ntReg, refTracker); + } + + // store affected nodes + itemOps.store(node); + itemOps.store(parent); + + // push current node onto stack of parents + parents.push(node); + + succeeded = true; + } finally { + if (!succeeded) { + // update operation failed, cancel all modifications + aborted = true; + itemOps.cancel(); + } } - createProperties(myNode, propInfos); - parents.push(myNode); } /** * {@inheritDoc} */ public void endNode(NodeInfo nodeInfo) throws RepositoryException { - //End of skip mode - if (skipNode != null && skipNode.equals(nodeInfo)) { - skip = false; - skipNode = null; + if (aborted) { + // the import has been aborted, get outta here... return; } - - if (aborted || skip) { + NodeState node = (NodeState) parents.pop(); + if (node == null) { + // node was skipped, nothing to do here return; } - + boolean succeeded = false; try { - NodeState node = (NodeState) parents.pop(); + // check sanity of workspace/session first + wsp.sanityCheck(); - if (!raw) { - this.postProcessNode(node); - } + // post-process node (initialize properties with special semantics etc.) + postProcessNode(node); + + // make sure node is valid according to its definition + itemOps.validate(node); + + // we're done with that node, now store its state itemOps.store(node); - } catch (IllegalStateException e) { - itemOps.cancel(); - aborted = true; + succeeded = true; + } finally { + if (!succeeded) { + // update operation failed, cancel all modifications + aborted = true; + itemOps.cancel(); + } } } @@ -559,54 +554,66 @@ */ public void end() throws RepositoryException { if (aborted) { - itemOps.cancel(); + // the import has been aborted, get outta here... return; } - wsp.sanityCheck(); - /** - * adjust references that refer to uuid's which have been mapped to - * newly gererated uuid's on import - */ - Iterator iter = refTracker.getProcessedReferences(); - while (iter.hasNext()) { - PropertyState prop = (PropertyState) iter.next(); - // being paranoid... - if (prop.getType() != PropertyType.REFERENCE) { - continue; - } - boolean modified = false; - InternalValue[] values = prop.getValues(); - InternalValue[] newVals = new InternalValue[values.length]; - for (int i = 0; i < values.length; i++) { - InternalValue val = values[i]; - UUID original = (UUID) val.internalValue(); - UUID adjusted = refTracker.getMappedUUID(original); - if (adjusted != null) { - newVals[i] = InternalValue.create(adjusted); - modified = true; - } else { - // reference doesn't need adjusting, just copy old value - newVals[i] = val; + boolean succeeded = false; + try { + // check sanity of workspace/session first + wsp.sanityCheck(); + + /** + * adjust references that refer to uuid's which have been mapped to + * newly gererated uuid's on import + */ + Iterator iter = refTracker.getProcessedReferences(); + while (iter.hasNext()) { + PropertyState prop = (PropertyState) iter.next(); + // being paranoid... + if (prop.getType() != PropertyType.REFERENCE) { + continue; + } + boolean modified = false; + InternalValue[] values = prop.getValues(); + InternalValue[] newVals = new InternalValue[values.length]; + for (int i = 0; i < values.length; i++) { + InternalValue val = values[i]; + UUID original = (UUID) val.internalValue(); + UUID adjusted = refTracker.getMappedUUID(original); + if (adjusted != null) { + newVals[i] = InternalValue.create(adjusted); + modified = true; + } else { + // reference doesn't need adjusting, just copy old value + newVals[i] = val; + } + } + if (modified) { + prop.setValues(newVals); + itemOps.store(prop); } } - if (modified) { - prop.setValues(newVals); - itemOps.store(prop); - } - } - refTracker.clear(); + refTracker.clear(); - // make sure import target is valid according to its definition - itemOps.validate(importTarget); + // make sure import target is valid according to its definition + itemOps.validate(importTarget); - // finally store the state of the import target - // (the parent of the imported subtree) - itemOps.store(importTarget); + // finally store the state of the import target + // (the parent of the imported subtree) + itemOps.store(importTarget); + succeeded = true; + } finally { + if (!succeeded) { + // update operation failed, cancel all modifications + aborted = true; + itemOps.cancel(); + } + } - // finish update - itemOps.update(); + if (!aborted) { + // finish update + itemOps.update(); + } } - } -