You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2005/02/21 19:03:35 UTC

svn commit: r154700 [1/2] - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: LocalNamespaceMappings.java NodeImpl.java QName.java SessionImpl.java nodetype/NodeDefImpl.java nodetype/builtin_nodetypes.xml xml/DocViewImportHandler.java xml/ImportHandler.java xml/Importer.java xml/SessionImporter.java xml/SysViewImportHandler.java

Author: stefan
Date: Mon Feb 21 10:03:31 2005
New Revision: 154700

URL: http://svn.apache.org/viewcvs?view=rev&rev=154700
Log:
reimplementing Session.importXML & friends due to spec changes 

Added:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java   (with props)
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java   (with props)
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SessionImporter.java   (with props)
Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/QName.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeDefImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java?view=auto&rev=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java Mon Feb 21 10:03:31 2005
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core;
+
+import org.apache.xerces.util.XMLChar;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.RepositoryException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * <code>LocalNamespaceMappings</code> ...
+ */
+class LocalNamespaceMappings implements NamespaceResolver {
+
+    // the global persistent namespace registry
+    private final NamespaceRegistryImpl nsReg;
+
+    // local prefix/namespace mappings
+    private final HashMap prefixToURI = new HashMap();
+    private final HashMap uriToPrefix = new HashMap();
+
+    // prefixes in global namespace registry hidden by local mappings
+    private Set hiddenPrefixes = new HashSet();
+
+    /**
+     * Constructor
+     *
+     * @param nsReg
+     */
+    LocalNamespaceMappings(NamespaceRegistryImpl nsReg) {
+        this.nsReg = nsReg;
+    }
+
+    /**
+     * Rename a persistently registered namespace URI to the new prefix.
+     *
+     * @param prefix
+     * @param uri
+     * @throws NamespaceException
+     * @throws RepositoryException
+     */
+    void setNamespacePrefix(String prefix, String uri)
+            throws NamespaceException, RepositoryException {
+        if (prefix == null || uri == null) {
+            throw new IllegalArgumentException("prefix/uri can not be null");
+        }
+        if (Constants.NS_EMPTY_PREFIX.equals(prefix)
+                || Constants.NS_DEFAULT_URI.equals(uri)) {
+            throw new NamespaceException("default namespace is reserved and can not be changed");
+        }
+        // special case: prefixes xml*
+        if (prefix.toLowerCase().startsWith(Constants.NS_XML_PREFIX)) {
+            throw new NamespaceException("reserved prefix: " + prefix);
+        }
+        // check if the prefix is a valid XML prefix
+        if (!XMLChar.isValidNCName(prefix)) {
+            throw new NamespaceException("invalid prefix: " + prefix);
+        }
+
+        // check if namespace exists (the following call will
+        // trigger a NamespaceException if it doesn't)
+        String globalPrefix = nsReg.getPrefix(uri);
+
+        // check new prefix for collision
+        String globalURI = null;
+        try {
+            globalURI = nsReg.getURI(prefix);
+        } catch (NamespaceException nse) {
+            // ignore
+        }
+        if (globalURI != null) {
+            // prefix is already mapped in global namespace registry;
+            // check if it is redundant or if it refers to a namespace
+            // that has been locally remapped, thus hiding it
+            if (!hiddenPrefixes.contains(prefix)) {
+                if (uri.equals(globalURI) && prefix.equals(globalPrefix)) {
+                    // redundant mapping, silently ignore
+                    return;
+                }
+                // we don't allow to hide a namespace because we can't
+                // guarantee that there are no references to it
+                // (in names of nodes/properties/node types etc.)
+                throw new NamespaceException(prefix + ": prefix is already mapped to the namespace: " + globalURI);
+            }
+        }
+
+        // check if namespace is already locally mapped
+        String oldPrefix = (String) uriToPrefix.get(uri);
+        if (oldPrefix != null) {
+            if (oldPrefix.equals(prefix)) {
+                // redundant mapping, silently ignore
+                return;
+            }
+            // resurrect hidden global prefix
+            hiddenPrefixes.remove(nsReg.getPrefix(uri));
+            // remove old mapping
+            uriToPrefix.remove(uri);
+            prefixToURI.remove(oldPrefix);
+        }
+
+        // check if prefix is already locally mapped
+        String oldURI = (String) prefixToURI.get(prefix);
+        if (oldURI != null) {
+            // resurrect hidden global prefix
+            hiddenPrefixes.remove(nsReg.getPrefix(oldURI));
+            // remove old mapping
+            uriToPrefix.remove(oldURI);
+            prefixToURI.remove(prefix);
+        }
+
+        if (!prefix.equals(globalPrefix)) {
+            // store new mapping
+            prefixToURI.put(prefix, uri);
+            uriToPrefix.put(uri, prefix);
+            hiddenPrefixes.add(globalPrefix);
+        }
+    }
+
+    /**
+     * Returns all prefixes.
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    String[] getPrefixes() throws RepositoryException {
+        if (prefixToURI.isEmpty()) {
+            // shortcut
+            return nsReg.getPrefixes();
+        }
+
+        HashSet prefixes = new HashSet();
+        // global prefixes
+        String[] globalPrefixes = nsReg.getPrefixes();
+        for (int i = 0; i < globalPrefixes.length; i++) {
+            if (!hiddenPrefixes.contains(globalPrefixes[i])) {
+                prefixes.add(globalPrefixes[i]);
+            }
+        }
+        // local prefixes
+        prefixes.addAll(prefixToURI.keySet());
+
+        return (String[]) prefixes.toArray(new String[prefixes.size()]);
+    }
+
+    //----------------------------------------------------< NamespaceResolver >
+    /**
+     * @see NamespaceResolver#getURI
+     */
+    public String getURI(String prefix) throws NamespaceException {
+        if (prefixToURI.isEmpty()) {
+            // shortcut
+            return nsReg.getURI(prefix);
+        }
+        // check local mappings
+        if (prefixToURI.containsKey(prefix)) {
+            return (String) prefixToURI.get(prefix);
+        }
+
+        // check global mappings
+        if (!hiddenPrefixes.contains(prefix)) {
+            return nsReg.getURI(prefix);
+        }
+
+        throw new NamespaceException(prefix + ": unknown prefix");
+    }
+
+    /**
+     * @see NamespaceResolver#getPrefix
+     */
+    public String getPrefix(String uri) throws NamespaceException {
+        if (prefixToURI.isEmpty()) {
+            // shortcut
+            return nsReg.getPrefix(uri);
+        }
+
+        // check local mappings
+        if (uriToPrefix.containsKey(uri)) {
+            return (String) uriToPrefix.get(uri);
+        }
+
+        // check global mappings
+        return nsReg.getPrefix(uri);
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java Mon Feb 21 10:03:31 2005
@@ -16,24 +16,77 @@
  */
 package org.apache.jackrabbit.core;
 
-import org.apache.jackrabbit.core.nodetype.*;
-import org.apache.jackrabbit.core.state.*;
+import org.apache.jackrabbit.core.nodetype.ChildNodeDef;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeDefId;
+import org.apache.jackrabbit.core.nodetype.NodeDefImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.core.nodetype.PropDefId;
+import org.apache.jackrabbit.core.nodetype.PropertyDefImpl;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeReferencesId;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.util.ChildrenCollectorFilter;
 import org.apache.jackrabbit.core.util.IteratorHelper;
 import org.apache.jackrabbit.core.util.uuid.UUID;
-import org.apache.jackrabbit.core.version.*;
+import org.apache.jackrabbit.core.version.GenericVersionSelector;
+import org.apache.jackrabbit.core.version.InternalFreeze;
+import org.apache.jackrabbit.core.version.InternalFrozenNode;
+import org.apache.jackrabbit.core.version.InternalFrozenVersionHistory;
+import org.apache.jackrabbit.core.version.InternalVersion;
+import org.apache.jackrabbit.core.version.VersionHistoryImpl;
+import org.apache.jackrabbit.core.version.VersionImpl;
+import org.apache.jackrabbit.core.version.VersionSelector;
 import org.apache.log4j.Logger;
 
-import javax.jcr.*;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.ItemVisitor;
+import javax.jcr.MergeException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.ReferenceValue;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
 import javax.jcr.lock.Lock;
 import javax.jcr.lock.LockException;
-import javax.jcr.nodetype.*;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDef;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDef;
 import javax.jcr.version.OnParentVersionAction;
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionException;
 import javax.jcr.version.VersionHistory;
 import java.io.InputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 
 /**
  * <code>NodeImpl</code> implements the <code>Node</code> interface.
@@ -359,7 +412,7 @@
         String parentUUID = ((NodeState) state).getUUID();
 
         // create a new property state
-        PropertyState propState = null;
+        PropertyState propState;
         try {
             propState = stateMgr.createTransientPropertyState(parentUUID, name, ItemState.STATUS_NEW);
             propState.setType(type);
@@ -402,7 +455,7 @@
             throws RepositoryException {
         String parentUUID = ((NodeState) state).getUUID();
         // create a new node state
-        NodeState nodeState = null;
+        NodeState nodeState;
         try {
             if (uuid == null) {
                 uuid = UUID.randomUUID().toString();	// version 4 uuid
@@ -705,7 +758,7 @@
     private void setMixinTypesProperty(Set mixinNames) throws RepositoryException {
         NodeState thisState = (NodeState) state;
         // get or create jcr:mixinTypes property
-        PropertyImpl prop = null;
+        PropertyImpl prop;
         if (thisState.hasPropertyEntry(JCR_MIXINTYPES)) {
             prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), JCR_MIXINTYPES));
         } else {
@@ -838,6 +891,222 @@
     }
 
     /**
+     * Same as {@link Node#addMixin(String)}, but takes a <code>QName</code>
+     * instad of a <code>String</code>.
+     *
+     * @see Node#addMixin(String)
+     */
+    public void addMixin(QName mixinName)
+            throws NoSuchNodeTypeException, VersionException,
+            ConstraintViolationException, LockException, RepositoryException {
+        // check state of this instance
+        sanityCheck();
+
+        // make sure this node is checked-out
+        if (!internalIsCheckedOut()) {
+            String msg = safeGetJCRPath() + ": cannot add a mixin node type to a checked-in node";
+            log.debug(msg);
+            throw new VersionException(msg);
+        }
+
+        // check protected flag
+        if (definition.isProtected()) {
+            String msg = safeGetJCRPath() + ": cannot add a mixin node type to a protected node";
+            log.debug(msg);
+            throw new ConstraintViolationException(msg);
+        }
+
+        NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
+        NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
+        if (!mixin.isMixin()) {
+            throw new RepositoryException(mixinName + ": not a mixin node type");
+        }
+        if (nodeType.isDerivedFrom(mixinName)) {
+            throw new RepositoryException(mixinName + ": already contained in primary node type");
+        }
+
+        // build effective node type of mixin's & primary type in order to detect conflicts
+        NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+        EffectiveNodeType entExisting;
+        try {
+            // existing mixin's
+            HashSet set = new HashSet(((NodeState) state).getMixinTypeNames());
+            // primary type
+            set.add(nodeType.getQName());
+            // build effective node type representing primary type including existing mixin's
+            entExisting = ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+            if (entExisting.includesNodeType(mixinName)) {
+                throw new RepositoryException(mixinName + ": already contained in mixin types");
+            }
+            // add new mixin
+            set.add(mixinName);
+            // try to build new effective node type (will throw in case of conflicts)
+            ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+        } catch (NodeTypeConflictException ntce) {
+            throw new ConstraintViolationException(ntce.getMessage());
+        }
+
+        // do the actual modifications implied by the new mixin;
+        // try to revert the changes in case an excpetion occurs
+        try {
+            // modify the state of this node
+            NodeState thisState = (NodeState) getOrCreateTransientItemState();
+            // add mixin name
+            Set mixins = new HashSet(thisState.getMixinTypeNames());
+            mixins.add(mixinName);
+            thisState.setMixinTypeNames(mixins);
+
+            // set jcr:mixinTypes property
+            setMixinTypesProperty(mixins);
+
+            // add 'auto-create' properties defined in mixin type
+            PropertyDef[] pda = mixin.getAutoCreatePropertyDefs();
+            for (int i = 0; i < pda.length; i++) {
+                PropertyDefImpl pd = (PropertyDefImpl) pda[i];
+                // make sure that the property is not already defined by primary type
+                // or existing mixin's
+                NodeTypeImpl declaringNT = (NodeTypeImpl) pd.getDeclaringNodeType();
+                if (!entExisting.includesNodeType(declaringNT.getQName())) {
+                    createChildProperty(pd.getQName(), pd.getRequiredType(), pd);
+                }
+            }
+
+            // recursively add 'auto-create' child nodes defined in mixin type
+            NodeDef[] nda = mixin.getAutoCreateNodeDefs();
+            for (int i = 0; i < nda.length; i++) {
+                NodeDefImpl nd = (NodeDefImpl) nda[i];
+                // make sure that the child node is not already defined by primary type
+                // or existing mixin's
+                NodeTypeImpl declaringNT = (NodeTypeImpl) nd.getDeclaringNodeType();
+                if (!entExisting.includesNodeType(declaringNT.getQName())) {
+                    createChildNode(nd.getQName(), nd, (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
+                }
+            }
+        } catch (RepositoryException re) {
+            // try to undo the modifications by removing the mixin
+            try {
+                removeMixin(mixinName);
+            } catch (RepositoryException re1) {
+                // silently ignore & fall through
+            }
+            throw re;
+        }
+    }
+
+    /**
+     * Same as {@link Node#removeMixin(String)}, but takes a <code>QName</code>
+     * instad of a <code>String</code>.
+     *
+     * @see Node#removeMixin(String)
+     */
+    public void removeMixin(QName mixinName)
+            throws NoSuchNodeTypeException, VersionException,
+            ConstraintViolationException, LockException, RepositoryException {
+        // check state of this instance
+        sanityCheck();
+
+        // make sure this node is checked-out
+        if (!internalIsCheckedOut()) {
+            String msg = safeGetJCRPath() + ": cannot remove a mixin node type from a checked-in node";
+            log.debug(msg);
+            throw new VersionException(msg);
+        }
+
+        // check protected flag
+        if (definition.isProtected()) {
+            String msg = safeGetJCRPath() + ": cannot remove a mixin node type from a protected node";
+            log.debug(msg);
+            throw new ConstraintViolationException(msg);
+        }
+
+        // check if mixin is assigned
+        if (!((NodeState) state).getMixinTypeNames().contains(mixinName)) {
+            throw new NoSuchNodeTypeException();
+        }
+
+        if (MIX_REFERENCEABLE.equals(mixinName)) {
+            /**
+             * mix:referenceable needs special handling because it has
+             * special semantics:
+             * it can only be removed if there no more references to this node
+             */
+            PropertyIterator iter = getReferences();
+            if (iter.hasNext()) {
+                throw new ConstraintViolationException(mixinName + " can not be removed: the node is being referenced through at least one property of type REFERENCE");
+            }
+        }
+
+        // modify the state of this node
+        NodeState thisState = (NodeState) getOrCreateTransientItemState();
+        // remove mixin name
+        Set mixins = new HashSet(thisState.getMixinTypeNames());
+        mixins.remove(mixinName);
+        thisState.setMixinTypeNames(mixins);
+
+        // set jcr:mixinTypes property
+        setMixinTypesProperty(mixins);
+
+        // build effective node type of remaining mixin's & primary type
+        NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
+        NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+        EffectiveNodeType entRemaining;
+        try {
+            // remaining mixin's
+            HashSet set = new HashSet(mixins);
+            // primary type
+            set.add(nodeType.getQName());
+            // build effective node type representing primary type including remaining mixin's
+            entRemaining = ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+        } catch (NodeTypeConflictException ntce) {
+            throw new ConstraintViolationException(ntce.getMessage());
+        }
+
+        NodeTypeImpl mixin = session.getNodeTypeManager().getNodeType(mixinName);
+
+        // shortcut
+        if (mixin.getChildNodeDefs().length == 0
+                && mixin.getPropertyDefs().length == 0) {
+            // the node type has neither property nor child node definitions,
+            // i.e. we're done
+            return;
+        }
+
+        // walk through properties and child nodes and remove those that have been
+        // defined by the specified mixin type
+
+        // use temp array to avoid ConcurrentModificationException
+        ArrayList tmp = new ArrayList(thisState.getPropertyEntries());
+        Iterator iter = tmp.iterator();
+        while (iter.hasNext()) {
+            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
+            PropertyImpl prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), entry.getName()));
+            // check if property has been defined by mixin type (or one of its supertypes)
+            NodeTypeImpl declaringNT = (NodeTypeImpl) prop.getDefinition().getDeclaringNodeType();
+            if (!entRemaining.includesNodeType(declaringNT.getQName())) {
+                // the remaining effective node type doesn't include the
+                // node type that declared this property, it is thus safe
+                // to remove it
+                removeChildProperty(entry.getName());
+            }
+        }
+        // use temp array to avoid ConcurrentModificationException
+        tmp = new ArrayList(thisState.getChildNodeEntries());
+        iter = tmp.iterator();
+        while (iter.hasNext()) {
+            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+            NodeImpl node = (NodeImpl) itemMgr.getItem(new NodeId(entry.getUUID()));
+            // check if node has been defined by mixin type (or one of its supertypes)
+            NodeTypeImpl declaringNT = (NodeTypeImpl) node.getDefinition().getDeclaringNodeType();
+            if (!entRemaining.includesNodeType(declaringNT.getQName())) {
+                // the remaining effective node type doesn't include the
+                // node type that declared this child node, it is thus safe
+                // to remove it
+                removeChildNode(entry.getName(), entry.getIndex());
+            }
+        }
+    }
+
+    /**
      * Same as {@link Node#isNodeType(String)}, but takes a <code>QName</code>
      * instad of a <code>String</code>.
      *
@@ -1106,20 +1375,30 @@
     }
 
     /**
-     * Same as <code>{@link Node#addNode(String)}</code> except that
-     * this method takes a <code>QName</code> name argument instead of a
-     * <code>String</code>.
-     *
-     * @param nodeName
-     * @return
+     * Same as <code>{@link Node#addNode(String, String)}</code> except that
+     * this method takes <code>QName</code> arguments instead of
+     * <code>String</code>s and has an additional <code>uuid</code> argument.
+     * <p/>
+     * <b>Important Notice:</b> This method is for internal use only! Passing
+     * already assigned uuid's might lead to unexpected results and
+     * data corruption in the worst case.
+     *
+     * @param nodeName     name of the new node
+     * @param nodeTypeName name of the new node's node type or <code>null</code>
+     *                     if it should be determined automatically
+     * @param uuid         uuid of the new node or <code>null</code> if a new
+     *                     uuid should be assigned
+     * @return the newly added node
      * @throws ItemExistsException
+     * @throws NoSuchNodeTypeException
      * @throws VersionException
      * @throws ConstraintViolationException
      * @throws LockException
      * @throws RepositoryException
      */
-    public synchronized NodeImpl addNode(QName nodeName)
-            throws ItemExistsException, VersionException,
+    public synchronized NodeImpl addNode(QName nodeName, QName nodeTypeName,
+                                         String uuid)
+            throws ItemExistsException, NoSuchNodeTypeException, VersionException,
             ConstraintViolationException, LockException, RepositoryException {
         // check state of this instance
         sanityCheck();
@@ -1131,55 +1410,51 @@
             throw new VersionException(msg);
         }
 
-        return internalAddChildNode(nodeName, null);
+        NodeTypeImpl nt = (nodeTypeName == null) ?
+                null : session.getNodeTypeManager().getNodeType(nodeTypeName);
+        return internalAddChildNode(nodeName, nt, uuid);
     }
 
     /**
-     * Same as <code>{@link Node#addNode(String, String)}</code> except that
-     * this method takes a <code>QName</code> arguments instead of a
-     * <code>String</code>s.
+     * Same as <code>{@link Node#setProperty(String, Value[])}</code> except that
+     * this method takes a <code>QName</code> name argument instead of a
+     * <code>String</code>.
      *
-     * @param nodeName
-     * @param nodeTypeName
+     * @param name
+     * @param values
      * @return
-     * @throws ItemExistsException
-     * @throws NoSuchNodeTypeException
+     * @throws ValueFormatException
      * @throws VersionException
-     * @throws ConstraintViolationException
      * @throws LockException
      * @throws RepositoryException
      */
