You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/07/12 15:33:27 UTC

svn commit: r421270 [9/23] - in /jackrabbit/trunk/contrib/spi: ./ commons/ commons/src/ commons/src/main/ commons/src/main/java/ commons/src/main/java/org/ commons/src/main/java/org/apache/ commons/src/main/java/org/apache/jackrabbit/ commons/src/main/...

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeTypeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeTypeImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeTypeImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeTypeImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,1062 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.spi.QItemDefinition;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.PropertyType;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Map;
+
+/**
+ * An <code>EffectiveNodeType</code> represents one or more
+ * <code>NodeType</code>s as one 'effective' node type where inheritance
+ * is resolved.
+ * <p/>
+ * Instances of <code>EffectiveNodeType</code> are immutable.
+ */
+// DIFF JR: extract interface
+// DIFF JR: rearrangement of methods
+public class EffectiveNodeTypeImpl implements Cloneable, EffectiveNodeType {
+    private static Logger log = LoggerFactory.getLogger(EffectiveNodeTypeImpl.class);
+
+    // node type registry
+    private final NodeTypeRegistry ntReg;
+
+    // list of explicitly aggregated {i.e. merged) node types
+    private final TreeSet mergedNodeTypes;
+    // list of implicitly aggregated {through inheritance) node types
+    private final TreeSet inheritedNodeTypes;
+    // list of all either explicitly (through aggregation) or implicitly
+    // (through inheritance) included node types.
+    private final TreeSet allNodeTypes;
+    // map of named item definitions (maps name to list of definitions)
+    private final HashMap namedItemDefs;
+    // list of unnamed item definitions (i.e. residual definitions)
+    private final ArrayList unnamedItemDefs;
+
+    /**
+     * private constructor.
+     */
+    private EffectiveNodeTypeImpl(NodeTypeRegistry ntReg) {
+        this.ntReg = ntReg;
+        mergedNodeTypes = new TreeSet();
+        inheritedNodeTypes = new TreeSet();
+        allNodeTypes = new TreeSet();
+        namedItemDefs = new HashMap();
+        unnamedItemDefs = new ArrayList();
+    }
+
+    // DIFF JR: remove create method that takes ntName instead of definition
+
+    /**
+     * Factory method: creates an effective node type
+     * representation of a node type definition. Whereas all referenced
+     * node types must exist (i.e. must be registered), the definition itself
+     * is not required to be registered.
+     *
+     * @param ntReg
+     * @param ntd
+     * @param ntdMap
+     * @return
+     * @throws NodeTypeConflictException
+     * @throws NoSuchNodeTypeException
+     */
+    static EffectiveNodeTypeImpl create(NodeTypeRegistry ntReg, QNodeTypeDefinition ntd, Map ntdMap)
+            throws NodeTypeConflictException, NoSuchNodeTypeException {
+        // create empty effective node type instance
+        EffectiveNodeTypeImpl ent = new EffectiveNodeTypeImpl(ntReg);
+        QName ntName = ntd.getQName();
+
+        // prepare new instance
+        ent.mergedNodeTypes.add(ntName);
+        ent.allNodeTypes.add(ntName);
+
+        // map of all item definitions (maps id to definition)
+        // used to effectively detect ambiguous child definitions where
+        // ambiguity is defined in terms of definition identity
+        Set itemDefIds = new HashSet();
+
+        QNodeDefinition[] cnda = ntd.getChildNodeDefs();
+        for (int i = 0; i < cnda.length; i++) {
+            // check if child node definition would be ambiguous within
+            // this node type definition
+            if (itemDefIds.contains(cnda[i])) {
+                // conflict
+                String msg;
+                if (cnda[i].definesResidual()) {
+                    msg = ntName + " contains ambiguous residual child node definitions";
+                } else {
+                    msg = ntName + " contains ambiguous definitions for child node named "
+                            + cnda[i].getQName();
+                }
+                log.debug(msg);
+                throw new NodeTypeConflictException(msg);
+            } else {
+                itemDefIds.add(cnda[i]);
+            }
+            if (cnda[i].definesResidual()) {
+                // residual node definition
+                ent.unnamedItemDefs.add(cnda[i]);
+            } else {
+                // named node definition
+                QName name = cnda[i].getQName();
+                List defs = (List) ent.namedItemDefs.get(name);
+                if (defs == null) {
+                    defs = new ArrayList();
+                    ent.namedItemDefs.put(name, defs);
+                }
+                if (defs.size() > 0) {
+                    /**
+                     * there already exists at least one definition with that
+                     * name; make sure none of them is auto-create
+                     */
+                    for (int j = 0; j < defs.size(); j++) {
+                        QItemDefinition qDef = (QItemDefinition) defs.get(j);
+                        if (cnda[i].isAutoCreated() || qDef.isAutoCreated()) {
+                            // conflict
+                            String msg = "There are more than one 'auto-create' item definitions for '"
+                                    + name + "' in node type '" + ntName + "'";
+                            log.debug(msg);
+                            throw new NodeTypeConflictException(msg);
+                        }
+                    }
+                }
+                defs.add(cnda[i]);
+            }
+        }
+        QPropertyDefinition[] pda = ntd.getPropertyDefs();
+        for (int i = 0; i < pda.length; i++) {
+            // check if property definition would be ambiguous within
+            // this node type definition
+            if (itemDefIds.contains(pda[i])) {
+                // conflict
+                String msg;
+                if (pda[i].definesResidual()) {
+                    msg = ntName + " contains ambiguous residual property definitions";
+                } else {
+                    msg = ntName + " contains ambiguous definitions for property named "
+                            + pda[i].getQName();
+                }
+                log.debug(msg);
+                throw new NodeTypeConflictException(msg);
+            } else {
+                itemDefIds.add(pda[i]);
+            }
+            if (pda[i].definesResidual()) {
+                // residual property definition
+                ent.unnamedItemDefs.add(pda[i]);
+            } else {
+                // named property definition
+                QName name = pda[i].getQName();
+                List defs = (List) ent.namedItemDefs.get(name);
+                if (defs == null) {
+                    defs = new ArrayList();
+                    ent.namedItemDefs.put(name, defs);
+                }
+                if (defs.size() > 0) {
+                    /**
+                     * there already exists at least one definition with that
+                     * name; make sure none of them is auto-create
+                     */
+                    for (int j = 0; j < defs.size(); j++) {
+                        QItemDefinition qDef = (QItemDefinition) defs.get(j);
+                        if (pda[i].isAutoCreated() || qDef.isAutoCreated()) {
+                            // conflict
+                            String msg = "There are more than one 'auto-create' item definitions for '"
+                                    + name + "' in node type '" + ntName + "'";
+                            log.debug(msg);
+                            throw new NodeTypeConflictException(msg);
+                        }
+                    }
+                }
+                defs.add(pda[i]);
+            }
+        }
+
+        // resolve supertypes recursively
+        QName[] supertypes = ntd.getSupertypes();
+        if (supertypes != null && supertypes.length > 0) {
+            EffectiveNodeTypeImpl effSuperType = (EffectiveNodeTypeImpl)ntReg.getEffectiveNodeType(supertypes, ntdMap);
+            ent.internalMerge(effSuperType, true);
+        }
+
+        // we're done
+        return ent;
+    }
+
+    /**
+     * Factory method: creates a new 'empty' effective node type instance
+     *
+     * @return
+     */
+    static EffectiveNodeType create(NodeTypeRegistryImpl ntReg) {
+        return new EffectiveNodeTypeImpl(ntReg);
+    }
+
+    //--------------------------------------------------< EffectiveNodeType >---
+    /**
+     * @inheritDoc
+     */
+    public QName[] getInheritedNodeTypes() {
+        return (QName[]) inheritedNodeTypes.toArray(new QName[inheritedNodeTypes.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QName[] getAllNodeTypes() {
+        return (QName[]) allNodeTypes.toArray(new QName[allNodeTypes.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QName[] getMergedNodeTypes() {
+        return (QName[]) mergedNodeTypes.toArray(new QName[mergedNodeTypes.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QNodeDefinition[] getAllNodeDefs() {
+        if (namedItemDefs.size() == 0 && unnamedItemDefs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size() + unnamedItemDefs.size());
+        Iterator iter = unnamedItemDefs.iterator();
+        while (iter.hasNext()) {
+            QItemDefinition qDef = (QItemDefinition) iter.next();
+            if (qDef.definesNode()) {
+                defs.add(qDef);
+            }
+        }
+        iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (qDef.definesNode()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        return (QNodeDefinition[]) defs.toArray(new QNodeDefinition[defs.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QPropertyDefinition[] getAllPropDefs() {
+        if (namedItemDefs.size() == 0 && unnamedItemDefs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size() + unnamedItemDefs.size());
+        Iterator iter = unnamedItemDefs.iterator();
+        while (iter.hasNext()) {
+            QItemDefinition qDef = (QItemDefinition) iter.next();
+            if (!qDef.definesNode()) {
+                defs.add(qDef);
+            }
+        }
+        iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (!qDef.definesNode()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        return (QPropertyDefinition[]) defs.toArray(new QPropertyDefinition[defs.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QNodeDefinition[] getAutoCreateNodeDefs() {
+        // since auto-create items must have a name,
+        // we're only searching the named item definitions
+        if (namedItemDefs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (qDef.definesNode() && qDef.isAutoCreated()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        return (QNodeDefinition[]) defs.toArray(new QNodeDefinition[defs.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QPropertyDefinition[] getAutoCreatePropDefs() {
+        // since auto-create items must have a name,
+        // we're only searching the named item definitions
+        if (namedItemDefs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (!qDef.definesNode() && qDef.isAutoCreated()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        return (QPropertyDefinition[]) defs.toArray(new QPropertyDefinition[defs.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QPropertyDefinition[] getMandatoryPropDefs() {
+        // since mandatory items must have a name,
+        // we're only searching the named item definitions
+        if (namedItemDefs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (!qDef.definesNode() && qDef.isMandatory()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        return (QPropertyDefinition[]) defs.toArray(new QPropertyDefinition[defs.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QNodeDefinition[] getMandatoryNodeDefs() {
+        // since mandatory items must have a name,
+        // we're only searching the named item definitions
+        if (namedItemDefs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (qDef.definesNode() && qDef.isMandatory()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        return (QNodeDefinition[]) defs.toArray(new QNodeDefinition[defs.size()]);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public boolean includesNodeType(QName nodeTypeName) {
+        return allNodeTypes.contains(nodeTypeName);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public void checkAddNodeConstraints(QName name)
+            throws ConstraintViolationException {
+        try {
+            getApplicableNodeDefinition(name, null);
+        } catch (NoSuchNodeTypeException nsnte) {
+            String msg = "internal eror: inconsistent node type";
+            log.debug(msg);
+            throw new ConstraintViolationException(msg, nsnte);
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public void checkAddNodeConstraints(QName name, QName nodeTypeName)
+            throws ConstraintViolationException, NoSuchNodeTypeException {
+        QNodeDefinition nd = getApplicableNodeDefinition(name, nodeTypeName);
+        if (nd.isProtected()) {
+            throw new ConstraintViolationException(name + " is protected");
+        }
+        if (nd.isAutoCreated()) {
+            throw new ConstraintViolationException(name + " is auto-created and can not be manually added");
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public void checkRemoveItemConstraints(QName name) throws ConstraintViolationException {
+        /**
+         * as there might be multiple definitions with the same name and we
+         * don't know which one is applicable, we check all of them
+         */
+        QItemDefinition[] defs = getNamedItemDefs(name);
+        if (defs != null) {
+            for (int i = 0; i < defs.length; i++) {
+                if (defs[i].isMandatory()) {
+                    throw new ConstraintViolationException("can't remove mandatory item");
+                }
+                if (defs[i].isProtected()) {
+                    throw new ConstraintViolationException("can't remove protected item");
+                }
+            }
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QNodeDefinition getApplicableNodeDefinition(QName name, QName nodeTypeName)
+            throws NoSuchNodeTypeException, ConstraintViolationException {
+        // try named node definitions first
+        QItemDefinition[] defs = getNamedItemDefs(name);
+        if (defs != null) {
+            for (int i = 0; i < defs.length; i++) {
+                QItemDefinition qDef = defs[i];
+                if (qDef.definesNode()) {
+                    QNodeDefinition nd = (QNodeDefinition) qDef;
+                    // node definition with that name exists
+                    if (nodeTypeName != null) {
+                        try {
+                            // check node type constraints
+                            checkRequiredPrimaryType(nodeTypeName, nd.getRequiredPrimaryTypes());
+                        } catch (ConstraintViolationException cve) {
+                            // ignore and try next
+                            continue;
+                        }
+                        // found node definition
+                        return nd;
+                    } else {
+                        if (nd.getDefaultPrimaryType() == null) {
+                            // no default node type defined, try next
+                            continue;
+                        } else {
+                            // found node definition with default node type
+                            return nd;
+                        }
+                    }
+                }
+            }
+        }
+
+        // no item with that name defined;
+        // try residual node definitions
+        QNodeDefinition[] nda = getUnnamedNodeDefs();
+        for (int i = 0; i < nda.length; i++) {
+            QNodeDefinition nd = nda[i];
+            if (nodeTypeName != null) {
+                try {
+                    // check node type constraint
+                    checkRequiredPrimaryType(nodeTypeName, nd.getRequiredPrimaryTypes());
+                } catch (ConstraintViolationException e) {
+                    // ignore and try next
+                    continue;
+                }
+                // found residual node definition
+                return nd;
+            } else {
+                // since no node type has been specified for the new node,
+                // it must be determined from the default node type;
+                if (nd.getDefaultPrimaryType() != null) {
+                    // found residual node definition with default node type
+                    return nd;
+                }
+            }
+        }
+
+        // no applicable definition found
+        throw new ConstraintViolationException("no matching child node definition found for " + name);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QPropertyDefinition getApplicablePropertyDefinition(QName name, int type,
+                                            boolean multiValued)
+            throws ConstraintViolationException {
+        // try named property definitions first
+        QPropertyDefinition match =
+                getMatchingPropDef(getNamedPropDefs(name), type, multiValued);
+        if (match != null) {
+            return match;
+        }
+
+        // no item with that name defined;
+        // try residual property definitions
+        match = getMatchingPropDef(getUnnamedPropDefs(), type, multiValued);
+        if (match != null) {
+            return match;
+        }
+
+        // no applicable definition found
+        throw new ConstraintViolationException("no matching property definition found for " + name);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QPropertyDefinition getApplicablePropertyDefinition(QName name, int type)
+            throws ConstraintViolationException {
+        // try named property definitions first
+        QPropertyDefinition match = getMatchingPropDef(getNamedPropDefs(name), type);
+        if (match != null) {
+            return match;
+        }
+
+        // no item with that name defined;
+        // try residual property definitions
+        match = getMatchingPropDef(getUnnamedPropDefs(), type);
+        if (match != null) {
+            return match;
+        }
+
+        // no applicable definition found
+        throw new ConstraintViolationException("no matching property definition found for " + name);
+    }
+
+    //---------------------------------------------< impl. specific methods >---
+    private QItemDefinition[] getAllItemDefs() {
+        if (namedItemDefs.size() == 0 && unnamedItemDefs.size() == 0) {
+            return QItemDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size() + unnamedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            defs.addAll((List) iter.next());
+        }
+        defs.addAll(unnamedItemDefs);
+        if (defs.size() == 0) {
+            return QItemDefinition.EMPTY_ARRAY;
+        }
+        return (QItemDefinition[]) defs.toArray(new QItemDefinition[defs.size()]);
+    }
+
+    private QItemDefinition[] getNamedItemDefs() {
+        if (namedItemDefs.size() == 0) {
+            return QItemDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            defs.addAll((List) iter.next());
+        }
+        if (defs.size() == 0) {
+            return QItemDefinition.EMPTY_ARRAY;
+        }
+        return (QItemDefinition[]) defs.toArray(new QItemDefinition[defs.size()]);
+    }
+
+    private QItemDefinition[] getUnnamedItemDefs() {
+        if (unnamedItemDefs.size() == 0) {
+            return QItemDefinition.EMPTY_ARRAY;
+        }
+        return (QItemDefinition[]) unnamedItemDefs.toArray(new QItemDefinition[unnamedItemDefs.size()]);
+    }
+
+    private boolean hasNamedItemDef(QName name) {
+        return namedItemDefs.containsKey(name);
+    }
+
+    private QItemDefinition[] getNamedItemDefs(QName name) {
+        List defs = (List) namedItemDefs.get(name);
+        if (defs == null || defs.size() == 0) {
+            return QItemDefinition.EMPTY_ARRAY;
+        }
+        return (QItemDefinition[]) defs.toArray(new QItemDefinition[defs.size()]);
+    }
+
+    private QNodeDefinition[] getNamedNodeDefs() {
+        if (namedItemDefs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (qDef.definesNode()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        return (QNodeDefinition[]) defs.toArray(new QNodeDefinition[defs.size()]);
+    }
+
+    private QNodeDefinition[] getNamedNodeDefs(QName name) {
+        List list = (List) namedItemDefs.get(name);
+        if (list == null || list.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(list.size());
+        Iterator iter = list.iterator();
+        while (iter.hasNext()) {
+            QItemDefinition qDef = (QItemDefinition) iter.next();
+            if (qDef.definesNode()) {
+                defs.add(qDef);
+            }
+        }
+        if (defs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        return (QNodeDefinition[]) defs.toArray(new QNodeDefinition[defs.size()]);
+    }
+
+    private QNodeDefinition[] getUnnamedNodeDefs() {
+        if (unnamedItemDefs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(unnamedItemDefs.size());
+        Iterator iter = unnamedItemDefs.iterator();
+        while (iter.hasNext()) {
+            QItemDefinition qDef = (QItemDefinition) iter.next();
+            if (qDef.definesNode()) {
+                defs.add(qDef);
+            }
+        }
+        if (defs.size() == 0) {
+            return QNodeDefinition.EMPTY_ARRAY;
+        }
+        return (QNodeDefinition[]) defs.toArray(new QNodeDefinition[defs.size()]);
+    }
+
+    private QPropertyDefinition[] getNamedPropDefs() {
+        if (namedItemDefs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(namedItemDefs.size());
+        Iterator iter = namedItemDefs.values().iterator();
+        while (iter.hasNext()) {
+            List list = (List) iter.next();
+            Iterator iter1 = list.iterator();
+            while (iter1.hasNext()) {
+                QItemDefinition qDef = (QItemDefinition) iter1.next();
+                if (!qDef.definesNode()) {
+                    defs.add(qDef);
+                }
+            }
+        }
+        if (defs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        return (QPropertyDefinition[]) defs.toArray(new QPropertyDefinition[defs.size()]);
+    }
+
+    private QPropertyDefinition[] getNamedPropDefs(QName name) {
+        List list = (List) namedItemDefs.get(name);
+        if (list == null || list.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(list.size());
+        Iterator iter = list.iterator();
+        while (iter.hasNext()) {
+            QItemDefinition qDef = (QItemDefinition) iter.next();
+            if (!qDef.definesNode()) {
+                defs.add(qDef);
+            }
+        }
+        if (defs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        return (QPropertyDefinition[]) defs.toArray(new QPropertyDefinition[defs.size()]);
+    }
+
+    private QPropertyDefinition[] getUnnamedPropDefs() {
+        if (unnamedItemDefs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        ArrayList defs = new ArrayList(unnamedItemDefs.size());
+        Iterator iter = unnamedItemDefs.iterator();
+        while (iter.hasNext()) {
+            QItemDefinition qDef = (QItemDefinition) iter.next();
+            if (!qDef.definesNode()) {
+                defs.add(qDef);
+            }
+        }
+        if (defs.size() == 0) {
+            return QPropertyDefinition.EMPTY_ARRAY;
+        }
+        return (QPropertyDefinition[]) defs.toArray(new QPropertyDefinition[defs.size()]);
+    }
+
+    private QPropertyDefinition getMatchingPropDef(QPropertyDefinition[] defs, int type) {
+        QPropertyDefinition match = null;
+        for (int i = 0; i < defs.length; i++) {
+            QItemDefinition qDef = defs[i];
+            if (!qDef.definesNode()) {
+                QPropertyDefinition pd = (QPropertyDefinition) qDef;
+                int reqType = pd.getRequiredType();
+                // match type
+                if (reqType == PropertyType.UNDEFINED
+                        || type == PropertyType.UNDEFINED
+                        || reqType == type) {
+                    if (match == null) {
+                        match = pd;
+                    } else {
+                        // check if this definition is a better match than
+                        // the one we've already got
+                        if (match.getRequiredType() != pd.getRequiredType()) {
+                            if (match.getRequiredType() == PropertyType.UNDEFINED) {
+                                // found better match
+                                match = pd;
+                            }
+                        } else {
+                            if (match.isMultiple() && !pd.isMultiple()) {
+                                // found better match
+                                match = pd;
+                            }
+                        }
+                    }
+                    if (match.getRequiredType() != PropertyType.UNDEFINED
+                            && !match.isMultiple()) {
+                        // found best possible match, get outta here
+                        return match;
+                    }
+                }
+            }
+        }
+        return match;
+    }
+
+    private QPropertyDefinition getMatchingPropDef(QPropertyDefinition[] defs, int type,
+                                       boolean multiValued) {
+        QPropertyDefinition match = null;
+        for (int i = 0; i < defs.length; i++) {
+            QItemDefinition qDef = defs[i];
+            if (!qDef.definesNode()) {
+                QPropertyDefinition pd = (QPropertyDefinition) qDef;
+                int reqType = pd.getRequiredType();
+                // match type
+                if (reqType == PropertyType.UNDEFINED
+                        || type == PropertyType.UNDEFINED
+                        || reqType == type) {
+                    // match multiValued flag
+                    if (multiValued == pd.isMultiple()) {
+                        // found match
+                        if (pd.getRequiredType() != PropertyType.UNDEFINED) {
+                            // found best possible match, get outta here
+                            return pd;
+                        } else {
+                            if (match == null) {
+                                match = pd;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return match;
+    }
+
+    /**
+     * @param nodeTypeName
+     * @param requiredPrimaryTypes
+     * @throws ConstraintViolationException
+     * @throws NoSuchNodeTypeException
+     */
+    private void checkRequiredPrimaryType(QName nodeTypeName, QName[] requiredPrimaryTypes)
+            throws ConstraintViolationException, NoSuchNodeTypeException {
+        if (requiredPrimaryTypes == null) {
+            // no constraint
+            return;
+        }
+        EffectiveNodeType ent = ntReg.getEffectiveNodeType(nodeTypeName);
+        for (int i = 0; i < requiredPrimaryTypes.length; i++) {
+            if (!ent.includesNodeType(requiredPrimaryTypes[i])) {
+                throw new ConstraintViolationException("node type constraint not satisfied: " + requiredPrimaryTypes[i]);
+            }
+        }
+    }
+
+    /**
+     * Merges another <code>EffectiveNodeType</code> with this one.
+     * Checks for merge conflicts.
+     *
+     * @param other
+     * @return
+     * @throws NodeTypeConflictException
+     */
+    EffectiveNodeTypeImpl merge(EffectiveNodeTypeImpl other)
+            throws NodeTypeConflictException {
+        // create a clone of this instance and perform the merge on
+        // the 'clone' to avoid a potentially inconsistant state
+        // of this instance if an exception is thrown during
+        // the merge.
+        EffectiveNodeTypeImpl copy = (EffectiveNodeTypeImpl) clone();
+        copy.internalMerge(other, false);
+        return copy;
+    }
+
+    /**
+     * Internal helper method which merges another <code>EffectiveNodeType</code>
+     * instance with <i>this</i> instance.
+     * <p/>
+     * Warning: This instance might be in an inconsistent state if an exception
+     * is thrown.
+     *
+     * @param other
+     * @param supertype true if the merge is a result of inheritance, i.e. <code>other</code>
+     *                  represents one or more supertypes of this instance; otherwise false, i.e.
+     *                  the merge is the result of an explicit aggregation
+     * @throws NodeTypeConflictException
+     */
+    private synchronized void internalMerge(EffectiveNodeTypeImpl other, boolean supertype)
+            throws NodeTypeConflictException {
+        QName[] nta = other.getAllNodeTypes();
+        int includedCount = 0;
+        for (int i = 0; i < nta.length; i++) {
+            if (includesNodeType(nta[i])) {
+                // redundant node type
+                log.debug("node type '" + nta[i] + "' is already contained.");
+                includedCount++;
+            }
+        }
+        if (includedCount == nta.length) {
+            // total overlap, ignore
+            return;
+        }
+
+        // named item definitions
+        QItemDefinition[] defs = other.getNamedItemDefs();
+        for (int i = 0; i < defs.length; i++) {
+            QItemDefinition qDef = defs[i];
+            if (includesNodeType(qDef.getDeclaringNodeType())) {
+                // ignore redundant definitions
+                continue;
+            }
+            QName name = qDef.getQName();
+            List existingDefs = (List) namedItemDefs.get(name);
+            if (existingDefs != null) {
+                if (existingDefs.size() > 0) {
+                    // there already exists at least one definition with that name
+                    for (int j = 0; j < existingDefs.size(); j++) {
+                        QItemDefinition qItemDef = (QItemDefinition) existingDefs.get(j);
+                        // make sure none of them is auto-create
+                        if (qDef.isAutoCreated() || qItemDef.isAutoCreated()) {
+                            // conflict
+                            String msg = "The item definition for '" + name
+                                    + "' in node type '"
+                                    + qDef.getDeclaringNodeType()
+                                    + "' conflicts with node type '"
+                                    + qItemDef.getDeclaringNodeType()
+                                    + "': name collision with auto-create definition";
+                            log.debug(msg);
+                            throw new NodeTypeConflictException(msg);
+                        }
+                        // check ambiguous definitions
+                        if (qDef.definesNode() == qItemDef.definesNode()) {
+                            if (!qDef.definesNode()) {
+                                // property definition
+                                QPropertyDefinition pd = (QPropertyDefinition) qDef;
+                                QPropertyDefinition epd = (QPropertyDefinition) qItemDef;
+                                // compare type & multiValued flag
+                                if (pd.getRequiredType() == epd.getRequiredType()
+                                        && pd.isMultiple() == epd.isMultiple()) {
+                                    // conflict
+                                    String msg = "The property definition for '"
+                                            + name + "' in node type '"
+                                            + qDef.getDeclaringNodeType()
+                                            + "' conflicts with node type '"
+                                            + qItemDef.getDeclaringNodeType()
+                                            + "': ambiguous property definition";
+                                    log.debug(msg);
+                                    throw new NodeTypeConflictException(msg);
+                                }
+                            } else {
+                                // child node definition
+                                // conflict
+                                String msg = "The child node definition for '"
+                                        + name + "' in node type '"
+                                        + qDef.getDeclaringNodeType()
+                                        + "' conflicts with node type '"
+                                        + qItemDef.getDeclaringNodeType()
+                                        + "': ambiguous child node definition";
+                                log.debug(msg);
+                                throw new NodeTypeConflictException(msg);
+                            }
+                        }
+                    }
+                }
+            } else {
+                existingDefs = new ArrayList();
+                namedItemDefs.put(name, existingDefs);
+            }
+            existingDefs.add(qDef);
+        }
+
+        // residual item definitions
+        defs = other.getUnnamedItemDefs();
+        for (int i = 0; i < defs.length; i++) {
+            QItemDefinition qDef = defs[i];
+            if (includesNodeType(qDef.getDeclaringNodeType())) {
+                // ignore redundant definitions
+                continue;
+            }
+            Iterator iter = unnamedItemDefs.iterator();
+            while (iter.hasNext()) {
+                QItemDefinition existing = (QItemDefinition) iter.next();
+                // compare with existing definition
+                if (qDef.definesNode() == existing.definesNode()) {
+                    if (!qDef.definesNode()) {
+                        // property definition
+                        QPropertyDefinition pd = (QPropertyDefinition) qDef;
+                        QPropertyDefinition epd = (QPropertyDefinition) existing;
+                        // compare type & multiValued flag
+                        if (pd.getRequiredType() == epd.getRequiredType()
+                                && pd.isMultiple() == epd.isMultiple()) {
+                            // conflict
+                            String msg = "A property definition in node type '"
+                                    + qDef.getDeclaringNodeType()
+                                    + "' conflicts with node type '"
+                                    + existing.getDeclaringNodeType()
+                                    + "': ambiguous residual property definition";
+                            log.debug(msg);
+                            throw new NodeTypeConflictException(msg);
+                        }
+                    } else {
+                        // child node definition
+                        QNodeDefinition nd = (QNodeDefinition) qDef;
+                        QNodeDefinition end = (QNodeDefinition) existing;
+                        // compare required & default primary types
+                        if (Arrays.equals(nd.getRequiredPrimaryTypes(), end.getRequiredPrimaryTypes())
+                                && (nd.getDefaultPrimaryType() == null
+                                ? end.getDefaultPrimaryType() == null
+                                : nd.getDefaultPrimaryType().equals(end.getDefaultPrimaryType()))) {
+                            // conflict
+                            String msg = "A child node definition in node type '"
+                                    + qDef.getDeclaringNodeType()
+                                    + "' conflicts with node type '"
+                                    + existing.getDeclaringNodeType()
+                                    + "': ambiguous residual child node definition";
+                            log.debug(msg);
+                            throw new NodeTypeConflictException(msg);
+                        }
+                    }
+                }
+            }
+            unnamedItemDefs.add(qDef);
+        }
+        for (int i = 0; i < nta.length; i++) {
+            allNodeTypes.add(nta[i]);
+        }
+
+        if (supertype) {
+            // implicit merge as result of inheritance
+
+            // add other merged node types as supertypes
+            nta = other.getMergedNodeTypes();
+            for (int i = 0; i < nta.length; i++) {
+                inheritedNodeTypes.add(nta[i]);
+            }
+            // add supertypes of other merged node types as supertypes
+            nta = other.getInheritedNodeTypes();
+            for (int i = 0; i < nta.length; i++) {
+                inheritedNodeTypes.add(nta[i]);
+            }
+        } else {
+            // explicit merge
+
+            // merge with other merged node types
+            nta = other.getMergedNodeTypes();
+            for (int i = 0; i < nta.length; i++) {
+                mergedNodeTypes.add(nta[i]);
+            }
+            // add supertypes of other merged node types as supertypes
+            nta = other.getInheritedNodeTypes();
+            for (int i = 0; i < nta.length; i++) {
+                inheritedNodeTypes.add(nta[i]);
+            }
+        }
+    }
+
+    protected Object clone() {
+        EffectiveNodeTypeImpl clone = new EffectiveNodeTypeImpl(ntReg);
+
+        clone.mergedNodeTypes.addAll(mergedNodeTypes);
+        clone.inheritedNodeTypes.addAll(inheritedNodeTypes);
+        clone.allNodeTypes.addAll(allNodeTypes);
+        Iterator iter = namedItemDefs.keySet().iterator();
+        while (iter.hasNext()) {
+            Object key = iter.next();
+            List list = (List) namedItemDefs.get(key);
+            clone.namedItemDefs.put(key, new ArrayList(list));
+        }
+        clone.unnamedItemDefs.addAll(unnamedItemDefs);
+
+        return clone;
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeTypeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/EffectiveNodeTypeImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidConstraintException.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidConstraintException.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidConstraintException.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidConstraintException.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.BaseException;
+
+/**
+ * The <code>InvalidConstraintException</code> ...
+ */
+public class InvalidConstraintException extends BaseException {
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public InvalidConstraintException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message and root cause.
+     *
+     * @param message   the detail message. The detail message is saved for
+     *                  later retrieval by the {@link #getMessage()} method.
+     * @param rootCause root failure cause
+     */
+    public InvalidConstraintException(String message, Throwable rootCause) {
+        super(message, rootCause);
+    }
+
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidConstraintException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidConstraintException.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidNodeTypeDefException.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidNodeTypeDefException.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidNodeTypeDefException.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidNodeTypeDefException.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.BaseException;
+
+/**
+ * The <code>NodeTypeConflictException</code> ...
+ */
+public class InvalidNodeTypeDefException extends BaseException {
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public InvalidNodeTypeDefException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message and root cause.
+     *
+     * @param message   the detail message. The detail message is saved for
+     *                  later retrieval by the {@link #getMessage()} method.
+     * @param rootCause root failure cause
+     */
+    public InvalidNodeTypeDefException(String message, Throwable rootCause) {
+        super(message, rootCause);
+    }
+
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidNodeTypeDefException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/InvalidNodeTypeDefException.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
+import org.apache.jackrabbit.spi.QItemDefinition;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+
+/**
+ * This class implements the <code>ItemDefinition</code> interface.
+ * All method calls are delegated to the wrapped {@link QItemDefinition},
+ * performing the translation from <code>QName</code>s to JCR names
+ * (and vice versa) where necessary.
+ */
+abstract class ItemDefinitionImpl implements ItemDefinition {
+
+    /**
+     * Logger instance for this class
+     */
+    private static Logger log = LoggerFactory.getLogger(ItemDefinitionImpl.class);
+
+    /**
+     * Literal for 'any name'.
+     */
+    protected static final String ANY_NAME = "*";
+
+    /**
+     * The node type manager of this session.
+     */
+    protected final NodeTypeManagerImpl ntMgr;
+
+    /**
+     * The namespace resolver used to translate qualified names to JCR names.
+     */
+    protected final NamespaceResolver nsResolver;
+
+    /**
+     * The wrapped item definition.
+     */
+    protected final QItemDefinition itemDef;
+
+    /**
+     * Package private constructor
+     *
+     * @param itemDef    item definition
+     * @param ntMgr      node type manager
+     * @param nsResolver namespace resolver
+     */
+    ItemDefinitionImpl(QItemDefinition itemDef, NodeTypeManagerImpl ntMgr,
+                       NamespaceResolver nsResolver) {
+        this.itemDef = itemDef;
+        this.ntMgr = ntMgr;
+        this.nsResolver = nsResolver;
+    }
+
+    //-------------------------------------------------------< ItemDefinition >
+    /**
+     * {@inheritDoc}
+     */
+    public NodeType getDeclaringNodeType() {
+        try {
+            return ntMgr.getNodeType(itemDef.getDeclaringNodeType());
+        } catch (NoSuchNodeTypeException e) {
+            // should never get here
+            log.error("declaring node type does not exist", e);
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        if (itemDef.definesResidual()) {
+            return ANY_NAME;
+        } else {
+            try {
+                return nsResolver.getJCRName(itemDef.getQName());
+            } catch (NoPrefixDeclaredException npde) {
+                // should never get here
+                log.error("encountered unregistered namespace in property name",
+                        npde);
+                // not correct, but an acceptable fallback
+                return itemDef.getQName().toString();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getOnParentVersion() {
+        return itemDef.getOnParentVersion();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAutoCreated() {
+        return itemDef.isAutoCreated();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMandatory() {
+        return itemDef.isMandatory();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isProtected() {
+        return itemDef.isProtected();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ItemDefinitionImpl)) {
+            return false;
+        }
+        return itemDef.equals(((ItemDefinitionImpl) o).itemDef);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        return itemDef.hashCode();
+    }
+}
+

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>ItemDefinitionManager</code>...
+ */
+public interface ItemDefinitionManager {
+
+    public NodeDefinition getNodeDefinition(QNodeDefinition def);
+
+    public PropertyDefinition getPropertyDefinition(QPropertyDefinition def);
+
+    public NodeDefinition getNodeDefinition(NodeState state, NodeState parentState) throws RepositoryException;
+
+    public PropertyDefinition getPropertyDefinition(PropertyState propState, NodeState parentState) throws RepositoryException;
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/ItemDefinitionManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeDefinitionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeDefinitionImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeDefinitionImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeDefinitionImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+
+/**
+ * This class implements the <code>NodeDefinition</code> interface.
+ * All method calls are delegated to the wrapped {@link QNodeDefinition},
+ * performing the translation from <code>QName</code>s to JCR names
+ * where necessary.
+ */
+public class NodeDefinitionImpl extends ItemDefinitionImpl implements NodeDefinition {
+
+    /**
+     * Logger instance for this class
+     */
+    private static Logger log = LoggerFactory.getLogger(NodeDefinitionImpl.class);
+
+    /**
+     * Package private constructor.
+     *
+     * @param nodeDef    child node definition
+     * @param ntMgr      node type manager
+     * @param nsResolver namespace resolver
+     */
+    NodeDefinitionImpl(QNodeDefinition nodeDef, NodeTypeManagerImpl ntMgr,
+                NamespaceResolver nsResolver) {
+        super(nodeDef, ntMgr, nsResolver);
+    }
+
+    //-------------------------------------------------------< NodeDefinition >
+    /**
+     * {@inheritDoc}
+     */
+    public NodeType getDefaultPrimaryType() {
+        QName ntName = ((QNodeDefinition) itemDef).getDefaultPrimaryType();
+        if (ntName == null) {
+            return null;
+        }
+        try {
+            return ntMgr.getNodeType(ntName);
+        } catch (NoSuchNodeTypeException e) {
+            // should never get here
+            log.error("invalid default node type " + ntName, e);
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeType[] getRequiredPrimaryTypes() {
+        QName[] ntNames = ((QNodeDefinition) itemDef).getRequiredPrimaryTypes();
+        try {
+            if (ntNames == null || ntNames.length == 0) {
+                // return "nt:base"
+                return new NodeType[] { ntMgr.getNodeType(QName.NT_BASE) };
+            } else {
+                NodeType[] nodeTypes = new NodeType[ntNames.length];
+                for (int i = 0; i < ntNames.length; i++) {
+                    nodeTypes[i] = ntMgr.getNodeType(ntNames[i]);
+                }
+                return nodeTypes;
+            }
+        } catch (NoSuchNodeTypeException e) {
+            // should never get here
+            log.error("required node type does not exist", e);
+            return new NodeType[0];
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean allowsSameNameSiblings() {
+        return ((QNodeDefinition) itemDef).allowsSameNameSiblings();
+    }
+}
+

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeDefinitionImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeDefinitionImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeConflictException.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeConflictException.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeConflictException.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeConflictException.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.BaseException;
+
+/**
+ * The <code>NodeTypeConflictException</code> ...
+ */
+public class NodeTypeConflictException extends BaseException {
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public NodeTypeConflictException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message and root cause.
+     *
+     * @param message   the detail message. The detail message is saved for
+     *                  later retrieval by the {@link #getMessage()} method.
+     * @param rootCause root failure cause
+     */
+    public NodeTypeConflictException(String message, Throwable rootCause) {
+        super(message, rootCause);
+    }
+
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeConflictException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeConflictException.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,584 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jcr2spi.nodetype;
+
+import org.apache.jackrabbit.name.IllegalNameException;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
+import org.apache.jackrabbit.name.UnknownPrefixException;
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.value.QValue;
+import org.apache.jackrabbit.value.ValueHelper;
+import org.apache.jackrabbit.value.ValueFormat;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * A <code>NodeTypeImpl</code> ...
+ */
+public class NodeTypeImpl implements NodeType {
+
+    private static Logger log = LoggerFactory.getLogger(NodeTypeImpl.class);
+
+    private final QNodeTypeDefinition ntd;
+    private final EffectiveNodeType ent;
+    private final NodeTypeManagerImpl ntMgr;
+    // namespace resolver used to translate qualified names to JCR names
+    private final NamespaceResolver nsResolver;
+    // DIFF JR: v-factory added
+    private final ValueFactory valueFactory;
+
+    /**
+     * Package private constructor
+     * <p/>
+     * Creates a valid node type instance.
+     * We assume that the node type definition is valid and all referenced
+     * node types (supertypes, required node types etc.) do exist and are valid.
+     *
+     * @param ent        the effective (i.e. merged and resolved) node type representation
+     * @param ntd        the definition of this node type
+     * @param ntMgr      the node type manager associated with this node type
+     * @param nsResolver namespace resolver
+     */
+    NodeTypeImpl(EffectiveNodeType ent, QNodeTypeDefinition ntd,
+                 NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver,
+                 ValueFactory valueFactory) {
+        this.ent = ent;
+        this.ntMgr = ntMgr;
+        this.nsResolver = nsResolver;
+        this.valueFactory = valueFactory;
+        this.ntd = ntd;
+    }
+
+    /**
+     * Returns the applicable child node definition for a child node with the
+     * specified name.
+     *
+     * @param nodeName
+     * @return
+     * @throws RepositoryException if no applicable child node definition
+     *                             could be found
+     */
+    private QNodeDefinition getApplicableNodeDef(QName nodeName)
+            throws RepositoryException {
+        return getApplicableNodeDef(nodeName, null);
+    }
+
+    /**
+     * Returns the applicable child node definition for a child node with the
+     * specified name and node type.
+     *
+     * @param nodeName
+     * @param nodeTypeName
+     * @return
+     * @throws RepositoryException if no applicable child node definition
+     *                             could be found
+     */
+    private QNodeDefinition getApplicableNodeDef(QName nodeName, QName nodeTypeName)
+            throws RepositoryException {
+        return ent.getApplicableNodeDefinition(nodeName, nodeTypeName);
+    }
+
+    /**
+     * Returns the applicable property definition for a property with the
+     * specified name and type.
+     *
+     * @param propertyName
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws RepositoryException if no applicable property definition
+     *                             could be found
+     */
+    private QPropertyDefinition getApplicablePropDef(QName propertyName, int type, boolean multiValued)
+            throws RepositoryException {
+        return ent.getApplicablePropertyDefinition(propertyName, type, multiValued);
+    }
+
+    /**
+     * Checks if this node type's name equals the given name or if this nodetype
+     * is directly or indirectly derived from the specified node type.
+     *
+     * @param nodeTypeName
+     * @return true if this node type is equal or directly or indirectly derived
+     * from the specified node type, otherwise false.
+     */
+    public boolean isNodeType(QName nodeTypeName) {
+        return getQName().equals(nodeTypeName) ||  ent.includesNodeType(nodeTypeName);
+    }
+
+    /**
+     * Returns an array containing only those child node definitions of this
+     * node type (including the child node definitions inherited from supertypes
+     * of this node type) where <code>{@link NodeDefinition#isAutoCreated()}</code>
+     * returns <code>true</code>.
+     *
+     * @return an array of child node definitions.
+     * @see NodeDefinition#isAutoCreated
+     */
+    private NodeDefinition[] getAutoCreatedNodeDefinitions() {
+        QNodeDefinition[] cnda = ent.getAutoCreateNodeDefs();
+        NodeDefinition[] nodeDefs = new NodeDefinition[cnda.length];
+        for (int i = 0; i < cnda.length; i++) {
+            nodeDefs[i] = ntMgr.getNodeDefinition(cnda[i]);
+        }
+        return nodeDefs;
+    }
+
+    /**
+     * Returns an array containing only those property definitions of this
+     * node type (including the property definitions inherited from supertypes
+     * of this node type) where <code>{@link PropertyDefinition#isAutoCreated()}</code>
+     * returns <code>true</code>.
+     *
+     * @return an array of property definitions.
+     * @see PropertyDefinition#isAutoCreated
+     */
+    private PropertyDefinition[] getAutoCreatedPropertyDefinitions() {
+        QPropertyDefinition[] pda = ent.getAutoCreatePropDefs();
+        PropertyDefinition[] propDefs = new PropertyDefinition[pda.length];
+        for (int i = 0; i < pda.length; i++) {
+            propDefs[i] = ntMgr.getPropertyDefinition(pda[i]);
+        }
+        return propDefs;
+    }
+
+    /**
+     * Returns an array containing only those property definitions of this
+     * node type (including the property definitions inherited from supertypes
+     * of this node type) where <code>{@link PropertyDefinition#isMandatory()}</code>
+     * returns <code>true</code>.
+     *
+     * @return an array of property definitions.
+     * @see PropertyDefinition#isMandatory
+     */
+    private PropertyDefinition[] getMandatoryPropertyDefinitions() {
+        QPropertyDefinition[] pda = ent.getMandatoryPropDefs();
+        PropertyDefinition[] propDefs = new PropertyDefinition[pda.length];
+        for (int i = 0; i < pda.length; i++) {
+            propDefs[i] = ntMgr.getPropertyDefinition(pda[i]);
+        }
+        return propDefs;
+    }
+
+    /**
+     * Returns an array containing only those child node definitions of this
+     * node type (including the child node definitions inherited from supertypes
+     * of this node type) where <code>{@link NodeDefinition#isMandatory()}</code>
+     * returns <code>true</code>.
+     *
+     * @return an array of child node definitions.
+     * @see NodeDefinition#isMandatory
+     */
+    private NodeDefinition[] getMandatoryNodeDefinitions() {
+        QNodeDefinition[] cnda = ent.getMandatoryNodeDefs();
+        NodeDefinition[] nodeDefs = new NodeDefinition[cnda.length];
+        for (int i = 0; i < cnda.length; i++) {
+            nodeDefs[i] = ntMgr.getNodeDefinition(cnda[i]);
+        }
+        return nodeDefs;
+    }
+
+    /**
+     * Tests if the value constraints defined in the property definition
+     * <code>def</code> are satisfied by the the specified <code>values</code>.
+     * <p/>
+     * Note that the <i>protected</i> flag is not checked. Also note that no
+     * type conversions are attempted if the type of the given values does not
+     * match the required type as specified in the given definition.
+     *
+     * @param def    The definiton of the property
+     * @param values An array of <code>QValue</code> objects.
+     * @throws ConstraintViolationException
+     * @throws RepositoryException
+     */
+    private static void checkSetPropertyValueConstraints(QPropertyDefinition def,
+                                                        QValue[] values)
+            throws ConstraintViolationException, RepositoryException {
+        ValueConstraint.checkValueConstraints(def, values);
+    }
+
+    /**
+     * Returns the 'internal', i.e. the fully qualified name.
+     *
+     * @return the qualified name
+     */
+    private QName getQName() {
+        return ntd.getQName();
+    }
+
+    /**
+     * Returns all <i>inherited</i> supertypes of this node type.
+     *
+     * @return an array of <code>NodeType</code> objects.
+     * @see #getSupertypes
+     * @see #getDeclaredSupertypes
+     */
+    private NodeType[] getInheritedSupertypes() {
+        // declared supertypes
+        QName[] ntNames = ntd.getSupertypes();
+        HashSet declared = new HashSet();
+        for (int i = 0; i < ntNames.length; i++) {
+            declared.add(ntNames[i]);
+        }
+        // all supertypes
+        ntNames = ent.getInheritedNodeTypes();
+
+        // filter from all supertypes those that are not declared
+        ArrayList inherited = new ArrayList();
+        for (int i = 0; i < ntNames.length; i++) {
+            if (!declared.contains(ntNames[i])) {
+                try {
+                    inherited.add(ntMgr.getNodeType(ntNames[i]));
+                } catch (NoSuchNodeTypeException e) {
+                    // should never get here
+                    log.error("undefined supertype", e);
+                    return new NodeType[0];
+                }
+            }
+        }
+
+        return (NodeType[]) inherited.toArray(new NodeType[inherited.size()]);
+    }
+
+    //-------------------------------------------------------------< NodeType >
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        try {
+            return nsResolver.getJCRName(ntd.getQName());
+        } catch (NoPrefixDeclaredException npde) {
+            // should never get here
+            log.error("encountered unregistered namespace in node type name", npde);
+            return ntd.getQName().toString();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPrimaryItemName() {
+        try {
+            QName piName = ntd.getPrimaryItemName();
+            if (piName != null) {
+                return nsResolver.getJCRName(piName);
+            } else {
+                return null;
+            }
+        } catch (NoPrefixDeclaredException npde) {
+            // should never get here
+            log.error("encountered unregistered namespace in name of primary item", npde);
+            return ntd.getQName().toString();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMixin() {
+        return ntd.isMixin();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isNodeType(String nodeTypeName) {
+        QName ntName;
+        try {
+            ntName = nsResolver.getQName(nodeTypeName);
+        } catch (IllegalNameException ine) {
+            log.warn("invalid node type name: " + nodeTypeName, ine);
+            return false;
+        } catch (UnknownPrefixException upe) {
+            log.warn("invalid node type name: " + nodeTypeName, upe);
+            return false;
+        }
+        return isNodeType(ntName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasOrderableChildNodes() {
+        return ntd.hasOrderableChildNodes();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeType[] getSupertypes() {
+        QName[] ntNames = ent.getInheritedNodeTypes();
+        NodeType[] supertypes = new NodeType[ntNames.length];
+        for (int i = 0; i < ntNames.length; i++) {
+            try {
+                supertypes[i] = ntMgr.getNodeType(ntNames[i]);
+            } catch (NoSuchNodeTypeException e) {
+                // should never get here
+                log.error("undefined supertype", e);
+                return new NodeType[0];
+            }
+        }
+        return supertypes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeDefinition[] getChildNodeDefinitions() {
+        QNodeDefinition[] cnda = ent.getAllNodeDefs();
+        NodeDefinition[] nodeDefs = new NodeDefinition[cnda.length];
+        for (int i = 0; i < cnda.length; i++) {
+            nodeDefs[i] = ntMgr.getNodeDefinition(cnda[i]);
+        }
+        return nodeDefs;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PropertyDefinition[] getPropertyDefinitions() {
+        QPropertyDefinition[] pda = ent.getAllPropDefs();
+        PropertyDefinition[] propDefs = new PropertyDefinition[pda.length];
+        for (int i = 0; i < pda.length; i++) {
+            propDefs[i] = ntMgr.getPropertyDefinition(pda[i]);
+        }
+        return propDefs;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeType[] getDeclaredSupertypes() {
+        QName[] ntNames = ntd.getSupertypes();
+        NodeType[] supertypes = new NodeType[ntNames.length];
+        for (int i = 0; i < ntNames.length; i++) {
+            try {
+                supertypes[i] = ntMgr.getNodeType(ntNames[i]);
+            } catch (NoSuchNodeTypeException e) {
+                // should never get here
+                log.error("undefined supertype", e);
+                return new NodeType[0];
+            }
+        }
+        return supertypes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeDefinition[] getDeclaredChildNodeDefinitions() {
+        QNodeDefinition[] cnda = ntd.getChildNodeDefs();
+        NodeDefinition[] nodeDefs = new NodeDefinition[cnda.length];
+        for (int i = 0; i < cnda.length; i++) {
+            nodeDefs[i] = ntMgr.getNodeDefinition(cnda[i]);
+        }
+        return nodeDefs;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canSetProperty(String propertyName, Value value) {
+        if (value == null) {
+            // setting a property to null is equivalent of removing it
+            return canRemoveItem(propertyName);
+        }
+        try {
+            QName name = nsResolver.getQName(propertyName);
+            QPropertyDefinition def;
+            try {
+                // try to get definition that matches the given value type
+                def = getApplicablePropDef(name, value.getType(), false);
+            } catch (ConstraintViolationException cve) {
+                // fallback: ignore type
+                def = getApplicablePropDef(name, PropertyType.UNDEFINED, false);
+            }
+            if (def.isProtected()) {
+                return false;
+            }
+            if (def.isMultiple()) {
+                return false;
+            }
+            int targetType;
+            if (def.getRequiredType() != PropertyType.UNDEFINED
+                    && def.getRequiredType() != value.getType()) {
+                // type conversion required
+                targetType = def.getRequiredType();
+            } else {
+                // no type conversion required
+                targetType = value.getType();
+            }
+            // create QValue from Value and perform
+            // type conversion as necessary
+            Value v = ValueHelper.convert(value, targetType, valueFactory);
+            QValue qValue = ValueFormat.getQValue(v, nsResolver);
+            checkSetPropertyValueConstraints(def, new QValue[]{qValue});
+            return true;
+        } catch (NameException be) {
+            // implementation specific exception, fall through
+        } catch (RepositoryException re) {
+            // fall through
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canSetProperty(String propertyName, Value[] values) {
+        if (values == null) {
+            // setting a property to null is equivalent of removing it
+            return canRemoveItem(propertyName);
+        }
+        try {
+            QName name = nsResolver.getQName(propertyName);
+            // determine type of values
+            int type = PropertyType.UNDEFINED;
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] == null) {
+                    // skip null values as those would be purged
+                    continue;
+                }
+                if (type == PropertyType.UNDEFINED) {
+                    type = values[i].getType();
+                } else if (type != values[i].getType()) {
+                    // inhomogeneous types
+                    return false;
+                }
+            }
+            QPropertyDefinition def;
+            try {
+                // try to get definition that matches the given value type
+                def = getApplicablePropDef(name, type, true);
+            } catch (ConstraintViolationException cve) {
+                // fallback: ignore type
+                def = getApplicablePropDef(name, PropertyType.UNDEFINED, true);
+            }
+
+            if (def.isProtected()) {
+                return false;
+            }
+            if (!def.isMultiple()) {
+                return false;
+            }
+            // determine target type
+            int targetType;
+            if (def.getRequiredType() != PropertyType.UNDEFINED
+                    && def.getRequiredType() != type) {
+                // type conversion required
+                targetType = def.getRequiredType();
+            } else {
+                // no type conversion required
+                targetType = type;
+            }
+
+            ArrayList list = new ArrayList();
+            // convert values and compact array (purge null entries)
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] != null) {
+                    // create QValue from Value and perform
+                    // type conversion as necessary
+                    Value v = ValueHelper.convert(values[i], targetType, valueFactory);
+                    QValue qValue = ValueFormat.getQValue(v, nsResolver);
+                    list.add(qValue);
+                }
+            }
+            QValue[] internalValues = (QValue[]) list.toArray(new QValue[list.size()]);
+            checkSetPropertyValueConstraints(def, internalValues);
+            return true;
+        } catch (NameException be) {
+            // implementation specific exception, fall through
+        } catch (RepositoryException re) {
+            // fall through
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canAddChildNode(String childNodeName) {
+        try {
+            ent.checkAddNodeConstraints(nsResolver.getQName(childNodeName));
+            return true;
+        } catch (NameException be) {
+            // implementation specific exception, fall through
+        } catch (RepositoryException re) {
+            // fall through
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canAddChildNode(String childNodeName, String nodeTypeName) {
+        try {
+            ent.checkAddNodeConstraints(nsResolver.getQName(childNodeName), nsResolver.getQName(nodeTypeName));
+            return true;
+        } catch (NameException be) {
+            // implementation specific exception, fall through
+        } catch (RepositoryException re) {
+            // fall through
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean canRemoveItem(String itemName) {
+        try {
+            ent.checkRemoveItemConstraints(nsResolver.getQName(itemName));
+            return true;
+        } catch (NameException be) {
+            // implementation specific exception, fall through
+        } catch (RepositoryException re) {
+            // fall through
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PropertyDefinition[] getDeclaredPropertyDefinitions() {
+        QPropertyDefinition[] pda = ntd.getPropertyDefs();
+        PropertyDefinition[] propDefs = new PropertyDefinition[pda.length];
+        for (int i = 0; i < pda.length; i++) {
+            propDefs[i] = ntMgr.getPropertyDefinition(pda[i]);
+        }
+        return propDefs;
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url