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 2006/10/18 13:30:51 UTC

svn commit: r465218 - /jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java

Author: jukka
Date: Wed Oct 18 04:30:50 2006
New Revision: 465218

URL: http://svn.apache.org/viewvc?view=rev&rev=465218
Log:
JCR-569: Applied the WorkspaceImporter refactoring patch from Nicolas Toper.

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=465218&r1=465217&r2=465218
==============================================================================
--- 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 Wed Oct 18 04:30:50 2006
@@ -16,6 +16,23 @@
  */
 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;
@@ -39,36 +56,23 @@
 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;
-
 /**
- * <code>WorkspaceImporter</code> ...
+ * WorkspaceImporter. It imports the content submitted to it
+ * by the Content Handler
+ *
  */
 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;
 
-    private boolean aborted;
+    //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 Stack parents;
 
     /**
@@ -77,12 +81,31 @@
      */
     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;
+
     /**
-     * Creates a new <code>WorkspaceImporter</code> instance.
+     * 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 <code>sWorkspaceImporter</code> instance.
      *
      * @param parentPath   target path where to add the imported subtree
-     * @param wsp
-     * @param ntReg
+     * @param wsp the workspace we want to import content to
+     * @param ntReg the NodeTypeRegistry of the repository
      * @param uuidBehavior flag that governs how incoming UUIDs are handled
      * @throws PathNotFoundException        if no node exists at
      *                                      <code>parentPath</code> or if the
@@ -98,108 +121,195 @@
      * @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();
 
-        // perform preliminary checks
+        this.hierMgr = wsp.getHierarchyManager();
+        //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);
     }
 
     /**
-     * @param parent
-     * @param conflicting
-     * @param nodeInfo
-     * @return
-     * @throws RepositoryException
+     * 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.
+     * <br/>
+     * 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
      */
-    protected NodeState resolveUUIDConflict(NodeState parent,
-                                            NodeState conflicting,
-                                            NodeInfo nodeInfo)
-            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;
+                }
 
-        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 (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()));
+                }
             }
-        } 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);
+        }
+
+        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() + "_");
                 }
-            } 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);
+                PropertyState newProp =
+                    itemOps.createPropertyState(parent, newName,
+                            conflicting.getType(), conflicting.getValues().length);
+                newProp.setValues(conflicting.getValues());
+                parent.removePropertyName(nodeName);
+                itemOps.store(parent);
+                itemOps.destroy(conflicting);
             }
-            // 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);
+        }
 
-            // 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);
+        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;
+
+        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 {
             // do create new node
-            node = itemOps.createNodeState(parent, nodeInfo.getName(),
-                    nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(),
-                    nodeInfo.getId());
-        } else if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING) {
+            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:
             NodeId parentId = conflicting.getParentId();
             if (parentId == null) {
                 String msg = "root node cannot be replaced";
@@ -225,34 +335,83 @@
                     | BatchedItemOperations.CHECK_CONSTRAINTS);
             // do remove conflicting (recursive)
             itemOps.removeNodeState(conflicting);
-            // create new with given uuid at same location as conflicting:
-            // check if new node can be added at other location
+            // 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
             // (access rights, node type constraints, locking & versioning status)
-            itemOps.checkAddNode(parent, nodeInfo.getName(),
-                    nodeInfo.getNodeTypeName(),
+            itemOps.checkRemoveNode(conflicting,
                     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());
-        } else {
-            String msg = "unknown uuidBehavior: " + uuidBehavior;
+            break;
+
+        case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
+            String msg = "a node with uuid " + nodeInfo.getId()
+            + " already exists!";
             log.debug(msg);
-            throw new RepositoryException(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.
+        }
         return node;
     }
 
     /**
+     * @return true if skip mode is on.
+     */
+    protected boolean isSkipped() {
+        return skip;
+    }
+
+    /**
      * Post-process imported node (initialize properties with special
      * semantics etc.)
      *
-     * @param node
-     * @throws RepositoryException
+     * @param node NodeState to postprocess
+     * @throws RepositoryException if issue when postprocessing a node
      */
     protected void postProcessNode(NodeState node) throws RepositoryException {
         /**
@@ -319,6 +478,7 @@
         }
     }
 
+
     //-------------------------------------------------------------< Importer >
     /**
      * {@inheritDoc}
@@ -339,213 +499,58 @@
      * {@inheritDoc}
      */
     public void startNode(NodeInfo nodeInfo, List propInfos)
-            throws RepositoryException {
+    throws RepositoryException {
         if (aborted) {
-            // the import has been aborted, get outta here...
             return;
         }
 
-        boolean succeeded = false;
-        NodeState parent;
-        try {
-            // check sanity of workspace/session first
-            wsp.sanityCheck();
-
-            parent = (NodeState) parents.peek();
+        NodeState parent = (NodeState) parents.peek();
 
-            // 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;
-
-                    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);
+        if (raw && !checkNode(parent, nodeInfo, propInfos)) {
+            skip = true;
+        }
 
-            // push current node onto stack of parents
-            parents.push(node);
+        if (skip) {
+            return;
+        }
 
-            succeeded = true;
-        } finally {
-            if (!succeeded) {
-                // update operation failed, cancel all modifications
-                aborted = true;
-                itemOps.cancel();
-            }
+        NodeState myNode;
+        if (existing == null) {
+            myNode = createNode(parent, nodeInfo);
+        }
+        else {
+            myNode = existing;
+            existing = null;
         }
+        createProperties(myNode, propInfos);
+        parents.push(myNode);
     }
 
     /**
      * {@inheritDoc}
      */
     public void endNode(NodeInfo nodeInfo) throws RepositoryException {
-        if (aborted) {
-            // the import has been aborted, get outta here...
+        //End of skip mode
+        if (skipNode != null && skipNode.equals(nodeInfo)) {
+            skip = false;
+            skipNode = null;
             return;
         }
-        NodeState node = (NodeState) parents.pop();
-        if (node == null) {
-            // node was skipped, nothing to do here
+
+        if (aborted || skip) {
             return;
         }
-        boolean succeeded = false;
-        try {
-            // check sanity of workspace/session first
-            wsp.sanityCheck();
-
-            // post-process node (initialize properties with special semantics etc.)
-            postProcessNode(node);
 
-            // make sure node is valid according to its definition
-            itemOps.validate(node);
+        try {
+            NodeState node = (NodeState) parents.pop();
 
-            // we're done with that node, now store its state
-            itemOps.store(node);
-            succeeded = true;
-        } finally {
-            if (!succeeded) {
-                // update operation failed, cancel all modifications
-                aborted = true;
-                itemOps.cancel();
+            if (!raw) {
+                this.postProcessNode(node);
             }
+            itemOps.store(node);
+        } catch (IllegalStateException e) {
+            itemOps.cancel();
+            aborted = true;
         }
     }
 
@@ -554,66 +559,54 @@
      */
     public void end() throws RepositoryException {
         if (aborted) {
-            // the import has been aborted, get outta here...
+            itemOps.cancel();
             return;
         }
 
-        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);
+        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;
                 }
             }
-            refTracker.clear();
-
-            // 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);
-            succeeded = true;
-        } finally {
-            if (!succeeded) {
-                // update operation failed, cancel all modifications
-                aborted = true;
-                itemOps.cancel();
+            if (modified) {
+                prop.setValues(newVals);
+                itemOps.store(prop);
             }
         }
+        refTracker.clear();
 
-        if (!aborted) {
-            // finish update
-            itemOps.update();
-        }
+        // 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);
+
+        // finish update
+        itemOps.update();
     }
+
 }
+