-    public synchronized NodeImpl addNode(QName nodeName, QName nodeTypeName)
-            throws ItemExistsException, NoSuchNodeTypeException, VersionException,
-            ConstraintViolationException, LockException, RepositoryException {
-        // check state of this instance
-        sanityCheck();
-
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = safeGetJCRPath() + ": cannot add node to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
+    public PropertyImpl setProperty(QName name, Value[] values)
+            throws ValueFormatException, VersionException, LockException,
+            RepositoryException {
+        int type;
+        if (values == null || values.length == 0) {
+            type = PropertyType.UNDEFINED;
+        } else {
+            type = values[0].getType();
         }
-
-        NodeTypeImpl nt = session.getNodeTypeManager().getNodeType(nodeTypeName);
-        return internalAddChildNode(nodeName, nt);
+        return setProperty(name, values, type);
     }
 
     /**
-     * Same as <code>{@link Node#setProperty(String, Value[])}</code> except that
-     * this method takes a <code>QName</code> name argument instead of a
+     * Same as <code>{@link Node#setProperty(String, Value[], int)}</code> except
+     * that this method takes a <code>QName</code> name argument instead of a
      * <code>String</code>.
      *
      * @param name
      * @param values
+     * @param type
      * @return
      * @throws ValueFormatException
      * @throws VersionException
      * @throws LockException
      * @throws RepositoryException
      */
-    public PropertyImpl setProperty(QName name, Value[] values)
+    public PropertyImpl setProperty(QName name, Value[] values, int type)
             throws ValueFormatException, VersionException, LockException,
             RepositoryException {
         // check state of this instance
@@ -1192,12 +1467,6 @@
             throw new VersionException(msg);
         }
 
-        int type;
-        if (values == null || values.length == 0) {
-            type = PropertyType.UNDEFINED;
-        } else {
-            type = values[0].getType();
-        }
         BitSet status = new BitSet();
         PropertyImpl prop = getOrCreateProperty(name, type, true, status);
         try {
@@ -2043,23 +2312,6 @@
     public void addMixin(String mixinName)
             throws NoSuchNodeTypeException, VersionException,
             ConstraintViolationException, LockException, RepositoryException {
-        // check state of this instance
-        sanityCheck();
-
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = safeGetJCRPath() + ": cannot add a mixin node type to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag
-        if (definition.isProtected()) {
-            String msg = safeGetJCRPath() + ": cannot add a mixin node type to a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
         QName ntName;
         try {
             ntName = QName.fromJCRName(mixinName, session.getNamespaceResolver());
@@ -2069,81 +2321,7 @@
             throw new RepositoryException("invalid mixin type name: " + mixinName, upe);
         }
 
-        NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
-        NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
-        if (!mixin.isMixin()) {
-            throw new RepositoryException(mixinName + ": not a mixin node type");
-        }
-        if (nodeType.isDerivedFrom(ntName)) {
-            throw new RepositoryException(mixinName + ": already contained in primary node type");
-        }
-
-        // build effective node type of mixin's & primary type in order to detect conflicts
-        NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
-        EffectiveNodeType entExisting;
-        try {
-            // existing mixin's
-            HashSet set = new HashSet(((NodeState) state).getMixinTypeNames());
-            // primary type
-            set.add(nodeType.getQName());
-            // build effective node type representing primary type including existing mixin's
-            entExisting = ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
-            if (entExisting.includesNodeType(ntName)) {
-                throw new RepositoryException(mixinName + ": already contained in mixin types");
-            }
-            // add new mixin
-            set.add(ntName);
-            // try to build new effective node type (will throw in case of conflicts)
-            ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
-        } catch (NodeTypeConflictException ntce) {
-            throw new ConstraintViolationException(ntce.getMessage());
-        }
-
-        // do the actual modifications implied by the new mixin;
-        // try to revert the changes in case an excpetion occurs
-        try {
-            // modify the state of this node
-            NodeState thisState = (NodeState) getOrCreateTransientItemState();
-            // add mixin name
-            Set mixins = new HashSet(thisState.getMixinTypeNames());
-            mixins.add(ntName);
-            thisState.setMixinTypeNames(mixins);
-
-            // set jcr:mixinTypes property
-            setMixinTypesProperty(mixins);
-
-            // add 'auto-create' properties defined in mixin type
-            PropertyDef[] pda = mixin.getAutoCreatePropertyDefs();
-            for (int i = 0; i < pda.length; i++) {
-                PropertyDefImpl pd = (PropertyDefImpl) pda[i];
-                // make sure that the property is not already defined by primary type
-                // or existing mixin's
-                NodeTypeImpl declaringNT = (NodeTypeImpl) pd.getDeclaringNodeType();
-                if (!entExisting.includesNodeType(declaringNT.getQName())) {
-                    createChildProperty(pd.getQName(), pd.getRequiredType(), pd);
-                }
-            }
-
-            // recursively add 'auto-create' child nodes defined in mixin type
-            NodeDef[] nda = mixin.getAutoCreateNodeDefs();
-            for (int i = 0; i < nda.length; i++) {
-                NodeDefImpl nd = (NodeDefImpl) nda[i];
-                // make sure that the child node is not already defined by primary type
-                // or existing mixin's
-                NodeTypeImpl declaringNT = (NodeTypeImpl) nd.getDeclaringNodeType();
-                if (!entExisting.includesNodeType(declaringNT.getQName())) {
-                    createChildNode(nd.getQName(), nd, (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
-                }
-            }
-        } catch (RepositoryException re) {
-            // try to undo the modifications by removing the mixin
-            try {
-                removeMixin(mixinName);
-            } catch (RepositoryException re1) {
-                // silently ignore & fall through
-            }
-            throw re;
-        }
+        addMixin(ntName);
     }
 
     /**
@@ -2152,23 +2330,6 @@
     public void removeMixin(String mixinName)
             throws NoSuchNodeTypeException, VersionException,
             ConstraintViolationException, LockException, RepositoryException {
-        // check state of this instance
-        sanityCheck();
-
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = safeGetJCRPath() + ": cannot remove a mixin node type from a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag
-        if (definition.isProtected()) {
-            String msg = safeGetJCRPath() + ": cannot remove a mixin node type from a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
         QName ntName;
         try {
             ntName = QName.fromJCRName(mixinName, session.getNamespaceResolver());
@@ -2178,91 +2339,7 @@
             throw new RepositoryException("invalid mixin type name: " + mixinName, upe);
         }
 
-        // check if mixin is assigned
-        if (!((NodeState) state).getMixinTypeNames().contains(ntName)) {
-            throw new NoSuchNodeTypeException(mixinName);
-        }
-
-        if (MIX_REFERENCEABLE.equals(ntName)) {
-            /**
-             * mix:referenceable needs special handling because it has
-             * special semantics:
-             * it can only be removed if there no more references to this node
-             */
-            PropertyIterator iter = getReferences();
-            if (iter.hasNext()) {
-                throw new ConstraintViolationException(mixinName + " can not be removed: the node is being referenced through at least one property of type REFERENCE");
-            }
-        }
-
-        // modify the state of this node
-        NodeState thisState = (NodeState) getOrCreateTransientItemState();
-        // remove mixin name
-        Set mixins = new HashSet(thisState.getMixinTypeNames());
-        mixins.remove(ntName);
-        thisState.setMixinTypeNames(mixins);
-
-        // set jcr:mixinTypes property
-        setMixinTypesProperty(mixins);
-
-        // build effective node type of remaining mixin's & primary type
-        NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
-        NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
-        EffectiveNodeType entRemaining;
-        try {
-            // remaining mixin's
-            HashSet set = new HashSet(mixins);
-            // primary type
-            set.add(nodeType.getQName());
-            // build effective node type representing primary type including remaining mixin's
-            entRemaining = ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
-        } catch (NodeTypeConflictException ntce) {
-            throw new ConstraintViolationException(ntce.getMessage());
-        }
-
-        NodeTypeImpl mixin = session.getNodeTypeManager().getNodeType(ntName);
-
-        // shortcut
-        if (mixin.getChildNodeDefs().length == 0
-                && mixin.getPropertyDefs().length == 0) {
-            // the node type has neither property nor child node definitions,
-            // i.e. we're done
-            return;
-        }
-
-        // walk through properties and child nodes and remove those that have been
-        // defined by the specified mixin type
-
-        // use temp array to avoid ConcurrentModificationException
-        ArrayList tmp = new ArrayList(thisState.getPropertyEntries());
-        Iterator iter = tmp.iterator();
-        while (iter.hasNext()) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
-            PropertyImpl prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), entry.getName()));
-            // check if property has been defined by mixin type (or one of its supertypes)
-            NodeTypeImpl declaringNT = (NodeTypeImpl) prop.getDefinition().getDeclaringNodeType();
-            if (!entRemaining.includesNodeType(declaringNT.getQName())) {
-                // the remaining effective node type doesn't include the
-                // node type that declared this property, it is thus safe
-                // to remove it
-                removeChildProperty(entry.getName());
-            }
-        }
-        // use temp array to avoid ConcurrentModificationException
-        tmp = new ArrayList(thisState.getChildNodeEntries());
-        iter = tmp.iterator();
-        while (iter.hasNext()) {
-            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
-            NodeImpl node = (NodeImpl) itemMgr.getItem(new NodeId(entry.getUUID()));
-            // check if node has been defined by mixin type (or one of its supertypes)
-            NodeTypeImpl declaringNT = (NodeTypeImpl) node.getDefinition().getDeclaringNodeType();
-            if (!entRemaining.includesNodeType(declaringNT.getQName())) {
-                // the remaining effective node type doesn't include the
-                // node type that declared this child node, it is thus safe
-                // to remove it
-                removeChildNode(entry.getName(), entry.getIndex());
-            }
-        }
+        removeMixin(ntName);
     }
 
     /**
@@ -3049,11 +3126,7 @@
         // todo: also respect mixing types on creation?
         QName[] mxNames = frozen.getFrozenMixinTypes();
         for (int i = 0; i < mxNames.length; i++) {
-            try {
-                node.addMixin(mxNames[i].toJCRName(session.getNamespaceResolver()));
-            } catch (NoPrefixDeclaredException e) {
-                throw new NoSuchNodeTypeException("Unable to resolve mixin: " + e.toString());
-            }
+            node.addMixin(mxNames[i]);
         }
         return node;
     }
@@ -3097,11 +3170,7 @@
         // todo: also respect mixing types on creation?
         QName[] mxNames = frozen.getFrozenMixinTypes();
         for (int i = 0; i < mxNames.length; i++) {
-            try {
-                node.addMixin(mxNames[i].toJCRName(session.getNamespaceResolver()));
-            } catch (NoPrefixDeclaredException e) {
-                throw new NoSuchNodeTypeException("Unable to resolve mixin: " + e.toString());
-            }
+            node.addMixin(mxNames[i]);
         }
         return node;
     }
@@ -3204,13 +3273,7 @@
                 }
             }
             if (!found) {
-                try {
-                    addMixin(values[i].toJCRName(session.getNamespaceResolver()));
-                } catch (NoPrefixDeclaredException e) {
-                    String msg = "Unable to add mixin for restored node: " + e.getMessage();
-                    log.debug(msg);
-                    throw new RepositoryException(msg);
-                }
+                addMixin(values[i]);
             }
         }
         // remove additional mixins

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/QName.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/QName.java?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/QName.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/QName.java Mon Feb 21 10:03:31 2005
@@ -95,7 +95,23 @@
         if (resolver == null) {
             throw new NullPointerException("resolver must not be null");
         }
-        return internalFromJCRName(rawName, resolver);
+
+        if (rawName == null || rawName.length() == 0) {
+            throw new IllegalNameException("empty name");
+        }
+
+        // parts[0]: prefix
+        // parts[1]: localName
+        String[] parts = parse(rawName);
+
+        String uri;
+        try {
+            uri = resolver.getURI(parts[0]);
+        } catch (NamespaceException nse) {
+            throw new UnknownPrefixException(parts[0]);
+        }
+
+        return new QName(uri, parts[1]);
     }
 
     /**
@@ -143,36 +159,29 @@
      *                              JCR-style name.
      */
     public static void checkFormat(String jcrName) throws IllegalNameException {
-        try {
-            internalFromJCRName(jcrName, null);
-        } catch (UnknownPrefixException e) {
-            // ignore, will never happen
-        }
+        parse(jcrName);
     }
 
     /**
-     * Parses the <code>jcrName</code>, resolves the prefix using the namespace
-     * resolver and returns a new QName instance. this method is also used
-     * internally just to check the format of the given string by passing a
-     * <code>null</code> value as <code>resolver</code>
+     * Parses the <code>jcrName</code> and returns an array of two strings:
+     * the first array element contains the prefix (or empty string),
+     * the second the local name.     
      *
-     * @param rawName  the jcr name to parse
-     * @param resolver the namespace resolver or <code>null</code>
-     * @return a new resolved QName
-     * @throws IllegalNameException
-     * @throws UnknownPrefixException
+     * @param jcrName the name to be parsed
+     * @return An array holding two strings: the first array element contains
+     *         the prefix (or empty string), the second the local name.
+     * @throws IllegalNameException If <code>jcrName</code> is not a valid
+     *                              JCR-style name.
      */
