/* * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.jcr.impl.core.nodetype; import org.exoplatform.services.jcr.core.nodetype.NodeDefinitionData; import org.exoplatform.services.jcr.core.nodetype.NodeTypeData; import org.exoplatform.services.jcr.core.nodetype.PropertyDefinitionData; import org.exoplatform.services.jcr.core.nodetype.PropertyDefinitionDatas; import org.exoplatform.services.jcr.datamodel.InternalQName; import org.exoplatform.services.jcr.impl.Constants; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * Created by The eXo Platform SAS. <br> * Per-repository component holding all Child Nodes and Properties Definitions * as flat Map For ex definition for jcr:primaryType will be repeated as many * times as many primary nodetypes is registered (as each primary nodetype * extends nt:base directly or indirectly) and so on. * * @author Gennady Azarenkov * @version $Id: ItemDefinitionDataHolder.java 11907 2008-03-13 15:36:21Z ksm $ */ public class ItemDefinitionDataHolder { private static Log LOG = ExoLogger.getLogger("exo.jcr.component.core.ItemDefinitionDataHolder"); private final Map<InternalQName, Map<InternalQName, Map<InternalQName, NodeDefinitionData>>> nodeDefinitions; private final Map<InternalQName, Map<InternalQName, Map<Boolean, PropertyDefinitionData>>> propertyDefinitions; private final Map<InternalQName, Map<InternalQName, NodeDefinitionData>> defNodeDefinitions; public ItemDefinitionDataHolder() { this.nodeDefinitions = new HashMap<InternalQName, Map<InternalQName, Map<InternalQName, NodeDefinitionData>>>(); this.propertyDefinitions = new HashMap<InternalQName, Map<InternalQName, Map<Boolean, PropertyDefinitionData>>>(); this.defNodeDefinitions = new HashMap<InternalQName, Map<InternalQName, NodeDefinitionData>>(); } private ItemDefinitionDataHolder( Map<InternalQName, Map<InternalQName, Map<InternalQName, NodeDefinitionData>>> nodeDefinitions, Map<InternalQName, Map<InternalQName, Map<Boolean, PropertyDefinitionData>>> propertyDefinitions, Map<InternalQName, Map<InternalQName, NodeDefinitionData>> defNodeDefinitions) { this.nodeDefinitions = nodeDefinitions; this.propertyDefinitions = propertyDefinitions; this.defNodeDefinitions = defNodeDefinitions; } /** * @param parentNodeType - name of parent node type * @param childName name of child node * @param childNodeType name of child node type * @return Child NodeDefinition or null if not found */ public NodeDefinitionData getChildNodeDefinition(InternalQName parentNodeType, InternalQName childName, InternalQName childNodeType) { NodeDefinitionData def = getNodeDefinitionFromThisOrSupertypes(parentNodeType, childName, childNodeType); return def; } /** * @param childName name of child node * @param nodeTypes name of parent node types * @return default ChildNodeDefinition or null if not found */ public NodeDefinitionData getDefaultChildNodeDefinition(InternalQName childName, InternalQName... nodeTypes) { for (InternalQName parentNodeType : nodeTypes) { NodeDefinitionData def = getNodeDefinitionDataInternal(parentNodeType, childName); if (def != null) return def; } // residual for (InternalQName parentNodeType : nodeTypes) { NodeDefinitionData def = getNodeDefinitionDataInternal(parentNodeType, Constants.JCR_ANY_NAME); if (def != null) return def; } return null; } /** * @param parentNodeType name of parent node type * @param childName name of child property * @param multiValued * @return Child PropertyDefinition or null if not found */ public PropertyDefinitionData getPropertyDefinition(InternalQName childName, boolean multiValued, InternalQName parentNodeType) { PropertyDefinitionData def = getPropertyDefinitionInternal(parentNodeType, childName, multiValued); // try residual def if (def == null) { return getPropertyDefinitionInternal(parentNodeType, Constants.JCR_ANY_NAME, multiValued); } return def; } /** * @param propertyName name of child property * @param nodeTypes name of parent node type * @return Child PropertyDefinition or null if not found */ public PropertyDefinitionDatas getPropertyDefinitions(final InternalQName propertyName, final InternalQName... nodeTypes) { PropertyDefinitionDatas pdefs = new PropertyDefinitionDatas(); for (InternalQName nt : nodeTypes) { // single-valued PropertyDefinitionData def = getPropertyDefinitionInternal(nt, propertyName, false); if (def != null && pdefs.getDefinition(def.isMultiple()) == null) pdefs.setDefinition(def); // set if same is not exists // multi-valued def = getPropertyDefinitionInternal(nt, propertyName, true); if (def != null && pdefs.getDefinition(def.isMultiple()) == null) pdefs.setDefinition(def); // set if same is not exists // try residual } return pdefs.getAnyDefinition() != null ? pdefs : null; } /** * adds Child Node/Property Definitions for incoming NodeType (should be * called by NodeTypeManager in register method) * * @param nodeType */ void putDefinitions(InternalQName name, NodeTypeData nodeType) { // put child node defs NodeDefinitionData[] nodeDefs = nodeType.getDeclaredChildNodeDefinitions(); for (NodeDefinitionData nodeDef : nodeDefs) { // put required node type defs for (InternalQName rnt : nodeDef.getRequiredPrimaryTypes()) { addNodeDefinitionDataInternal(name, nodeDef.getName(), rnt, nodeDef); if (LOG.isDebugEnabled()) { LOG.debug("NodeDef added: parent NT: " + name.getAsString() + " child nodeName: " + nodeDef.getName().getAsString() + " childNT: " + rnt.getAsString()); } } // put default node definition addNodeDefinitionDataInternal(name, nodeDef.getName(), nodeDef); if (LOG.isDebugEnabled()) { LOG.debug("Default NodeDef added: parent NT: " + name.getAsString() + " child nodeName: " + nodeDef.getName()); } } // put prop defs PropertyDefinitionData[] propDefs = nodeType.getDeclaredPropertyDefinitions(); for (PropertyDefinitionData propDef : propDefs) { addPropertyDefinitionInternal(name, propDef.getName(), propDef.isMultiple(), propDef); if (LOG.isDebugEnabled()) { LOG.debug("PropDef added: parent NT: " + name.getAsString() + " child propName: " + propDef.getName().getAsString() + " isMultiple: " + propDef.isMultiple()); } } } void removeDefinitions(InternalQName name, NodeTypeData nodeType) { // remove child node defs NodeDefinitionData[] nodeDefs = nodeType.getDeclaredChildNodeDefinitions(); for (NodeDefinitionData nodeDef : nodeDefs) { // remove required node type defs for (InternalQName rnt : nodeDef.getRequiredPrimaryTypes()) { removeNodeDefinitionDataInternal(name, nodeDef.getName(), rnt); if (LOG.isDebugEnabled()) { LOG.debug("NodeDef removed: parent NT: " + name.getAsString() + " child nodeName: " + nodeDef.getName().getAsString() + " childNT: " + rnt.getAsString()); } } // remove default node definition removeNodeDefinitionDataInternal(name, nodeDef.getName()); if (LOG.isDebugEnabled()) { LOG.debug("Default NodeDef removed: parent NT: " + name.getAsString() + " child nodeName: " + nodeDef.getName()); } } // remove defs PropertyDefinitionData[] propDefs = nodeType.getDeclaredPropertyDefinitions(); for (PropertyDefinitionData propDef : propDefs) { removePropertyDefinitionInternal(name, propDef.getName(), propDef.isMultiple()); if (LOG.isDebugEnabled()) { LOG.debug("PropDef remode: parent NT: " + name.getAsString() + " child propName: " + propDef.getName().getAsString() + " isMultiple: " + propDef.isMultiple()); } } } private NodeDefinitionData getNodeDefinitionFromThisOrSupertypes(InternalQName parentNodeType, InternalQName childName, InternalQName childNodeType) { NodeDefinitionData def = getNodeDefinitionDataInternal(parentNodeType, childName, childNodeType); if (def != null) return def; return def; } private NodeDefinitionData getNodeDefinitionDataInternal(InternalQName parentNodeType, InternalQName childName) { Map<InternalQName, NodeDefinitionData> defs = defNodeDefinitions.get(parentNodeType); if (defs == null) { return null; } return defs.get(childName); } private void addNodeDefinitionDataInternal(InternalQName parentNodeType, InternalQName childName, NodeDefinitionData nodeDef) { Map<InternalQName, NodeDefinitionData> defs = defNodeDefinitions.get(parentNodeType); if (defs == null) { defs = new HashMap<InternalQName, NodeDefinitionData>(); defNodeDefinitions.put(parentNodeType, defs); } defs.put(childName, nodeDef); } private void removeNodeDefinitionDataInternal(InternalQName parentNodeType, InternalQName childName) { Map<InternalQName, NodeDefinitionData> defs = defNodeDefinitions.get(parentNodeType); if (defs == null) { return; } defs.remove(childName); } private PropertyDefinitionData getPropertyDefinitionInternal(InternalQName parentNodeType, InternalQName childName, boolean multiValued) { Map<InternalQName, Map<Boolean, PropertyDefinitionData>> defs = propertyDefinitions.get(parentNodeType); if (defs == null) { return null; } Map<Boolean, PropertyDefinitionData> def = defs.get(childName); if (def == null) { return null; } return def.get(multiValued); } private void addPropertyDefinitionInternal(InternalQName parentNodeType, InternalQName childName, boolean multiValued, PropertyDefinitionData propDef) { Map<InternalQName, Map<Boolean, PropertyDefinitionData>> defs = propertyDefinitions.get(parentNodeType); if (defs == null) { defs = new HashMap<InternalQName, Map<Boolean, PropertyDefinitionData>>(); propertyDefinitions.put(parentNodeType, defs); } Map<Boolean, PropertyDefinitionData> def = defs.get(childName); if (def == null) { def = new HashMap<Boolean, PropertyDefinitionData>(); defs.put(childName, def); } def.put(multiValued, propDef); } private void removePropertyDefinitionInternal(InternalQName parentNodeType, InternalQName childName, boolean multiValued) { Map<InternalQName, Map<Boolean, PropertyDefinitionData>> defs = propertyDefinitions.get(parentNodeType); if (defs == null) { return; } Map<Boolean, PropertyDefinitionData> def = defs.get(childName); if (def == null) { return; } def.remove(multiValued); } private NodeDefinitionData getNodeDefinitionDataInternal(InternalQName parentNodeType, InternalQName childName, InternalQName childNodeType) { Map<InternalQName, Map<InternalQName, NodeDefinitionData>> defs = nodeDefinitions.get(parentNodeType); if (defs == null) { return null; } Map<InternalQName, NodeDefinitionData> def = defs.get(childName); if (def == null) { return null; } return def.get(childNodeType); } private void addNodeDefinitionDataInternal(InternalQName parentNodeType, InternalQName childName, InternalQName childNodeType, NodeDefinitionData nodeDef) { Map<InternalQName, Map<InternalQName, NodeDefinitionData>> defs = nodeDefinitions.get(parentNodeType); if (defs == null) { defs = new HashMap<InternalQName, Map<InternalQName, NodeDefinitionData>>(); nodeDefinitions.put(parentNodeType, defs); } Map<InternalQName, NodeDefinitionData> def = defs.get(childName); if (def == null) { def = new HashMap<InternalQName, NodeDefinitionData>(); defs.put(childName, def); } def.put(childNodeType, nodeDef); } private void removeNodeDefinitionDataInternal(InternalQName parentNodeType, InternalQName childName, InternalQName childNodeType) { Map<InternalQName, Map<InternalQName, NodeDefinitionData>> defs = nodeDefinitions.get(parentNodeType); if (defs == null) { return; } Map<InternalQName, NodeDefinitionData> def = defs.get(childName); if (def == null) { return; } def.remove(childNodeType); } /** * Create copy of holder. * * @return */ protected ItemDefinitionDataHolder createCopy() { return new ItemDefinitionDataHolder(cloneMap(nodeDefinitions), cloneMap(propertyDefinitions), cloneMap(defNodeDefinitions)); } @SuppressWarnings("unchecked") private static <K, V> Map<K, V> cloneMap(Map<? extends K, ? extends V> map) { Map<K, V> copyMap = (Map<K, V>)((HashMap<K, V>)map).clone(); for (Entry<K, V> entry : copyMap.entrySet()) { if (entry.getValue() instanceof Map<?, ?>) { entry.setValue((V)cloneMap((Map<?, ?>)entry.getValue())); } } return copyMap; } }