jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r421270 [10/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...
Date Wed, 12 Jul 2006 13:33:27 GMT
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeManagerImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeManagerImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeManagerImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,457 @@
+/*
+ * 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.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.name.IllegalNameException;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.UnknownPrefixException;
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.util.IteratorHelper;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.jcr2spi.util.Dumpable;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.version.OnParentVersionAction;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.nodetype.NodeDefinition;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.io.PrintStream;
+
+/**
+ * A <code>NodeTypeManagerImpl</code> implements a session dependant
+ * NodeTypeManager.
+ */
+public class NodeTypeManagerImpl implements NodeTypeManager, ItemDefinitionManager,
+        NodeTypeRegistryListener, Dumpable {
+
+    /**
+     * Logger instance for this class
+     */
+    private static Logger log = LoggerFactory.getLogger(NodeTypeManagerImpl.class);
+
+    /**
+     * The wrapped node type registry.
+     */
+    private final NodeTypeRegistry ntReg;
+
+    /**
+     * The namespace resolver used to translate qualified names to JCR names.
+     */
+    private final NamespaceResolver nsResolver;
+
+    /**
+     * The ValueFactory used to convert qualified values to JCR values.
+     */
+    private final ValueFactory valueFactory;
+
+    /**
+     * A cache for <code>NodeType</code> instances created by this
+     * <code>NodeTypeManager</code>
+     */
+    private final Map ntCache;
+
+    /**
+     * A cache for <code>PropertyDefinition</code> instances created by this
+     * <code>NodeTypeManager</code>
+     */
+    private final Map pdCache;
+
+    /**
+     * A cache for <code>NodeDefinition</code> instances created by this
+     * <code>NodeTypeManager</code>
+     */
+    private final Map ndCache;
+
+    /**
+     * Creates a new <code>NodeTypeManagerImpl</code> instance.
+     *
+     * @param ntReg      node type registry
+     * @param nsResolver namespace resolver
+     */
+    public NodeTypeManagerImpl(NodeTypeRegistry ntReg, NamespaceResolver nsResolver,
+                               ValueFactory valueFactory) {
+        this.nsResolver = nsResolver;
+        this.ntReg = ntReg;
+        this.ntReg.addListener(this);
+        this.valueFactory = valueFactory;
+
+        // initialize ItemDefinitionManager
+        // 1) setup caches with soft references to node type
+        ntCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
+        pdCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
+        ndCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
+
+        // 2) setup root definition and update cache
+        QNodeDefinition rootDef = ntReg.getRootNodeDef();
+        NodeDefinition rootNodeDefinition = new NodeDefinitionImpl(rootDef, this, nsResolver);
+        ndCache.put(rootDef, rootNodeDefinition);
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * @param name
+     * @return
+     * @throws NoSuchNodeTypeException
+     */
+    public NodeTypeImpl getNodeType(QName name) throws NoSuchNodeTypeException {
+        synchronized (ntCache) {
+            NodeTypeImpl nt = (NodeTypeImpl) ntCache.get(name);
+            if (nt == null) {
+                EffectiveNodeType ent = ntReg.getEffectiveNodeType(name);
+                QNodeTypeDefinition def = ntReg.getNodeTypeDefinition(name);
+                nt = new NodeTypeImpl(ent, def, this, nsResolver, valueFactory);
+                ntCache.put(name, nt);
+            }
+            return nt;
+        }
+    }
+
+    /**
+     *
+     * @param nodeTypeName
+     * @return
+     */
+    public boolean hasNodeType(QName nodeTypeName) {
+        boolean isRegistered = ntCache.containsKey(nodeTypeName);
+        if (!isRegistered) {
+            isRegistered = ntReg.isRegistered(nodeTypeName);
+        }
+        return isRegistered;
+    }
+
+    //----------------------------------------------< ItemDefinitionManager >---
+    // DIFF JR: new interface ItemDefinitionManager -> avoid usage of NodeTypeManagerImpl
+    /**
+     * @inheritDoc
+     */
+    public NodeDefinition getNodeDefinition(QNodeDefinition def) {
+        synchronized (ndCache) {
+            NodeDefinition ndi = (NodeDefinition) ndCache.get(def);
+            if (ndi == null) {
+                ndi = new NodeDefinitionImpl(def, this, nsResolver);
+                ndCache.put(def, ndi);
+            }
+            return ndi;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public PropertyDefinition getPropertyDefinition(QPropertyDefinition def) {
+        synchronized (pdCache) {
+            PropertyDefinition pdi = (PropertyDefinition) pdCache.get(def);
+            if (pdi == null) {
+                pdi = new PropertyDefinitionImpl(def, this, nsResolver, valueFactory);
+                pdCache.put(def, pdi);
+            }
+            return pdi;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    // DIFF JACKRABBIT: method added (JR defines similar in ItemManager)
+    public NodeDefinition getNodeDefinition(NodeState nodeState, NodeState parentState) throws RepositoryException {
+        QNodeDefinition def = nodeState.getDefinition();
+        if (def == null) {
+            try {
+                if (parentState == null) {
+                    // special case for root state
+                    def = ntReg.getRootNodeDef();
+                } else {
+                    NodeState.ChildNodeEntry cne = parentState.getChildNodeEntry(nodeState.getNodeId());
+                    def = ntReg.getEffectiveNodeType(parentState.getNodeTypeNames()).getApplicableNodeDefinition(cne.getName(), nodeState.getNodeTypeName());
+                }
+            } catch (NodeTypeConflictException e) {
+                String msg = "internal error: failed to build effective node type.";
+                log.debug(msg);
+                throw new RepositoryException(msg, e);
+            }
+            // make sure the state has the definition set now
+            nodeState.setDefinition(def);
+        }
+        return getNodeDefinition(def);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    // DIFF JACKRABBIT: method added (JR defines similar in ItemManager)
+    public PropertyDefinition getPropertyDefinition(PropertyState propState, NodeState parentState) throws RepositoryException {
+        QPropertyDefinition def = propState.getDefinition();
+        if (def == null) {
+            try {
+                def = ntReg.getEffectiveNodeType(parentState.getNodeTypeNames()).getApplicablePropertyDefinition(propState.getName(), propState.getType(), propState.isMultiValued());
+                propState.setDefinition(def);
+            } catch (NodeTypeConflictException e) {
+                String msg = "internal error: failed to build effective node type.";
+                log.debug(msg);
+                throw new RepositoryException(msg, e);
+            }
+        }
+        return getPropertyDefinition(def);
+    }
+
+    //-------------------------------------------< NodeTypeRegistryListener >---
+    /**
+     * {@inheritDoc}
+     */
+    public void nodeTypeRegistered(QName ntName) {
+        // not interested, ignore
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void nodeTypeReRegistered(QName ntName) {
+        // flush all affected cache entries
+        ntCache.remove(ntName);
+        try {
+            String name = nsResolver.getJCRName(ntName);
+            synchronized (pdCache) {
+                Iterator iter = pdCache.values().iterator();
+                while (iter.hasNext()) {
+                    PropertyDefinition pd = (PropertyDefinition) iter.next();
+                    if (name.equals(pd.getDeclaringNodeType())) {
+                        iter.remove();
+                    }
+                }
+            }
+            synchronized (ndCache) {
+                Iterator iter = ndCache.values().iterator();
+                while (iter.hasNext()) {
+                    NodeDefinition nd = (NodeDefinition) iter.next();
+                    if (name.equals(nd.getDeclaringNodeType())) {
+                        iter.remove();
+                    }
+                }
+            }
+        } catch (NameException e) {
+            log.warn(e.getMessage() + " -> clear definition cache." );
+            synchronized (pdCache) {
+                pdCache.clear();
+            }
+            synchronized (ndCache) {
+                ndCache.clear();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void nodeTypeUnregistered(QName ntName) {
+        // flush all affected cache entries
+        ntCache.remove(ntName);
+        try {
+            String name = nsResolver.getJCRName(ntName);
+            synchronized (pdCache) {
+                Iterator iter = pdCache.values().iterator();
+                while (iter.hasNext()) {
+                    PropertyDefinition pd = (PropertyDefinition) iter.next();
+                    if (name.equals(pd.getDeclaringNodeType())) {
+                        iter.remove();
+                    }
+                }
+            }
+            synchronized (ndCache) {
+                Iterator iter = ndCache.values().iterator();
+                while (iter.hasNext()) {
+                    NodeDefinition nd = (NodeDefinition) iter.next();
+                    if (name.equals(nd.getDeclaringNodeType())) {
+                        iter.remove();
+                    }
+                }
+            }
+        } catch (NameException e) {
+            log.warn(e.getMessage() + " -> clear definition cache." );
+            synchronized (pdCache) {
+                pdCache.clear();
+            }
+            synchronized (ndCache) {
+                ndCache.clear();
+            }
+        }
+    }
+
+    //----------------------------------------------------< NodeTypeManager >---
+    /**
+     * {@inheritDoc}
+     */
+    public NodeTypeIterator getAllNodeTypes() throws RepositoryException {
+        QName[] ntNames = ntReg.getRegisteredNodeTypes();
+        ArrayList list = new ArrayList(ntNames.length);
+        for (int i = 0; i < ntNames.length; i++) {
+            list.add(getNodeType(ntNames[i]));
+        }
+        return new IteratorHelper(Collections.unmodifiableCollection(list));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException {
+        QName[] ntNames = ntReg.getRegisteredNodeTypes();
+        ArrayList list = new ArrayList(ntNames.length);
+        for (int i = 0; i < ntNames.length; i++) {
+            NodeType nt = getNodeType(ntNames[i]);
+            if (!nt.isMixin()) {
+                list.add(nt);
+            }
+        }
+        return new IteratorHelper(Collections.unmodifiableCollection(list));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeTypeIterator getMixinNodeTypes() throws RepositoryException {
+        QName[] ntNames = ntReg.getRegisteredNodeTypes();
+        ArrayList list = new ArrayList(ntNames.length);
+        for (int i = 0; i < ntNames.length; i++) {
+            NodeType nt = getNodeType(ntNames[i]);
+            if (nt.isMixin()) {
+                list.add(nt);
+            }
+        }
+        return new IteratorHelper(Collections.unmodifiableCollection(list));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeType getNodeType(String nodeTypeName)
+            throws NoSuchNodeTypeException {
+        try {
+            QName qName = nsResolver.getQName(nodeTypeName);
+            return getNodeType(qName);
+        } catch (UnknownPrefixException upe) {
+            throw new NoSuchNodeTypeException(nodeTypeName, upe);
+        } catch (IllegalNameException ine) {
+            throw new NoSuchNodeTypeException(nodeTypeName, ine);
+        }
+    }
+    
+    //-----------------------------------------------------------< Dumpable >---
+    /**
+     * {@inheritDoc}
+     */
+    public void dump(PrintStream ps) {
+        ps.println("NodeTypeManager (" + this + ")");
+        ps.println();
+        ps.println("All NodeTypes:");
+        ps.println();
+        try {
+            NodeTypeIterator iter = this.getAllNodeTypes();
+            while (iter.hasNext()) {
+                NodeType nt = iter.nextNodeType();
+                ps.println(nt.getName());
+                NodeType[] supertypes = nt.getSupertypes();
+                ps.println("\tSupertypes");
+                for (int i = 0; i < supertypes.length; i++) {
+                    ps.println("\t\t" + supertypes[i].getName());
+                }
+                ps.println("\tMixin\t" + nt.isMixin());
+                ps.println("\tOrderableChildNodes\t" + nt.hasOrderableChildNodes());
+                ps.println("\tPrimaryItemName\t" + (nt.getPrimaryItemName() == null ? "<null>" : nt.getPrimaryItemName()));
+                PropertyDefinition[] pd = nt.getPropertyDefinitions();
+                for (int i = 0; i < pd.length; i++) {
+                    ps.print("\tPropertyDefinition");
+                    ps.println(" (declared in " + pd[i].getDeclaringNodeType().getName() + ") ");
+                    ps.println("\t\tName\t\t" + (pd[i].getName()));
+                    String type = pd[i].getRequiredType() == 0 ? "null" : PropertyType.nameFromValue(pd[i].getRequiredType());
+                    ps.println("\t\tRequiredType\t" + type);
+                    String[] vca = pd[i].getValueConstraints();
+                    StringBuffer constraints = new StringBuffer();
+                    if (vca == null) {
+                        constraints.append("<null>");
+                    } else {
+                        for (int n = 0; n < vca.length; n++) {
+                            if (constraints.length() > 0) {
+                                constraints.append(", ");
+                            }
+                            constraints.append(vca[n]);
+                        }
+                    }
+                    ps.println("\t\tValueConstraints\t" + constraints.toString());
+                    Value[] defVals = pd[i].getDefaultValues();
+                    StringBuffer defaultValues = new StringBuffer();
+                    if (defVals == null) {
+                        defaultValues.append("<null>");
+                    } else {
+                        for (int n = 0; n < defVals.length; n++) {
+                            if (defaultValues.length() > 0) {
+                                defaultValues.append(", ");
+                            }
+                            defaultValues.append(defVals[n].getString());
+                        }
+                    }
+                    ps.println("\t\tDefaultValue\t" + defaultValues.toString());
+                    ps.println("\t\tAutoCreated\t" + pd[i].isAutoCreated());
+                    ps.println("\t\tMandatory\t" + pd[i].isMandatory());
+                    ps.println("\t\tOnVersion\t" + OnParentVersionAction.nameFromValue(pd[i].getOnParentVersion()));
+                    ps.println("\t\tProtected\t" + pd[i].isProtected());
+                    ps.println("\t\tMultiple\t" + pd[i].isMultiple());
+                }
+                NodeDefinition[] nd = nt.getChildNodeDefinitions();
+                for (int i = 0; i < nd.length; i++) {
+                    ps.print("\tNodeDefinition");
+                    ps.println(" (declared in " + nd[i].getDeclaringNodeType() + ") ");
+                    ps.println("\t\tName\t\t" + nd[i].getName());
+                    NodeType[] reqPrimaryTypes = nd[i].getRequiredPrimaryTypes();
+                    if (reqPrimaryTypes != null && reqPrimaryTypes.length > 0) {
+                        for (int n = 0; n < reqPrimaryTypes.length; n++) {
+                            ps.print("\t\tRequiredPrimaryType\t" + reqPrimaryTypes[n].getName());
+                        }
+                    }
+                    NodeType defPrimaryType = nd[i].getDefaultPrimaryType();
+                    if (defPrimaryType != null) {
+                        ps.print("\n\t\tDefaultPrimaryType\t" + defPrimaryType.getName());
+                    }
+                    ps.println("\n\t\tAutoCreated\t" + nd[i].isAutoCreated());
+                    ps.println("\t\tMandatory\t" + nd[i].isMandatory());
+                    ps.println("\t\tOnVersion\t" + OnParentVersionAction.nameFromValue(nd[i].getOnParentVersion()));
+                    ps.println("\t\tProtected\t" + nd[i].isProtected());
+                    ps.println("\t\tAllowsSameNameSiblings\t" + nd[i].allowsSameNameSiblings());
+                }
+            }
+            ps.println();
+        } catch (RepositoryException e) {
+            e.printStackTrace(ps);
+        }
+    }
+}

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistry.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistry.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistry.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,210 @@
+/*
+ * 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.QName;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.RepositoryException;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * <code>NodeTypeRegistry</code>...
+ *
+ */
+public interface NodeTypeRegistry {
+
+    // TODO: review, probably does not belong into NodeTypeRegistry interface
+    /**
+     * Return the <code>QNodeDefinition</code> of the root node.
+     *
+     * @return
+     */
+    QNodeDefinition getRootNodeDef();
+
+    /**
+     * Returns the node type definition of the node type with the given name.
+     *
+     * @param nodeTypeName name of node type whose definition should be returned.
+     * @return the node type definition of the node type with the given name.
+     * @throws NoSuchNodeTypeException if a node type with the given name
+     *                                 does not exist
+     */
+    QNodeTypeDefinition getNodeTypeDefinition(QName nodeTypeName)
+            throws NoSuchNodeTypeException;
+
+    // TODO: review, probably does not belong into NodeTypeRegistry interface
+    /**
+     *
+     *
+     * @param ntName
+     * @return
+     * @throws NoSuchNodeTypeException
+     */
+    EffectiveNodeType getEffectiveNodeType(QName ntName)
+            throws NoSuchNodeTypeException;
+
+    // TODO: review, probably does not belong into NodeTypeRegistry interface
+    /**
+     *
+     *
+     * @param ntNames
+     * @return
+     * @throws NodeTypeConflictException
+     * @throws NoSuchNodeTypeException
+     */
+    EffectiveNodeType getEffectiveNodeType(QName[] ntNames)
+            throws NodeTypeConflictException, NoSuchNodeTypeException;
+
+    // TODO: review, probably does not belong into NodeTypeRegistry interface
+    /**
+     * @param ntNames
+     * @param ntdMap
+     * @return
+     * @throws NodeTypeConflictException
+     * @throws NoSuchNodeTypeException
+     */
+    EffectiveNodeType getEffectiveNodeType(QName[] ntNames,
+                                           Map ntdMap)
+            throws NodeTypeConflictException, NoSuchNodeTypeException;
+
+
+    /**
+     * Add a <code>NodeTypeRegistryListener</code>
+     *
+     * @param listener the new listener to be informed on (un)registration
+     *                 of node types
+     */
+    void addListener(NodeTypeRegistryListener listener);
+
+    /**
+     * Remove a <code>NodeTypeRegistryListener</code>
+     *
+     * @param listener an existing listener
+     */
+    void removeListener(NodeTypeRegistryListener listener);
+
+    /**
+     * @param ntName
+     * @return
+     */
+    boolean isRegistered(QName ntName);
+
+    /**
+     * Returns the names of all registered node types. That includes primary
+     * and mixin node types.
+     *
+     * @return the names of all registered node types.
+     */
+    public QName[] getRegisteredNodeTypes();
+
+    /**
+     * Validates the <code>NodeTypeDef</code> and returns
+     * a registered <code>EffectiveNodeType</code> instance.
+     * <p/>
+     * The validation includes the following checks:
+     * <ul>
+     * <li>Supertypes must exist and be registered</li>
+     * <li>Inheritance graph must not be circular</li>
+     * <li>Aggregation of supertypes must not result in name conflicts,
+     * ambiguities, etc.</li>
+     * <li>Definitions of auto-created properties must specify a name</li>
+     * <li>Default values in property definitions must satisfy value constraints
+     * specified in the same property definition</li>
+     * <li>Definitions of auto-created child-nodes must specify a name</li>
+     * <li>Default node type in child-node definitions must exist and be
+     * registered</li>
+     * <li>The aggregation of the default node types in child-node definitions
+     * must not result in name conflicts, ambiguities, etc.</li>
+     * <li>Definitions of auto-created child-nodes must not specify default
+     * node types which would lead to infinite child node creation
+     * (e.g. node type 'A' defines auto-created child node with default
+     * node type 'A' ...)</li>
+     * <li>Node types specified as constraints in child-node definitions
+     * must exist and be registered</li>
+     * <li>The aggregation of the node types specified as constraints in
+     * child-node definitions must not result in name conflicts, ambiguities,
+     * etc.</li>
+     * <li>Default node types in child-node definitions must satisfy
+     * node type constraints specified in the same child-node definition</li>
+     * </ul>
+     *
+     * @param ntDef the definition of the new node type
+     * @return an <code>EffectiveNodeType</code> instance
+     * @throws InvalidNodeTypeDefException
+     * @throws RepositoryException
+     */
+    public EffectiveNodeType registerNodeType(QNodeTypeDefinition ntDef)
+            throws InvalidNodeTypeDefException, RepositoryException;
+
+    /**
+     * Same as <code>{@link #registerNodeType(QNodeTypeDefinition)}</code> except
+     * that a collection of <code>NodeTypeDef</code>s is registered instead of
+     * just one.
+     * <p/>
+     * This method can be used to register a set of node types that have
+     * dependencies on each other.
+     * <p/>
+     * Note that in the case an exception is thrown, some node types might have
+     * been nevertheless successfully registered.
+     *
+     * @param ntDefs a collection of <code>NodeTypeDef<code>s
+     * @throws InvalidNodeTypeDefException
+     * @throws RepositoryException
+     */
+    public void registerNodeTypes(Collection ntDefs)
+            throws InvalidNodeTypeDefException, RepositoryException;
+
+    /**
+     * @param nodeTypeName
+     * @throws NoSuchNodeTypeException
+     * @throws RepositoryException
+     */
+    public void unregisterNodeType(QName nodeTypeName)
+            throws NoSuchNodeTypeException, RepositoryException;
+
+    /**
+     * Same as <code>{@link #unregisterNodeType(QName)}</code> except
+     * that a set of node types is unregistered instead of just one.
+     * <p/>
+     * This method can be used to unregister a set of node types that depend on
+     * each other.
+     *
+     * @param nodeTypeNames a collection of <code>QName</code> objects denoting the
+     *                node types to be unregistered
+     * @throws NoSuchNodeTypeException if any of the specified names does not
+     *                                 denote a registered node type.
+     * @throws RepositoryException if another error occurs
+     * @see #unregisterNodeType(QName)
+     */
+    public void unregisterNodeTypes(Collection nodeTypeNames)
+        throws NoSuchNodeTypeException, RepositoryException;
+
+    /**
+     * @param ntd
+     * @return
+     * @throws NoSuchNodeTypeException
+     * @throws InvalidNodeTypeDefException
+     * @throws RepositoryException
+     */
+    public EffectiveNodeType reregisterNodeType(QNodeTypeDefinition ntd)
+            throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+            RepositoryException;
+}

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,837 @@
+/*
+ * 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.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.jcr2spi.util.Dumpable;
+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.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.version.OnParentVersionAction;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A <code>NodeTypeRegistry</code> ...
+ */
+public class NodeTypeRegistryImpl implements Dumpable, NodeTypeRegistry {
+
+    private static Logger log = LoggerFactory.getLogger(NodeTypeRegistryImpl.class);
+
+    // cache of pre-built aggregations of node types
+    private final EffectiveNodeTypeCache entCache;
+
+    // map of node type names and node type definitions
+    private final HashMap registeredNTDefs;
+
+    // definition of the root node
+    private final QNodeDefinition rootNodeDef;
+
+    // map of id's and property definitions
+    private final Set propDefs;
+    // map of id's and node definitions
+    private final Set nodeDefs;
+
+    /**
+     * DIFF JACKRABBIT: persisting nodetypes is delegated to a separate object
+     */
+    private final NodeTypeStorage storage;
+
+    /**
+     * DIFF JACKRABBIT: validation is delegated to extra class
+     */
+    private final DefinitionValidator validator;
+
+
+    // DIFF JR: checkAutoCreatePropHasDefault is set directely on calling validator.validate
+
+    /**
+     * Listeners (soft references)
+     */
+    private final Map listeners = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK));
+
+    /**
+     * Create a new <code>NodeTypeRegistry</codes>
+     *
+     * @param nodeTypeDefs
+     * @param nsRegistry
+     * @return <code>NodeTypeRegistry</codes> object
+     * @throws RepositoryException
+     */
+    public static NodeTypeRegistryImpl create(Collection nodeTypeDefs, NodeTypeStorage storage, QNodeDefinition rootNodeDef, NamespaceRegistry nsRegistry)
+            throws RepositoryException {
+        NodeTypeRegistryImpl ntRegistry = new NodeTypeRegistryImpl(nodeTypeDefs, storage, rootNodeDef, nsRegistry);
+        return ntRegistry;
+    }
+
+    /**
+     * Private constructor
+     *
+     * @param nodeTypeDefs
+     * @param nsRegistry
+     * @throws RepositoryException
+     */
+    private NodeTypeRegistryImpl(Collection nodeTypeDefs, NodeTypeStorage storage, QNodeDefinition rootNodeDef, NamespaceRegistry nsRegistry)
+            throws RepositoryException {
+        this.storage = storage;
+        this.validator = new DefinitionValidator(this, nsRegistry);
+
+        entCache = new EffectiveNodeTypeCache();
+        registeredNTDefs = new HashMap();
+
+        propDefs = new HashSet();
+        nodeDefs = new HashSet();
+
+        // setup definition of root node
+        this.rootNodeDef = rootNodeDef;
+        nodeDefs.add(rootNodeDef);
+
+        try {
+            // validate & register the definitions
+            // DIFF JACKRABBIT: we cannot determine built-in vs. custom nodetypes.
+            // TODO: 'false' flag maybe not totally correct....
+            Map defMap = validator.validateNodeTypeDefs(nodeTypeDefs, new HashMap(registeredNTDefs), false);
+            internalRegister(defMap);
+        } catch (InvalidNodeTypeDefException intde) {
+            String error = "Unexpected error: Found invalid node type definition.";
+            log.debug(error);
+            throw new RepositoryException(error, intde);
+        }
+        // DIFF JR: 'finally' for resetting 'checkAutoCreated' not needed any more...
+    }
+
+
+
+    /**
+     * @inheritDoc
+     */
+    public void addListener(NodeTypeRegistryListener listener) {
+        if (!listeners.containsKey(listener)) {
+            listeners.put(listener, listener);
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public void removeListener(NodeTypeRegistryListener listener) {
+        listeners.remove(listener);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized QName[] getRegisteredNodeTypes() {
+        return (QName[]) registeredNTDefs.keySet().toArray(new QName[registeredNTDefs.size()]);
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized boolean isRegistered(QName nodeTypeName) {
+        return registeredNTDefs.containsKey(nodeTypeName);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public QNodeDefinition getRootNodeDef() {
+        return rootNodeDef;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized EffectiveNodeType getEffectiveNodeType(QName ntName)
+            throws NoSuchNodeTypeException {
+        return getEffectiveNodeType(ntName, entCache, registeredNTDefs);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized EffectiveNodeType getEffectiveNodeType(QName[] ntNames)
+            throws NodeTypeConflictException, NoSuchNodeTypeException {
+        return getEffectiveNodeType(ntNames, entCache, registeredNTDefs);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized EffectiveNodeType getEffectiveNodeType(QName[] ntNames,
+                                                               Map ntdMap)
+        throws NodeTypeConflictException, NoSuchNodeTypeException {
+        return getEffectiveNodeType(ntNames, entCache, ntdMap);
+    }
+
+    // DIFF JR: method private: EffectiveNodeTypeCache must not be exposed in interface
+    /**
+     *
+     * @param ntName
+     * @param anEntCache
+     * @param aRegisteredNTDefCache
+     * @return
+     * @throws NoSuchNodeTypeException
+     */
+    private synchronized EffectiveNodeType getEffectiveNodeType(QName ntName,
+                                                               EffectiveNodeTypeCache anEntCache,
+                                                               Map aRegisteredNTDefCache)
+            throws NoSuchNodeTypeException {
+        // 1. check if effective node type has already been built
+        EffectiveNodeType ent = anEntCache.get(new QName[]{ntName});
+        if (ent != null) {
+            return ent;
+        }
+
+        // 2. make sure that the specified node type exists
+        if (!aRegisteredNTDefCache.containsKey(ntName)) {
+            throw new NoSuchNodeTypeException(ntName.toString());
+        }
+
+        // 3. build effective node type
+        try {
+            QNodeTypeDefinition ntd = (QNodeTypeDefinition) aRegisteredNTDefCache.get(ntName);
+            ent = EffectiveNodeTypeImpl.create(this, ntd, aRegisteredNTDefCache);
+            // store new effective node type
+            anEntCache.put(ent);
+            return ent;
+        } catch (NodeTypeConflictException ntce) {
+            // should never get here as all registered node types have to be valid!
+            String msg = "internal error: encountered invalid registered node type " + ntName;
+            log.debug(msg);
+            throw new NoSuchNodeTypeException(msg, ntce);
+        }
+    }
+
+    // DIFF JR: method private: EffectiveNodeTypeCache must not be exposed in interface
+    /**
+     * @param ntNames
+     * @param anEntCache
+     * @param aRegisteredNTDefCache
+     * @return
+     * @throws NodeTypeConflictException
+     * @throws NoSuchNodeTypeException
+     */
+    private synchronized EffectiveNodeType getEffectiveNodeType(QName[] ntNames,
+                                                               EffectiveNodeTypeCache anEntCache,
+                                                               Map aRegisteredNTDefCache)
+            throws NodeTypeConflictException, NoSuchNodeTypeException {
+
+        EffectiveNodeTypeCache.WeightedKey key =
+                new EffectiveNodeTypeCache.WeightedKey(ntNames);
+
+        // 1. check if aggregate has already been built
+        if (anEntCache.contains(key)) {
+            return anEntCache.get(key);
+        }
+
+        // 2. make sure every single node type exists
+        for (int i = 0; i < ntNames.length; i++) {
+            if (!aRegisteredNTDefCache.containsKey(ntNames[i])) {
+                throw new NoSuchNodeTypeException(ntNames[i].toString());
+            }
+        }
+        // 3. build aggregate
+        EffectiveNodeTypeImpl result = null;
+
+        // build list of 'best' existing sub-aggregates
+        ArrayList tmpResults = new ArrayList();
+        while (key.getNames().length > 0) {
+            // check if we've already built this aggregate
+            if (anEntCache.contains(key)) {
+                tmpResults.add(anEntCache.get(key));
+                // subtract the result from the temporary key
+                // (which is 'empty' now)
+                key = key.subtract(key);
+                break;
+            }
+            /**
+             * walk list of existing aggregates sorted by 'weight' of
+             * aggregate (i.e. the cost of building it)
+             */
+            boolean foundSubResult = false;
+            Iterator iter = anEntCache.keyIterator();
+            while (iter.hasNext()) {
+                EffectiveNodeTypeCache.WeightedKey k =
+                        (EffectiveNodeTypeCache.WeightedKey) iter.next();
+                /**
+                 * check if the existing aggregate is a 'subset' of the one
+                 * we're looking for
+                 */
+                if (key.contains(k)) {
+                    tmpResults.add(anEntCache.get(k));
+                    // subtract the result from the temporary key
+                    key = key.subtract(k);
+                    foundSubResult = true;
+                    break;
+                }
+            }
+            if (!foundSubResult) {
+                /**
+                 * no matching sub-aggregates found:
+                 * build aggregate of remaining node types through iteration
+                 */
+                QName[] remainder = key.getNames();
+                for (int i = 0; i < remainder.length; i++) {
+                    QNodeTypeDefinition ntd = (QNodeTypeDefinition) aRegisteredNTDefCache.get(remainder[i]);
+                    EffectiveNodeTypeImpl ent =
+                            EffectiveNodeTypeImpl.create(this, ntd, aRegisteredNTDefCache);
+                    // store new effective node type
+                    anEntCache.put(ent);
+                    if (result == null) {
+                        result = ent;
+                    } else {
+                        result = result.merge(ent);
+                        // store intermediate result (sub-aggregate)
+                        anEntCache.put(result);
+                    }
+                }
+                // add aggregate of remaining node types to result list
+                tmpResults.add(result);
+                break;
+            }
+        }
+        // merge the sub-aggregates into new effective node type
+        for (int i = 0; i < tmpResults.size(); i++) {
+            if (result == null) {
+                result = (EffectiveNodeTypeImpl) tmpResults.get(i);
+            } else {
+                result = result.merge((EffectiveNodeTypeImpl) tmpResults.get(i));
+                // store intermediate result
+                anEntCache.put(result);
+            }
+        }
+        // we're done
+        return result;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized EffectiveNodeType registerNodeType(QNodeTypeDefinition ntDef)
+            throws InvalidNodeTypeDefException, RepositoryException {
+        // validate the new nodetype definition
+        EffectiveNodeTypeImpl ent = validator.validateNodeTypeDef(ntDef, registeredNTDefs, true);
+
+        // persist new node type definition
+        storage.registerNodeTypes(new QNodeTypeDefinition[] {ntDef});
+
+        // update internal caches
+        internalRegister(ntDef, ent);
+
+        // notify listeners
+        notifyRegistered(ntDef.getQName());
+        return ent;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized void registerNodeTypes(Collection ntDefs)
+            throws InvalidNodeTypeDefException, RepositoryException {
+
+        // validate new nodetype definitions
+        Map defMap = validator.validateNodeTypeDefs(ntDefs, registeredNTDefs, true);
+        storage.registerNodeTypes((QNodeTypeDefinition[])ntDefs.toArray(new QNodeTypeDefinition[ntDefs.size()]));
+
+        // update internal cache
+        internalRegister(defMap);
+
+        // notify listeners
+        for (Iterator iter = ntDefs.iterator(); iter.hasNext();) {
+            QName ntName = ((QNodeTypeDefinition)iter.next()).getQName();
+            notifyRegistered(ntName);
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized void unregisterNodeType(QName nodeTypeName)
+            throws NoSuchNodeTypeException, RepositoryException {
+
+        // perform basic validation
+        if (!registeredNTDefs.containsKey(nodeTypeName)) {
+            throw new NoSuchNodeTypeException(nodeTypeName.toString());
+        }
+        // DIFF JACKRABBIT: detection of built-in NodeTypes not possible
+        // omit check for build-in nodetypes which would cause failure
+
+        /**
+         * check if there are node types that have dependencies on the given
+         * node type
+         */
+        if (hasDependentNodeTypes(nodeTypeName)) {
+            StringBuffer msg = new StringBuffer();
+            msg.append(nodeTypeName + " could not be removed because registered node types are still referencing it.");
+            throw new RepositoryException(msg.toString());
+        }
+
+        // make sure node type is not currently in use
+        checkForReferencesInContent(nodeTypeName);
+
+        // persist removal of node type definition
+        storage.unregisterNodeTypes(new QName[] {nodeTypeName});
+
+        // update internal cache
+        internalUnregister(nodeTypeName);
+
+        // notify listeners
+        notifyUnregistered(nodeTypeName);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized void unregisterNodeTypes(Collection nodeTypeNames)
+            throws NoSuchNodeTypeException, RepositoryException {
+        // do some preliminary checks
+        for (Iterator iter = nodeTypeNames.iterator(); iter.hasNext();) {
+            QName ntName = (QName) iter.next();
+            if (!registeredNTDefs.containsKey(ntName)) {
+                throw new NoSuchNodeTypeException(ntName.toString());
+            }
+            // DIFF JR: no distiction of built-in nts
+
+            // check for node types other than those to be unregistered
+            // that depend on the given node types
+            Set dependents = getDependentNodeTypes(ntName);
+            dependents.removeAll(nodeTypeNames);
+            if (dependents.size() > 0) {
+                StringBuffer msg = new StringBuffer();
+                msg.append(ntName
+                        + " can not be removed because the following node types depend on it: ");
+                for (Iterator depIter = dependents.iterator(); depIter.hasNext();) {
+                    msg.append(depIter.next());
+                    msg.append(" ");
+                }
+                throw new RepositoryException(msg.toString());
+            }
+        }
+
+        // make sure node types are not currently in use
+        for (Iterator iter = nodeTypeNames.iterator(); iter.hasNext();) {
+            QName ntName = (QName) iter.next();
+            checkForReferencesInContent(ntName);
+        }
+
+
+
+        // persist removal of node type definitions
+        storage.unregisterNodeTypes((QName[]) nodeTypeNames.toArray(new QName[nodeTypeNames.size()]));
+
+
+        // all preconditions are met, node types can now safely be unregistered
+        internalUnregister(nodeTypeNames);
+
+        // notify listeners
+        for (Iterator iter = nodeTypeNames.iterator(); iter.hasNext();) {
+            QName ntName = (QName) iter.next();
+            notifyUnregistered(ntName);
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized EffectiveNodeType reregisterNodeType(QNodeTypeDefinition ntd)
+            throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+            RepositoryException {
+        QName name = ntd.getQName();
+        if (!registeredNTDefs.containsKey(name)) {
+            throw new NoSuchNodeTypeException(name.toString());
+        }
+        // DIFF JACKRABBIT: detection of built-in NodeTypes not possible
+        // omit check for build-in nodetypes which would cause failure
+
+        /**
+         * validate new node type definition
+         */
+        EffectiveNodeTypeImpl ent = validator.validateNodeTypeDef(ntd, registeredNTDefs, true);
+
+        // DIFF JACKRABBIT: removed check for severity of nt modification
+
+        // first call reregistering on storage
+        storage.reregisterNodeTypes(new QNodeTypeDefinition[]{ntd});
+
+        // unregister old node type definition
+        internalUnregister(name);
+        // register new definition
+        internalRegister(ntd, ent);
+
+        // notify listeners
+        notifyReRegistered(name);
+        return ent;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized QNodeTypeDefinition getNodeTypeDefinition(QName nodeTypeName)
+            throws NoSuchNodeTypeException {
+        if (!registeredNTDefs.containsKey(nodeTypeName)) {
+            throw new NoSuchNodeTypeException(nodeTypeName.toString());
+        }
+        QNodeTypeDefinition def = (QNodeTypeDefinition) registeredNTDefs.get(nodeTypeName);
+        return def;
+    }
+
+    //------------------------------------------------------------< private >---
+    /**
+     * Notify the listeners that a node type <code>ntName</code> has been registered.
+     */
+    private void notifyRegistered(QName ntName) {
+        // copy listeners to array to avoid ConcurrentModificationException
+        NodeTypeRegistryListener[] la =
+                new NodeTypeRegistryListener[listeners.size()];
+        Iterator iter = listeners.values().iterator();
+        int cnt = 0;
+        while (iter.hasNext()) {
+            la[cnt++] = (NodeTypeRegistryListener) iter.next();
+        }
+        for (int i = 0; i < la.length; i++) {
+            if (la[i] != null) {
+                la[i].nodeTypeRegistered(ntName);
+            }
+        }
+    }
+
+    /**
+     * Notify the listeners that a node type <code>ntName</code> has been re-registered.
+     */
+    private void notifyReRegistered(QName ntName) {
+        // copy listeners to array to avoid ConcurrentModificationException
+        NodeTypeRegistryListener[] la = new NodeTypeRegistryListener[listeners.size()];
+        Iterator iter = listeners.values().iterator();
+        int cnt = 0;
+        while (iter.hasNext()) {
+            la[cnt++] = (NodeTypeRegistryListener) iter.next();
+        }
+        for (int i = 0; i < la.length; i++) {
+            if (la[i] != null) {
+                la[i].nodeTypeReRegistered(ntName);
+            }
+        }
+    }
+
+    /**
+     * Notify the listeners that a node type <code>ntName</code> has been unregistered.
+     */
+    private void notifyUnregistered(QName ntName) {
+        // copy listeners to array to avoid ConcurrentModificationException
+        NodeTypeRegistryListener[] la = new NodeTypeRegistryListener[listeners.size()];
+        Iterator iter = listeners.values().iterator();
+        int cnt = 0;
+        while (iter.hasNext()) {
+            la[cnt++] = (NodeTypeRegistryListener) iter.next();
+        }
+        for (int i = 0; i < la.length; i++) {
+            if (la[i] != null) {
+                la[i].nodeTypeUnregistered(ntName);
+            }
+        }
+    }
+
+    private void internalRegister(Map defMap) {
+        Iterator it = defMap.keySet().iterator();
+        while (it.hasNext()) {
+            QNodeTypeDefinition ntd = (QNodeTypeDefinition)it.next();
+            internalRegister(ntd, (EffectiveNodeTypeImpl)defMap.get(ntd));
+        }
+    }
+
+    private void internalRegister(QNodeTypeDefinition ntd, EffectiveNodeTypeImpl ent) {
+
+        // store new effective node type instance
+        entCache.put(ent);
+        // register nt-definition
+        registeredNTDefs.put(ntd.getQName(), ntd);
+
+        // store property & child node definitions of new node type by id
+        QPropertyDefinition[] pda = ntd.getPropertyDefs();
+        for (int i = 0; i < pda.length; i++) {
+            propDefs.add(pda[i]);
+        }
+        QNodeDefinition[] nda = ntd.getChildNodeDefs();
+        for (int i = 0; i < nda.length; i++) {
+            nodeDefs.add(nda[i]);
+        }
+    }
+
+    private void internalUnregister(QName name) {
+        // DIFF JACKRABBIT: check for registered name removed, since duplicate code
+
+        // DIFF JACKRABBIT: detection of built-in NodeTypes not possible
+        // omit check for build-in nodetypes which would cause failure
+
+        QNodeTypeDefinition ntd = (QNodeTypeDefinition) registeredNTDefs.get(name);
+        registeredNTDefs.remove(name);
+        /**
+         * remove all affected effective node types from aggregates cache
+         * (copy keys first to prevent ConcurrentModificationException)
+         */
+        ArrayList keys = new ArrayList(entCache.keySet());
+        for (Iterator keysIter = keys.iterator(); keysIter.hasNext();) {
+            EffectiveNodeTypeCache.WeightedKey k =
+                    (EffectiveNodeTypeCache.WeightedKey) keysIter.next();
+            EffectiveNodeType ent = entCache.get(k);
+            if (ent.includesNodeType(name)) {
+                entCache.remove(k);
+            }
+        }
+
+        // remove property & child node definitions
+        QPropertyDefinition[] pda = ntd.getPropertyDefs();
+        for (int i = 0; i < pda.length; i++) {
+            propDefs.remove(pda[i]);
+        }
+        QNodeDefinition[] nda = ntd.getChildNodeDefs();
+        for (int i = 0; i < nda.length; i++) {
+            nodeDefs.remove(nda[i]);
+        }
+    }
+
+    private void internalUnregister(Collection ntNames) {
+        for (Iterator iter = ntNames.iterator(); iter.hasNext();) {
+            QName name = (QName) iter.next();
+            internalUnregister(name);
+        }
+    }
+
+    /**
+     * Returns the names of those registered node types that have
+     * dependencies on the given node type.
+     *
+     * @param nodeTypeName
+     * @return a set of node type <code>QName</code>s
+     * @throws NoSuchNodeTypeException
+     */
+    private synchronized boolean hasDependentNodeTypes(QName nodeTypeName)
+            throws NoSuchNodeTypeException {
+        if (!registeredNTDefs.containsKey(nodeTypeName)) {
+            throw new NoSuchNodeTypeException(nodeTypeName.toString());
+        }
+        Iterator iter = registeredNTDefs.values().iterator();
+        while (iter.hasNext()) {
+            QNodeTypeDefinition ntd = (QNodeTypeDefinition) iter.next();
+            if (ntd.getDependencies().contains(nodeTypeName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+   /**
+     * Returns the names of those registered node types that have
+     * dependencies on the given node type.
+     *
+     * @param nodeTypeName node type name
+     * @return a set of node type <code>QName</code>s
+     * @throws NoSuchNodeTypeException
+     */
+    private synchronized Set getDependentNodeTypes(QName nodeTypeName)
+            throws NoSuchNodeTypeException {
+        if (!registeredNTDefs.containsKey(nodeTypeName)) {
+            throw new NoSuchNodeTypeException(nodeTypeName.toString());
+        }
+
+        /**
+         * collect names of those node types that have dependencies on the given
+         * node type
+         */
+        HashSet names = new HashSet();
+        Iterator iter = registeredNTDefs.values().iterator();
+        while (iter.hasNext()) {
+            QNodeTypeDefinition ntd = (QNodeTypeDefinition) iter.next();
+            if (ntd.getDependencies().contains(nodeTypeName)) {
+                names.add(ntd.getQName());
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Checks whether there is existing content that would conflict with the
+     * given node type definition.
+     * <p/>
+     * This method is not implemented yet and always throws a
+     * <code>RepositoryException</code>.
+     * <p/>
+     * TODO
+     * <ol>
+     * <li>apply deep locks on root nodes in every workspace or alternatively
+     * put repository in 'exclusive' or 'single-user' mode
+     * <li>check if the given node type (or any node type that has
+     * dependencies on this node type) is currently referenced by nodes
+     * in the repository.
+     * <li>check if applying the changed definitions to the affected items would
+     * violate existing node type constraints
+     * <li>apply and persist changes to affected nodes (e.g. update
+     * definition id's, etc.)
+     * </ul>
+     * <p/>
+     * the above checks/actions are absolutely necessary in order to
+     * guarantee integrity of repository content.
+     *
+     * @param ntd The node type definition replacing the former node type
+     *            definition of the same name.
+     * @throws RepositoryException If there is conflicting content or if the
+     *                             check failed for some other reason.
+     */
+    private void checkForConflictingContent(QNodeTypeDefinition ntd)
+            throws RepositoryException {
+        /**
+         * collect names of node types that have dependencies on the given
+         * node type
+         */
+        //Set dependentNTs = getDependentNodeTypes(ntd.getQName());
+
+        throw new RepositoryException("not yet implemented");
+    }
+
+    /**
+     * Checks whether there is existing content that directly or indirectly
+     * refers to the specified node type.
+     * <p/>
+     * This method is not implemented yet and always throws a
+     * <code>RepositoryException</code>.
+     * <p/>
+     * TODO:
+     * <ol>
+     * <li>apply deep locks on root nodes in every workspace or alternatively
+     * put repository in 'single-user' mode
+     * <li>check if the given node type is currently referenced by nodes
+     * in the repository.
+     * <li>remove the node type if it is not currently referenced, otherwise
+     * throw exception
+     * </ul>
+     * <p/>
+     * the above checks are absolutely necessary in order to guarantee
+     * integrity of repository content.
+     *
+     * @param nodeTypeName The name of the node type to be checked.
+     * @throws RepositoryException If the specified node type is currently
+     *                             being referenced or if the check failed for
+     *                             some other reason.
+     */
+    private void checkForReferencesInContent(QName nodeTypeName)
+            throws RepositoryException {
+        throw new RepositoryException("not yet implemented");
+    }
+    //-----------------------------------------------------------< Dumpable >---
+    /**
+     * {@inheritDoc}
+     */
+    public void dump(PrintStream ps) {
+        ps.println("NodeTypeRegistry (" + this + ")");
+        ps.println();
+        ps.println("Registered NodeTypes:");
+        ps.println();
+        Iterator iter = registeredNTDefs.values().iterator();
+        while (iter.hasNext()) {
+            QNodeTypeDefinition ntd = (QNodeTypeDefinition) iter.next();
+            ps.println(ntd.getQName());
+            QName[] supertypes = ntd.getSupertypes();
+            ps.println("\tSupertypes");
+            for (int i = 0; i < supertypes.length; i++) {
+                ps.println("\t\t" + supertypes[i]);
+            }
+            ps.println("\tMixin\t" + ntd.isMixin());
+            ps.println("\tOrderableChildNodes\t" + ntd.hasOrderableChildNodes());
+            ps.println("\tPrimaryItemName\t" + (ntd.getPrimaryItemName() == null ? "<null>" : ntd.getPrimaryItemName().toString()));
+            QPropertyDefinition[] pd = ntd.getPropertyDefs();
+            for (int i = 0; i < pd.length; i++) {
+                ps.print("\tPropertyDefinition");
+                ps.println(" (declared in " + pd[i].getDeclaringNodeType() + ") ");
+                ps.println("\t\tName\t\t" + (pd[i].definesResidual() ? "*" : pd[i].getQName().toString()));
+                String type = pd[i].getRequiredType() == 0 ? "null" : PropertyType.nameFromValue(pd[i].getRequiredType());
+                ps.println("\t\tRequiredType\t" + type);
+                String[] vca = pd[i].getValueConstraints();
+                StringBuffer constraints = new StringBuffer();
+                if (vca == null) {
+                    constraints.append("<null>");
+                } else {
+                    for (int n = 0; n < vca.length; n++) {
+                        if (constraints.length() > 0) {
+                            constraints.append(", ");
+                        }
+                        constraints.append(vca[n]);
+                    }
+                }
+                ps.println("\t\tValueConstraints\t" + constraints.toString());
+                String[] defVals = pd[i].getDefaultValues();
+                StringBuffer defaultValues = new StringBuffer();
+                if (defVals == null) {
+                    defaultValues.append("<null>");
+                } else {
+                    for (int n = 0; n < defVals.length; n++) {
+                        if (defaultValues.length() > 0) {
+                            defaultValues.append(", ");
+                        }
+                        defaultValues.append(defVals[n]);
+                    }
+                }
+                ps.println("\t\tDefaultValue\t" + defaultValues.toString());
+                ps.println("\t\tAutoCreated\t" + pd[i].isAutoCreated());
+                ps.println("\t\tMandatory\t" + pd[i].isMandatory());
+                ps.println("\t\tOnVersion\t" + OnParentVersionAction.nameFromValue(pd[i].getOnParentVersion()));
+                ps.println("\t\tProtected\t" + pd[i].isProtected());
+                ps.println("\t\tMultiple\t" + pd[i].isMultiple());
+            }
+            QNodeDefinition[] nd = ntd.getChildNodeDefs();
+            for (int i = 0; i < nd.length; i++) {
+                ps.print("\tNodeDefinition");
+                ps.println(" (declared in " + nd[i].getDeclaringNodeType() + ") ");
+                ps.println("\t\tName\t\t" + (nd[i].definesResidual() ? "*" : nd[i].getQName().toString()));
+                QName[] reqPrimaryTypes = nd[i].getRequiredPrimaryTypes();
+                if (reqPrimaryTypes != null && reqPrimaryTypes.length > 0) {
+                    for (int n = 0; n < reqPrimaryTypes.length; n++) {
+                        ps.print("\t\tRequiredPrimaryType\t" + reqPrimaryTypes[n]);
+                    }
+                }
+                QName defPrimaryType = nd[i].getDefaultPrimaryType();
+                if (defPrimaryType != null) {
+                    ps.print("\n\t\tDefaultPrimaryType\t" + defPrimaryType);
+                }
+                ps.println("\n\t\tAutoCreated\t" + nd[i].isAutoCreated());
+                ps.println("\t\tMandatory\t" + nd[i].isMandatory());
+                ps.println("\t\tOnVersion\t" + OnParentVersionAction.nameFromValue(nd[i].getOnParentVersion()));
+                ps.println("\t\tProtected\t" + nd[i].isProtected());
+                ps.println("\t\tAllowsSameNameSiblings\t" + nd[i].allowsSameNameSiblings());
+            }
+        }
+        ps.println();
+
+        entCache.dump(ps);
+    }
+}

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryListener.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryListener.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryListener.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,50 @@
+/*
+ * 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.QName;
+
+/**
+ * The <code>NodeTypeRegistryListener</code> interface allows an implementing
+ * object to be informed about node type (un)registration.
+ *
+ * @see NodeTypeRegistry#addListener(NodeTypeRegistryListener)
+ * @see NodeTypeRegistry#removeListener(NodeTypeRegistryListener)
+ */
+public interface NodeTypeRegistryListener {
+
+    /**
+     * Called when a node type has been registered.
+     *
+     * @param ntName name of the node type that has been registered
+     */
+    void nodeTypeRegistered(QName ntName);
+
+    /**
+     * Called when a node type has been re-registered.
+     *
+     * @param ntName name of the node type that has been registered
+     */
+    void nodeTypeReRegistered(QName ntName);
+
+    /**
+     * Called when a node type has been deregistered.
+     *
+     * @param ntName name of the node type that has been unregistered
+     */
+    void nodeTypeUnregistered(QName ntName);
+}

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeStorage.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeStorage.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeStorage.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeStorage.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,35 @@
+/*
+ * 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.QName;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>NodeTypeStorage</code>...
+ */
+public interface NodeTypeStorage {
+
+    public void registerNodeTypes(QNodeTypeDefinition[] nodeTypeDefs) throws NoSuchNodeTypeException, RepositoryException;
+
+    public void reregisterNodeTypes(QNodeTypeDefinition[] nodeTypeDefs) throws NoSuchNodeTypeException, RepositoryException;
+
+    public void unregisterNodeTypes(QName[] nodeTypeNames) throws NoSuchNodeTypeException, RepositoryException;
+}
\ No newline at end of file

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/PropertyDefinitionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/PropertyDefinitionImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/PropertyDefinitionImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/PropertyDefinitionImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,120 @@
+/*
+ * 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.spi.QPropertyDefinition;
+import org.apache.jackrabbit.value.QValue;
+import org.apache.jackrabbit.value.ValueFormat;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.nodetype.PropertyDefinition;
+
+/**
+ * This class implements the <code>PropertyDefinition</code> interface.
+ * All method calls are delegated to the wrapped {@link QPropertyDefinition},
+ * performing the translation from <code>QName</code>s to JCR names
+ * (and vice versa) where necessary.
+ */
+public class PropertyDefinitionImpl extends ItemDefinitionImpl implements PropertyDefinition {
+
+    /**
+     * Logger instance for this class
+     */
+    private static Logger log = LoggerFactory.getLogger(PropertyDefinitionImpl.class);
+
+    private final ValueFactory valueFactory;
+    
+    /**
+     * Package private constructor
+     *
+     * @param propDef    property definition
+     * @param ntMgr      node type manager
+     * @param nsResolver namespace resolver
+     */
+    PropertyDefinitionImpl(QPropertyDefinition propDef, NodeTypeManagerImpl ntMgr,
+                           NamespaceResolver nsResolver, ValueFactory valueFactory) {
+        super(propDef, ntMgr, nsResolver);
+        this.valueFactory = valueFactory;
+    }
+
+    //---------------------------------------------------< PropertyDefinition >
+    /**
+     * {@inheritDoc}
+     */
+    public Value[] getDefaultValues() {
+        QValue[] defVals = QValue.create(((QPropertyDefinition) itemDef).getDefaultValues());
+        if (defVals == null) {
+            return null;
+        }
+        Value[] values = new Value[defVals.length];
+        for (int i = 0; i < defVals.length; i++) {
+            try {
+                values[i] = ValueFormat.getJCRValue(defVals[i], nsResolver, valueFactory);
+            } catch (RepositoryException re) {
+                // should never get here
+                String propName = (getName() == null) ? "[null]" : getName();
+                log.error("illegal default value specified for property "
+                        + propName + " in node type " + getDeclaringNodeType(),
+                        re);
+                return null;
+            }
+        }
+        return values;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getRequiredType() {
+        return ((QPropertyDefinition) itemDef).getRequiredType();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] getValueConstraints() {
+        QPropertyDefinition pd = (QPropertyDefinition)itemDef;
+        String[] constraints = pd.getValueConstraints();
+        if (constraints == null || constraints.length == 0) {
+            return new String[0];
+        }
+        try {
+            String[] vca = new String[constraints.length];
+            for (int i = 0; i < constraints.length; i++) {
+                ValueConstraint constr = ValueConstraint.create(pd.getRequiredType(), constraints[i]);
+                vca[i] = constr.getDefinition(nsResolver);
+            }
+            return vca;
+        } catch (InvalidConstraintException e) {
+            log.error("Invalid value constraint: " + e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMultiple() {
+        return ((QPropertyDefinition) itemDef).isMultiple();
+    }
+}
+

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

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



Mime
View raw message