-    public static QName internalFromJCRName(String rawName, NamespaceResolver resolver)
-            throws IllegalNameException, UnknownPrefixException {
-
-        if (rawName == null || rawName.length() == 0) {
+    public static String[] parse(String jcrName) throws IllegalNameException {
+        if (jcrName == null || jcrName.length() == 0) {
             throw new IllegalNameException("empty name");
         }
 
-        String prefix = null;
-        String localName = null;
+        String prefix;
+        String localName;
 
-        Matcher matcher = NAME_PATTERN.matcher(rawName);
+        Matcher matcher = NAME_PATTERN.matcher(jcrName);
         if (matcher.matches()) {
             // check for prefix (group 1)
             if (matcher.group(1) != null) {
@@ -188,23 +197,11 @@
             localName = matcher.group(3);
         } else {
             // illegal syntax for name
-            throw new IllegalNameException("'" + rawName + "' is not a valid name");
+            throw new IllegalNameException("'" + jcrName + "' is not a valid name");
         }
 
-        if (resolver == null) {
-            return null;
-        } else {
-            String uri;
-            try {
-                uri = resolver.getURI(prefix);
-            } catch (NamespaceException nse) {
-                throw new UnknownPrefixException(prefix);
-            }
-
-            return new QName(uri, localName);
-        }
+        return new String[]{prefix, localName};
     }
-
 
     //-------------------------------------------------------< public methods >
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java Mon Feb 21 10:03:31 2005
@@ -30,8 +30,9 @@
 import org.apache.jackrabbit.core.xml.DocViewSAXEventGenerator;
 import org.apache.jackrabbit.core.xml.ImportHandler;
 import org.apache.jackrabbit.core.xml.SysViewSAXEventGenerator;
+import org.apache.jackrabbit.core.xml.SessionImporter;
+import org.apache.jackrabbit.core.xml.Importer;
 import org.apache.log4j.Logger;
-import org.apache.xerces.util.XMLChar;
 import org.apache.xml.serialize.OutputFormat;
 import org.apache.xml.serialize.XMLSerializer;
 import org.xml.sax.ContentHandler;
@@ -40,7 +41,23 @@
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.XMLReaderFactory;
 
-import javax.jcr.*;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.InvalidSerializedDataException;
+import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.LoginException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Workspace;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.version.VersionException;
@@ -49,7 +66,10 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.security.AccessControlException;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
 
 /**
  * A <code>SessionImpl</code> ...
@@ -119,7 +139,7 @@
     /**
      * the transient prefix/namespace mappings with session scope
      */
-    protected final TransientNamespaceMappings nsMappings;
+    protected final LocalNamespaceMappings nsMappings;
 
     /**
      * The version manager for this session
@@ -160,7 +180,7 @@
         } else {
             userId = null;
         }
-        nsMappings = new TransientNamespaceMappings(rep.getNamespaceRegistry());
+        nsMappings = new LocalNamespaceMappings(rep.getNamespaceRegistry());
         ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), getNamespaceResolver());
         String wspName = wspConfig.getName();
         wsp = new WorkspaceImpl(wspConfig, rep.getWorkspaceStateManager(wspName),
@@ -193,7 +213,7 @@
         alive = true;
         this.rep = rep;
         this.userId = userId;
-        nsMappings = new TransientNamespaceMappings(rep.getNamespaceRegistry());
+        nsMappings = new LocalNamespaceMappings(rep.getNamespaceRegistry());
         ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), getNamespaceResolver());
         String wspName = wspConfig.getName();
         wsp = new WorkspaceImpl(wspConfig, rep.getWorkspaceStateManager(wspName),
@@ -874,7 +894,8 @@
             throw new ConstraintViolationException(msg);
         }
 
-        return new ImportHandler(parent, rep.getNamespaceRegistry(), this);
+        SessionImporter importer = new SessionImporter(parent, this, Importer.IMPORT_UUID_CREATE_NEW);
+        return new ImportHandler(importer, getNamespaceResolver(), rep.getNamespaceRegistry());
     }
 
     /**
@@ -932,7 +953,8 @@
                               boolean skipBinary, boolean noRecurse)
             throws InvalidSerializedDataException, IOException,
             PathNotFoundException, RepositoryException {
-        OutputFormat format = new OutputFormat("xml", "UTF-8", true);
+        boolean indenting = true;
+        OutputFormat format = new OutputFormat("xml", "UTF-8", indenting);
         XMLSerializer serializer = new XMLSerializer(out, format);
         try {
             exportDocView(absPath, serializer.asContentHandler(), skipBinary, noRecurse);
@@ -965,7 +987,8 @@
     public void exportSysView(String absPath, OutputStream out,
                               boolean skipBinary, boolean noRecurse)
             throws IOException, PathNotFoundException, RepositoryException {
-        OutputFormat format = new OutputFormat("xml", "UTF-8", true);
+        boolean indenting = true;
+        OutputFormat format = new OutputFormat("xml", "UTF-8", indenting);
         XMLSerializer serializer = new XMLSerializer(out, format);
         try {
             exportSysView(absPath, serializer.asContentHandler(), skipBinary, noRecurse);
@@ -1082,160 +1105,5 @@
     public void removeLockToken(String lt) {
         // @todo implement locking support
         throw new UnsupportedOperationException("Locking not implemented yet.");
-    }
-
-    //--------------------------------------------------------< inner classes >
-    class TransientNamespaceMappings implements NamespaceResolver {
-
-        // the global persistent namespace registry
-        private NamespaceRegistryImpl nsReg;
-
-        // local prefix/namespace mappings
-        private HashMap prefixToURI = new HashMap();
-        private HashMap uriToPrefix = new HashMap();
-
-        // prefixes in global namespace registry hidden by local mappings
-        private Set hiddenPrefixes = new HashSet();
-
-        TransientNamespaceMappings(NamespaceRegistryImpl nsReg) {
-            this.nsReg = nsReg;
-        }
-
-        void setNamespacePrefix(String prefix, String uri)
-                throws NamespaceException, RepositoryException {
-            if (prefix == null || uri == null) {
-                throw new IllegalArgumentException("prefix/uri can not be null");
-            }
-            if (NS_EMPTY_PREFIX.equals(prefix)
-                    || NS_DEFAULT_URI.equals(uri)) {
-                throw new NamespaceException("default namespace is reserved and can not be changed");
-            }
-            // special case: prefixes xml*
-            if (prefix.toLowerCase().startsWith(NS_XML_PREFIX)) {
-                throw new NamespaceException("reserved prefix: " + prefix);
-            }
-            // check if the prefix is a valid XML prefix
-            if (!XMLChar.isValidNCName(prefix)) {
-                throw new NamespaceException("invalid prefix: " + prefix);
-            }
-
-            // check if namespace exists (the following call will
-            // trigger a NamespaceException if it doesn't)
-            String globalPrefix = nsReg.getPrefix(uri);
-
-            // check new prefix for collision
-            String globalURI = null;
-            try {
-                globalURI = nsReg.getURI(prefix);
-            } catch (NamespaceException nse) {
-                // ignore
-            }
-            if (globalURI != null) {
-                // prefix is already mapped in global namespace registry;
-                // check if it is redundant or if it refers to a namespace
-                // that has been locally remapped, thus hiding it
-                if (!hiddenPrefixes.contains(prefix)) {
-                    if (uri.equals(globalURI) && prefix.equals(globalPrefix)) {
-                        // redundant mapping, silently ignore
-                        return;
-                    }
-                    // we don't allow to hide a namespace because we can't
-                    // guarantee that there are no references to it
-                    // (in names of nodes/properties/node types etc.)
-                    throw new NamespaceException(prefix + ": prefix is already mapped to the namespace: " + globalURI);
-                }
-            }
-
-            // check if namespace is already locally mapped
-            String oldPrefix = (String) uriToPrefix.get(uri);
-            if (oldPrefix != null) {
-                if (oldPrefix.equals(prefix)) {
-                    // redundant mapping, silently ignore
-                    return;
-                }
-                // resurrect hidden global prefix
-                hiddenPrefixes.remove(nsReg.getPrefix(uri));
-                // remove old mapping
-                uriToPrefix.remove(uri);
-                prefixToURI.remove(oldPrefix);
-            }
-
-            // check if prefix is already locally mapped
-            String oldURI = (String) prefixToURI.get(prefix);
-            if (oldURI != null) {
-                // resurrect hidden global prefix
-                hiddenPrefixes.remove(nsReg.getPrefix(oldURI));
-                // remove old mapping
-                uriToPrefix.remove(oldURI);
-                prefixToURI.remove(prefix);
-            }
-
-            if (!prefix.equals(globalPrefix)) {
-                // store new mapping
-                prefixToURI.put(prefix, uri);
-                uriToPrefix.put(uri, prefix);
-                hiddenPrefixes.add(globalPrefix);
-            }
-        }
-
-        String[] getPrefixes() throws RepositoryException {
-            if (prefixToURI.isEmpty()) {
-                // shortcut
-                return nsReg.getPrefixes();
-            }
-
-            HashSet prefixes = new HashSet();
-            // global prefixes
-            String[] globalPrefixes = nsReg.getPrefixes();
-            for (int i = 0; i < globalPrefixes.length; i++) {
-                if (!hiddenPrefixes.contains(globalPrefixes[i])) {
-                    prefixes.add(globalPrefixes[i]);
-                }
-            }
-            // local prefixes
-            prefixes.addAll(prefixToURI.keySet());
-
-            return (String[]) prefixes.toArray(new String[prefixes.size()]);
-        }
-
-        //------------------------------------------------< NamespaceResolver >
-        /**
-         * @see NamespaceResolver#getURI
-         */
-        public String getURI(String prefix) throws NamespaceException {
-            if (prefixToURI.isEmpty()) {
-                // shortcut
-                return nsReg.getURI(prefix);
-            }
-            // check local mappings
-            if (prefixToURI.containsKey(prefix)) {
-                return (String) prefixToURI.get(prefix);
-            }
-
-            // check global mappings
-            if (!hiddenPrefixes.contains(prefix)) {
-                return nsReg.getURI(prefix);
-            }
-
-            throw new NamespaceException(prefix + ": unknown prefix");
-        }
-
-        /**
-         * @see NamespaceResolver#getPrefix
-         */
-        public String getPrefix(String uri) throws NamespaceException {
-            if (prefixToURI.isEmpty()) {
-                // shortcut
-                return nsReg.getPrefix(uri);
-            }
-
-            // check local mappings
-            if (uriToPrefix.containsKey(uri)) {
-                return (String) uriToPrefix.get(uri);
-            }
-
-            // check global mappings
-            return nsReg.getPrefix(uri);
-        }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeDefImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeDefImpl.java?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeDefImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeDefImpl.java Mon Feb 21 10:03:31 2005
@@ -57,16 +57,14 @@
      */
     public NodeType getDefaultPrimaryType() {
         QName ntName = nodeDef.getDefaultPrimaryType();
+        if (ntName == null) {
+            return null;
+        }
         try {
-            if (ntName == null) {
-                // return "nt:unstructured"
-                return ntMgr.getNodeType(Constants.NT_UNSTRUCTURED);
-            } else {
-                return ntMgr.getNodeType(ntName);
-            }
+            return ntMgr.getNodeType(ntName);
         } catch (NoSuchNodeTypeException e) {
             // should never get here
-            log.error("default node type does not exist", e);
+            log.error("invalid default node type " + ntName, e);
             return null;
         }
     }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml Mon Feb 21 10:03:31 2005
@@ -336,7 +336,7 @@
             </requiredPrimaryTypes>
         </childNodeDef>
     </nodeType>
-    <!-- internal nodetypes for persistent version manager -->
+    <!-- internal node types for persistent version manager -->
     <nodeType name="rep:versionHistory" isMixin="false" hasOrderableChildNodes="false" primaryItemName="">
         <supertypes>
             <supertype>nt:unstructured</supertype>

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java Mon Feb 21 10:03:31 2005
@@ -16,53 +16,80 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.BaseException;
+import org.apache.jackrabbit.core.Constants;
+import org.apache.jackrabbit.core.IllegalNameException;
+import org.apache.jackrabbit.core.NamespaceResolver;
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.UnknownPrefixException;
+import org.apache.jackrabbit.core.util.ISO9075;
 import org.apache.log4j.Logger;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
+import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.StringValue;
+import javax.jcr.Value;
+import java.util.ArrayList;
 import java.util.Stack;
 
 /**
- * <code>DocViewImportHandler</code>  ...
+ * <code>DocViewImportHandler</code> processes Document View XML SAX events
+ * and 'translates' them into <code>{@link Importer}</code> method calls.
  */
-class DocViewImportHandler extends DefaultHandler {
+class DocViewImportHandler extends DefaultHandler implements Constants {
 
     private static Logger log = Logger.getLogger(DocViewImportHandler.class);
 
-    private Stack parents;
-    private SessionImpl session;
-    // buffer used to merge adjacent character data
-    private StringBuffer text;
-
-    DocViewImportHandler(NodeImpl importTargetNode, SessionImpl session) {
-        this.session = session;
-        parents = new Stack();
+    private final Importer importer;
+    private final NamespaceResolver nsContext;
 
-        parents.push(importTargetNode);
+    /**
+     * stack of NodeInfo instances; an instance is pushed onto the stack
+     * in the startElement method and is popped from the stack in the
+     * endElement method.
+     */
+    private final Stack stack = new Stack();
+    // buffer used to merge adjacent character data
+    private final StringBuffer text = new StringBuffer();
 
-        text = new StringBuffer();
+    DocViewImportHandler(Importer importer, NamespaceResolver nsContext) {
+        this.importer = importer;
+        this.nsContext = nsContext;
     }
 
     /**
-     * Stores character data encountered in <code>{@link #characters(char[], int, int)}</code>
-     * as <code>jcr:xmlcharacters</code> property of <code>jcr:xmltext</code>
-     * child node.
+     * Translates character data encountered in
+     * <code>{@link #characters(char[], int, int)}</code> into a
+     * <code>jcr:xmltext</code> child node with a <code>jcr:xmlcharacters</code>
+     * property.
      *
-     * @param parent
      * @param text
      * @throws SAXException
      */
-    protected void addTextNode(NodeImpl parent, String text) throws SAXException {
+    private void onTextNode(String text)
+            throws SAXException {
+        if (text.trim().length() == 0) {
+            // ignore whitespace-only character data
+            log.debug("ignoring withespace character data: " + text);
+            return;
+        }
         if (text.length() > 0) {
             try {
-                NodeImpl txtNode = (NodeImpl) parent.addNode(Constants.JCR_XMLTEXT);
-                StringValue val = new StringValue(text.toString());
-                txtNode.setProperty(Constants.JCR_XMLCHARACTERS, val);
+                Importer.NodeInfo node =
+                        new Importer.NodeInfo(JCR_XMLTEXT, null, null, null);
+                Value[] values =
+                        new Value[]{new StringValue(text.toString())};
+                ArrayList props = new ArrayList();
+                Importer.PropInfo prop =
+                        new Importer.PropInfo(JCR_XMLCHARACTERS, PropertyType.STRING, values);
+                props.add(prop);
+                // call Importer
+                importer.startNode(node, props, nsContext);
+                importer.endNode(node);
             } catch (RepositoryException re) {
                 throw new SAXException(re);
             }
@@ -71,12 +98,25 @@
 
     //-------------------------------------------------------< ContentHandler >
     /**
+     * @see ContentHandler#startDocument()
+     */
+    public void startDocument() throws SAXException {
+        try {
+            importer.start();
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
+    }
+
+    /**
      * @see ContentHandler#startElement(String, String, String, Attributes)
      */
-    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+    public void startElement(String namespaceURI, String localName,
+                             String qName, Attributes atts)
+            throws SAXException {
         if (text.length() > 0) {
             // there is character data that needs to be added to the current node
-            addTextNode((NodeImpl) parents.peek(), text.toString());
+            onTextNode(text.toString());
             // reset buffer
             text.setLength(0);
         }
@@ -87,20 +127,22 @@
                 nodeName = new QName(namespaceURI, localName);
             } else {
                 try {
-                    nodeName = QName.fromJCRName(qName, session.getNamespaceResolver());
+                    nodeName = QName.fromJCRName(qName, nsContext);
                 } catch (IllegalNameException ine) {
                     throw new SAXException("illegal node name: " + qName, ine);
                 } catch (UnknownPrefixException upe) {
                     throw new SAXException("illegal node name: " + qName, upe);
                 }
             }
-
-            // @todo how should 'system' properties be handled in document view (e.g. jcr:primaryType,jcr:mixinTypes, jcr:uuid)?
-            NodeImpl currentParent = (NodeImpl) parents.peek();
-            currentParent = (NodeImpl) currentParent.addNode(nodeName, Constants.NT_UNSTRUCTURED);
-            parents.push(currentParent);
+            // decode node name
+            nodeName = ISO9075.decode(nodeName);
 
             // properties
+            String uuid = null;
+            QName nodeTypeName = null;
+            QName[] mixinTypes = null;
+
+            ArrayList props = new ArrayList(atts.getLength());
             for (int i = 0; i < atts.getLength(); i++) {
                 if (atts.getQName(i).startsWith("xml:")) {
                     // skipping xml:space, xml:lang, etc.
@@ -112,16 +154,58 @@
                     propName = new QName(atts.getURI(i), atts.getLocalName(i));
                 } else {
                     try {
-                        propName = QName.fromJCRName(atts.getQName(i), session.getNamespaceResolver());
+                        propName = QName.fromJCRName(atts.getQName(i), nsContext);
                     } catch (IllegalNameException ine) {
                         throw new SAXException("illegal property name: " + atts.getQName(i), ine);
                     } catch (UnknownPrefixException upe) {
                         throw new SAXException("illegal property name: " + atts.getQName(i), upe);
                     }
                 }
-                StringValue val = new StringValue(atts.getValue(i));
-                currentParent.setProperty(propName, val);
+                // decode property name
+                propName = ISO9075.decode(propName);
+
+                // value(s)
+                String attrValue = atts.getValue(i);
+                Value[] propValues;
+/*
+                // @todo should attribute value be interpreted as LIST type (i.e. multi-valued property)?
+                String[] strings = Text.explode(attrValue, ' ', true);
+                propValues = new Value[strings.length];
+                for (int j = 0; j < strings.length; j++) {
+                    // decode encoded blanks in value
+                    strings[j] = Text.replace(strings[j], "_x0020_", " ");
+                    propValues[j] = new StringValue(strings[j]);
+                }
+*/
+                if (propName.equals(JCR_PRIMARYTYPE)) {
+                    // jcr:primaryType
+                    try {
+                        nodeTypeName = QName.fromJCRName(attrValue, nsContext);
+                    } catch (BaseException be) {
+                        throw new SAXException("illegal jcr:primaryType value: " + attrValue, be);
+                    }
+                } else if (propName.equals(JCR_MIXINTYPES)) {
+                    // jcr:mixinTypes
+                    try {
+                        mixinTypes = new QName[]{QName.fromJCRName(attrValue, nsContext)};
+                    } catch (BaseException be) {
+                        throw new SAXException("illegal jcr:mixinTypes value: " + attrValue, be);
+                    }
+                } else if (propName.equals(JCR_UUID)) {
+                    // jcr:uuid
+                    uuid = attrValue;
+                } else {
+                    propValues = new Value[]{new StringValue(atts.getValue(i))};
+                    props.add(new Importer.PropInfo(propName, PropertyType.STRING, propValues));
+                }
             }
+
+            Importer.NodeInfo nodeInfo =
+                    new Importer.NodeInfo(nodeName, nodeTypeName, mixinTypes, uuid);
+            // all information has been collected, now delegate to importer
+            importer.startNode(nodeInfo, props, nsContext);
+            // push current node data onto stack
+            stack.push(nodeInfo);
         } catch (RepositoryException re) {
             throw new SAXException(re);
         }
@@ -144,10 +228,29 @@
     public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
         if (text.length() > 0) {
             // there is character data that needs to be added to the current node
-            addTextNode((NodeImpl) parents.peek(), text.toString());
+            onTextNode(text.toString());
             // reset buffer
             text.setLength(0);
         }
-        parents.pop();
+        Importer.NodeInfo node = (Importer.NodeInfo) stack.peek();
+        try {
+            // call Importer
+            importer.endNode(node);
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
+        // we're done with this node, pop it from stack
+        stack.pop();
+    }
+
+    /**
+     * @see ContentHandler#endDocument()
+     */
+    public void endDocument() throws SAXException {
+        try {
+            importer.end();
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java?view=diff&r1=154699&r2=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java Mon Feb 21 10:03:31 2005
@@ -16,39 +16,64 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.BaseException;
+import org.apache.jackrabbit.core.Constants;
+import org.apache.jackrabbit.core.NamespaceRegistryImpl;
+import org.apache.jackrabbit.core.NamespaceResolver;
+import org.apache.jackrabbit.core.QName;
 import org.apache.log4j.Logger;
-import org.xml.sax.*;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.NamespaceSupport;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
 
 /**
  * An <code>ImportHandler</code> instance can be used to import serialized
- * data in System View XML or Document View XML. The actual task of importing
- * is delegated to specialized <code>ContentHandler</code>s (i.e.
- * <code>SysViewImportHandler</code> and <code>DocViewImportHandler</code>).
+ * data in System View XML or Document View XML. Processing of the XML is handled
+ * by specialized <code>ContentHandler</code>s (i.e. <code>SysViewImportHandler</code>
+ * and <code>DocViewImportHandler</code>).
+ * <p/>
+ * The actual task of importing though is delegated to the implementation of
+ * the <code>{@link Importer}</code> interface.
  */
 public class ImportHandler extends DefaultHandler {
 
     private static Logger log = Logger.getLogger(ImportHandler.class);
 
+    protected final Importer importer;
+    protected final NamespaceRegistryImpl nsReg;
+    protected final NamespaceResolver nsResolver;
+
     protected Locator locator;
     protected ContentHandler targetHandler;
-
-    protected SessionImpl session;
-    protected NodeImpl importTargetNode;
-    protected NamespaceRegistryImpl nsReg;
     protected boolean systemViewXML;
     protected boolean initialized;
 
-    public ImportHandler(NodeImpl importTargetNode,
-                         NamespaceRegistryImpl nsReg,
-                         SessionImpl session) {
-        this.importTargetNode = importTargetNode;
-        this.session = session;
+    protected final NamespaceContext nsContext;
+
+    /**
+     * this flag is used to determine whether a namespace context needs to be
+     * started in the startElement event or if the namespace context has already
+     * been started in a preceeding startPrefixMapping event;
+     * the flag is set per element in the first startPrefixMapping event and is
+     * cleared again in the following startElement event;
+     */
+    protected boolean nsContextStarted;
+
+    public ImportHandler(Importer importer, NamespaceResolver nsResolver,
+                         NamespaceRegistryImpl nsReg) {
+        this.importer = importer;
+        this.nsResolver = nsResolver;
         this.nsReg = nsReg;
+
+        nsContext = new NamespaceContext();
     }
 
     //---------------------------------------------------------< ErrorHandler >
@@ -91,6 +116,24 @@
         systemViewXML = false;
         initialized = false;
         targetHandler = null;
+
+        /**
+         * start initial context containing existing mappings reflected
+         * by nsResolver
+         */
+        nsContext.reset();
+        nsContext.pushContext();
+        try {
+            String[] uris = nsReg.getURIs();
+            for (int i = 0; i < uris.length; i++) {
+                nsContext.declarePrefix(nsResolver.getPrefix(uris[i]), uris[i]);
+            }
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
+
+        // initialize flag
+        nsContextStarted = false;
     }
 
     /**
@@ -99,6 +142,8 @@
     public void endDocument() throws SAXException {
         // delegate to target handler
         targetHandler.endDocument();
+        // cleanup
+        nsContext.reset();
     }
 
     /**
@@ -106,39 +151,49 @@
      */
     public void startPrefixMapping(String prefix, String uri)
             throws SAXException {
+        // check if new context needs to be started
+        if (!nsContextStarted) {
+            // entering new namespace context
+            nsContext.pushContext();
+            nsContextStarted = true;
+        }
+
         try {
-            String oldPrefix = session.getNamespacePrefix(uri);
-            // namespace is already registered; check prefix
-            if (!"".equals(prefix) && !oldPrefix.equals(prefix)) {
-                /**
-                 * namespace is mapped to different prefix;
-                 * try to remap it to given prefix
-                 */
-                try {
-                    session.setNamespacePrefix(prefix, uri);
-                } catch (RepositoryException re) {
-                    throw new SAXException("failed to remap namespace " + uri
-                            + " to prefix " + prefix, re);
-                }
-            }
+            // this will trigger NamespaceException if namespace is unknown
+            nsContext.getPrefix(uri);
         } catch (NamespaceException nse) {
-            // namespace is not yet registered, try to register it
+            // namespace is not yet registered ...
+            String newPrefix;
             if ("".equals(prefix)) {
                 /**
-                 * the xml document specifies a default namespace (i.e. an empty prefix);
-                 * we need to create a random prefix as the empty prefix is reserved
-                 * according to the JCR spec.
+                 * the xml document specifies a default namespace
+                 * (i.e. an empty prefix); we need to create a random
+                 * prefix as the empty prefix is reserved according
+                 * to the JCR spec.
                  */
-                prefix = nsReg.getUniquePrefix(uri);
+                newPrefix = nsReg.getUniquePrefix(uri);
+            } else {
+                newPrefix = prefix;
             }
+            // register new namespace
             try {
-                nsReg.registerNamespace(prefix, uri);
+                nsReg.registerNamespace(newPrefix, uri);
             } catch (RepositoryException re) {
-                throw new SAXException("failed to register namespace " + uri + " with prefix " + prefix, re);
+                throw new SAXException(re);
             }
-        } catch (RepositoryException re) {
-            throw new SAXException("failed to check prefix for namespace " + uri, re);
         }
+        // map namespace in this context to given prefix
+        nsContext.declarePrefix(prefix, uri);
+    }
+
+    /**
+     * @see ContentHandler#endPrefixMapping(String)
+     */
+    public void endPrefixMapping(String prefix) throws SAXException {
+        /**
+         * nothing to do here as namespace context has already been popped
+         * in endElement event
+         */
     }
 
     /**
@@ -146,6 +201,16 @@
      */
     public void startElement(String namespaceURI, String localName, String qName,
                              Attributes atts) throws SAXException {
+        // check if new context needs to be started
+        if (!nsContextStarted) {
+            // there hasn't been a preceeding startPrefixMapping event
+            // so enter new namespace context
+            nsContext.pushContext();
+        } else {
+            // reset flag
+            nsContextStarted = false;
+        }
+
         if (!initialized) {
             // the namespace of the first element determines the type of XML
             // (system view/document view)
@@ -154,7 +219,7 @@
                 nsURI = namespaceURI;
             } else {
                 try {
-                    nsURI = QName.fromJCRName(qName, session.getNamespaceResolver()).getNamespaceURI();
+                    nsURI = QName.fromJCRName(qName, nsResolver).getNamespaceURI();
                 } catch (BaseException e) {
                     // should never happen...
                     String msg = "internal error: failed to parse/resolve element name " + qName;
@@ -165,9 +230,9 @@
             systemViewXML = Constants.NS_SV_URI.equals(nsURI);
 
             if (systemViewXML) {
-                targetHandler = new SysViewImportHandler(importTargetNode, session);
+                targetHandler = new SysViewImportHandler(importer, nsContext);
             } else {
-                targetHandler = new DocViewImportHandler(importTargetNode, session);
+                targetHandler = new DocViewImportHandler(importer, nsContext);
             }
             targetHandler.startDocument();
             initialized = true;
@@ -190,6 +255,9 @@
      */
     public void endElement(String namespaceURI, String localName, String qName)
             throws SAXException {
+        // leaving element, pop namespace context
+        nsContext.popContext();
+
         // delegate to target handler
         targetHandler.endElement(namespaceURI, localName, qName);
     }
@@ -199,5 +267,86 @@
      */
     public void setDocumentLocator(Locator locator) {
         this.locator = locator;
+    }
+
+    //--------------------------------------------------------< inner classes >
+    class NamespaceContext implements NamespaceResolver {
+
+        private final NamespaceSupport nsContext;
+
+        /**
+         * NamespaceSupport doesn't accept "" as default uri;
+         * internally we're using " " instead
+         */
+        private static final String DUMMY_DEFAULT_URI = " ";
+        private static final String DEFAULT_URI = Constants.NS_DEFAULT_URI;
+
+        private static final String EMPTY_PREFIX = "";
+
+        NamespaceContext() {
+            nsContext = new NamespaceSupport();
+        }
+
+        /**
+         * @see NamespaceSupport#popContext()
+         */
+        void popContext() {
+            nsContext.popContext();
+        }
+
+        /**
+         * @see NamespaceSupport#pushContext()
+         */
+        void pushContext() {
+            nsContext.pushContext();
+        }
+
+        /**
+         * @see NamespaceSupport#reset()
+         */
+        void reset() {
+            nsContext.reset();
+        }
+
+        /**
+         * @see NamespaceSupport#declarePrefix(String, String)
+         */
+        boolean declarePrefix(String prefix, String uri) {
+            uri = DEFAULT_URI.equals(uri) ? DUMMY_DEFAULT_URI : uri;
+            return nsContext.declarePrefix(prefix, uri);
+        }
+
+        //------------------------------------------------< NamespaceResolver >
+        /**
+         * @see NamespaceResolver#getURI(String)
+         */
+        public String getURI(String prefix) throws NamespaceException {
+            String uri = nsContext.getURI(prefix);
+            if (uri == null) {
+                throw new NamespaceException("unknown prefix");
+            }
+            return DUMMY_DEFAULT_URI.equals(uri) ? DEFAULT_URI : uri;
+        }
+
+        /**
+         * @see NamespaceResolver#getPrefix(String)
+         */
+        public String getPrefix(String uri) throws NamespaceException {
+            uri = DEFAULT_URI.equals(uri) ? DUMMY_DEFAULT_URI : uri;
+            String prefix = nsContext.getPrefix(uri);
+            if (prefix == null) {
+                /**
+                 * NamespaceSupport#getPrefix will never return the empty
+                 * (default) prefix; we have to do a reverse-lookup to check
+                 * whether it's the current default namespace
+                 */
+                if (uri.equals(nsContext.getURI(EMPTY_PREFIX))) {
+                    return EMPTY_PREFIX;
+                }
+                throw new NamespaceException("unknown uri");
+            }
+            return prefix;
+        }
+
     }
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java?view=auto&rev=154700
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java Mon Feb 21 10:03:31 2005
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+  *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.xml;
+
+import org.apache.jackrabbit.core.NamespaceResolver;
+import org.apache.jackrabbit.core.QName;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.Workspace;
+import java.util.List;
+
+/**
+ * The <code>Importer</code> interface ...
+ */
+public interface Importer {
+
+    public static final int IMPORT_UUID_CREATE_NEW = Workspace.IMPORT_UUID_CREATE_NEW;
+    public static final int IMPORT_UUID_COLLISION_REMOVE_EXISTING = Workspace.IMPORT_UUID_COLLISION_REMOVE_EXISTING;
+    public static final int IMPORT_UUID_COLLISION_REPLACE_EXISTING = Workspace.IMPORT_UUID_COLLISION_REPLACE_EXISTING;
+    public static final int IMPORT_UUID_COLLISION_THROW = Workspace.IMPORT_UUID_COLLISION_THROW;
+
+    /**
+     * @throws RepositoryException
+     */
+    public void start() throws RepositoryException;
+
+    /**
+     * @param nodeInfo
+     * @param propInfos list of <code>PropInfo</code> instances
+     * @param nsContext prefix mappings of current context
+     * @throws RepositoryException
+     */
+    public void startNode(NodeInfo nodeInfo, List propInfos,
+                          NamespaceResolver nsContext) throws RepositoryException;
+
+    /**
+     * @param nodeInfo
+     * @throws RepositoryException
+     */
+    public void endNode(NodeInfo nodeInfo) throws RepositoryException;
+
+    /**
+     * @throws RepositoryException
+     */
+    public void end() throws RepositoryException;
+
+    //--------------------------------------------------------< inner classes >
+    public static class NodeInfo {
+        private QName name;
+        private QName nodeTypeName;
+        private QName[] mixinNames;
+        private String uuid;
+
+        public NodeInfo() {
+        }
+
+        public NodeInfo(QName name, QName nodeTypeName, QName[] mixinNames,
+                        String uuid) {
+            this.name = name;
+            this.nodeTypeName = nodeTypeName;
+            this.mixinNames = mixinNames;
+            this.uuid = uuid;
+        }
+
+        public void setName(QName name) {
+            this.name = name;
+        }
+
+        public QName getName() {
+            return name;
+        }
+
+        public void setNodeTypeName(QName nodeTypeName) {
+            this.nodeTypeName = nodeTypeName;
+        }
+
+        public QName getNodeTypeName() {
+            return nodeTypeName;
+        }
+
+        public void setMixinNames(QName[] mixinNames) {
+            this.mixinNames = mixinNames;
+        }
+
+        public QName[] getMixinNames() {
+            return mixinNames;
+        }
+
+        public void setUUID(String uuid) {
+            this.uuid = uuid;
+        }
+
+        public String getUUID() {
+            return uuid;
+        }
+    }
+
+    public static class PropInfo {
+        private QName name;
+        private int type;
+        private Value[] values;
+
+        public PropInfo() {
+        }
+
+        public PropInfo(QName name, int type, Value[] values) {
+            this.name = name;
+            this.type = type;
+            this.values = values;
+        }
+
+        public void setName(QName name) {
+            this.name = name;
+        }
+
+        public QName getName() {
+            return name;
+        }
+
+        public void setType(int type) {
+            this.type = type;
+        }
+
+        public int getType() {
+            return type;
+        }
+
+        public void setValues(Value[] values) {
+            this.values = values;
+        }
+
+        public Value[] getValues() {
+            return values;
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java
------------------------------------------------------------------------------
    svn:eol-style = native