/*
* 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;
}
}