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 [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...
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