Package org.jahia.services.content.nodetypes

Source Code of org.jahia.services.content.nodetypes.ExtendedNodeType

/**
* This file is part of Jahia, next-generation open source CMS:
* Jahia's next-generation, open source CMS stems from a widely acknowledged vision
* of enterprise application convergence - web, search, document, social and portal -
* unified by the simplicity of web content management.
*
* For more information, please visit http://www.jahia.com.
*
* Copyright (C) 2002-2011 Jahia Solutions Group SA. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* As a special exception to the terms and conditions of version 2.0 of
* the GPL (or any later version), you may redistribute this Program in connection
* with Free/Libre and Open Source Software ("FLOSS") applications as described
* in Jahia's FLOSS exception. You should have received a copy of the text
* describing the FLOSS exception, and it is also available here:
* http://www.jahia.com/license
*
* Commercial and Supported Versions of the program (dual licensing):
* alternatively, commercial and supported versions of the program may be used
* in accordance with the terms and conditions contained in a separate
* written agreement between you and Jahia Solutions Group SA.
*
* If you are unsure which license is appropriate for your use,
* please contact the sales department at sales@jahia.com.
*/

package org.jahia.services.content.nodetypes;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.spi.commons.nodetype.constraint.ValueConstraint;
import org.apache.jackrabbit.spi.commons.value.QValueValue;
import org.slf4j.Logger;
import org.jahia.api.Constants;
import org.jahia.data.templates.JahiaTemplatesPackage;
import org.jahia.registries.ServicesRegistry;
import org.jahia.utils.i18n.JahiaResourceBundle;
import org.jahia.utils.i18n.JahiaTemplatesRBLoader;

import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.nodetype.*;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* Jahia extended JCR node type information.
* @author Thomas Draier
* Date: 4 janv. 2008
* Time: 14:02:22
*/
public class ExtendedNodeType implements NodeType {

    private static final transient Logger logger = org.slf4j.LoggerFactory.getLogger(ExtendedNodeType.class);
    public static final Name NT_BASE_NAME = new Name("base", org.apache.jackrabbit.spi.Name.NS_NT_PREFIX, org.apache.jackrabbit.spi.Name.NS_NT_URI);
   
    private NodeTypeRegistry registry;
    private String systemId;
    private List<ExtendedItemDefinition> items = new ArrayList<ExtendedItemDefinition>();
    private List<String> groupedItems;

    private Map<String, ExtendedNodeDefinition> nodes = new ConcurrentHashMap<String, ExtendedNodeDefinition>();
    private Map<String, ExtendedPropertyDefinition> properties = new ConcurrentHashMap<String, ExtendedPropertyDefinition>();
    private Map<String, ExtendedNodeDefinition> unstructuredNodes = new ConcurrentHashMap<String, ExtendedNodeDefinition>();
    private Map<Integer, ExtendedPropertyDefinition> unstructuredProperties = new ConcurrentHashMap<Integer, ExtendedPropertyDefinition>();

    private Map<String, ExtendedNodeDefinition> allNodes;
    private Map<String, ExtendedPropertyDefinition> allProperties;
    private Map<String, ExtendedNodeDefinition> allUnstructuredNodes;
    private Map<Integer, ExtendedPropertyDefinition> allUnstructuredProperties;

    private Name name;
    private String alias;
    private boolean isAbstract;
    private boolean isMixin;
    private boolean hasOrderableChildNodes;
    private String primaryItemName;
    private String[] declaredSupertypeNames = new String[0];
    private ExtendedNodeType[] declaredSupertypes = new ExtendedNodeType[0];
    private List<ExtendedNodeType> declaredSubtypes = new ArrayList<ExtendedNodeType>();
    private String validator;
    private boolean queryable = true;
    private String itemsType;
    private List<String> mixinExtendNames = new ArrayList<String>();
    private List<ExtendedNodeType> mixinExtend = new ArrayList<ExtendedNodeType>();
//    private boolean liveContent = false;

    private Map<Locale, String> labels = new ConcurrentHashMap<Locale, String>(1);
    private Map<Locale, String> descriptions = new ConcurrentHashMap<Locale, String>(1);
    public ExtendedNodeType(NodeTypeRegistry registry, String systemId) {
        this.registry = registry;
        this.systemId = systemId;
    }

    public String getSystemId() {
        return systemId;
    }

    public String getName() {
        return name.toString();
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public Name getNameObject() {
        return name;
    }

    public void setName(Name name) {
        this.name = name;
        this.alias = name != null ? name.toString() : null;
    }

    public boolean isAbstract() {
        return isAbstract;
    }

    public void setAbstract(boolean anAbstract) {
        isAbstract = anAbstract;
    }

    public boolean isMixin() {
        return isMixin;
    }

    public void setMixin(boolean mixin) {
        isMixin = mixin;
    }

//    public boolean isLiveContent() {
//        return liveContent;
//    }
//
//    public void setLiveContent(boolean liveContent) {
//        this.liveContent = liveContent;
//    }

    public boolean hasOrderableChildNodes() {
        if(!hasOrderableChildNodes) {
            return hasOrderableChildNodes(true);
        }
        return hasOrderableChildNodes;
    }

    private boolean hasOrderableChildNodes(boolean checkSupertypes) {
        if (checkSupertypes) {
            final ExtendedNodeType[] supertypes = getSupertypes();
            for (ExtendedNodeType supertype : supertypes) {
                if (supertype.hasOrderableChildNodes(false)) {
                    return true;
                }
            }
            return false;
        }
        return hasOrderableChildNodes;
    }

    public void setHasOrderableChildNodes(boolean hasOrderableChildNodes) {
        this.hasOrderableChildNodes = hasOrderableChildNodes;
    }

    public boolean isQueryable() {
        return queryable;
    }

    public void setQueryable(boolean queryable) {
        this.queryable = queryable;
    }

    public String getPrimaryItemName() {
        return primaryItemName;
    }

    public void setPrimaryItemName(String primaryItemName) {
        this.primaryItemName = primaryItemName;
    }


    public ExtendedNodeType[] getSupertypes() {
        Set<ExtendedNodeType> l = new LinkedHashSet<ExtendedNodeType>();
        boolean primaryFound = false;
        ExtendedNodeType[] d = getDeclaredSupertypes();
        for (int i = 0; i < d.length; i++) {
            ExtendedNodeType s = d[i];
            if (s != null) {
                l.add(s);
                l.addAll(Arrays.asList(s.getSupertypes()));
                if (!s.isMixin()) {
                    primaryFound = true;
                }
            }
        }
        if (!primaryFound && !Constants.NT_BASE.equals(getName()) && !isMixin) {
            try {
                l.add(registry.getNodeType(Constants.NT_BASE));
            } catch (NoSuchNodeTypeException e) {
                logger.error("No such supertype for "+getName(),e);
            }
        }
        return new ArrayList<ExtendedNodeType>(l).toArray(new ExtendedNodeType[l.size()]);
    }

    public ExtendedNodeType[] getPrimarySupertypes() {
        List<ExtendedNodeType> l = new ArrayList<ExtendedNodeType>();
        boolean primaryFound = false;
        ExtendedNodeType[] d = getDeclaredSupertypes();
        for (int i = 0; i < d.length; i++) {
            ExtendedNodeType s = d[i];
            if (s != null && !s.isMixin()) {
                l.add(s);
                l.addAll(Arrays.asList(s.getPrimarySupertypes()));
                primaryFound = true;
            }
        }
        if (!primaryFound && !Constants.NT_BASE.equals(name.toString()) && !isMixin) {
            try {
                l.add(registry.getNodeType(Constants.NT_BASE));
            } catch (NoSuchNodeTypeException e) {
                logger.error("No such supertype for "+getName(),e);
            }
        }
        return l.toArray(new ExtendedNodeType[l.size()]);
    }

    public ExtendedNodeType[] getDeclaredSupertypes() {
        return declaredSupertypes;
    }

    public void setDeclaredSupertypes(String[] declaredSupertypes) {
        this.declaredSupertypeNames = declaredSupertypes;
    }


    void validate() throws NoSuchNodeTypeException {
        this.declaredSupertypes = new ExtendedNodeType[declaredSupertypeNames.length];
        int mixIndex = 0;
        for (int i = 0; i < declaredSupertypeNames.length; i++) {
            final ExtendedNodeType nodeType = registry.getNodeType(declaredSupertypeNames[i]);
            if (!nodeType.isMixin && i>0) {
                System.arraycopy(this.declaredSupertypes, mixIndex, this.declaredSupertypes, mixIndex+1, i-mixIndex);
                this.declaredSupertypes[mixIndex] = nodeType;
                mixIndex ++;
            } else {
                this.declaredSupertypes[i] = nodeType;
            }
            nodeType.addSubType(this);
        }
        for (String s : mixinExtendNames) {
            final ExtendedNodeType type = registry.getNodeType(s);
            registry.addMixinExtension(this, type);
            mixinExtend.add(type);
        }
        for (ExtendedItemDefinition itemDefinition : items) {
            if (itemDefinition.getItemType() != null) {
                registry.addTypedItem(itemDefinition);
            }
        }
    }

    void addSubType(ExtendedNodeType subType) {
        declaredSubtypes.remove(subType);
        declaredSubtypes.add(subType);
    }

    public NodeTypeIterator getDeclaredSubtypes() {
        return new NodeTypeIteratorImpl(declaredSubtypes.iterator(), declaredSubtypes.size());
    }

    public String[] getDeclaredSupertypeNames() {
        return declaredSupertypeNames;
    }


    public NodeTypeIterator getSubtypes() {
        List<ExtendedNodeType> l = new ArrayList<ExtendedNodeType>();
        for (Iterator<ExtendedNodeType> iterator = declaredSubtypes.iterator(); iterator.hasNext();) {
            ExtendedNodeType s =  iterator.next();
            l.add(s);
            NodeTypeIterator subtypes = s.getSubtypes();
            while (subtypes.hasNext()) {
                l.add((ExtendedNodeType) subtypes.next());
            }
        }
        return new NodeTypeIteratorImpl(l.iterator(), l.size());
    }

    public List<ExtendedNodeType> getSubtypesAsList() {
        List<ExtendedNodeType> l = new ArrayList<ExtendedNodeType>();
        for (Iterator<ExtendedNodeType> iterator = declaredSubtypes.iterator(); iterator.hasNext();) {
            ExtendedNodeType s =  iterator.next();
            l.add(s);
            NodeTypeIterator subtypes = s.getSubtypes();
            while (subtypes.hasNext()) {
                l.add((ExtendedNodeType) subtypes.next());
            }
        }
        return l;
    }

    public ExtendedNodeType[] getMixinSubtypes() {
        List<ExtendedNodeType> l = new ArrayList<ExtendedNodeType>();
        for (Iterator<ExtendedNodeType> iterator = declaredSubtypes.iterator(); iterator.hasNext();) {
            ExtendedNodeType s =  iterator.next();
            if (s.isMixin()) {
                l.add(s);
                l.addAll(Arrays.asList(s.getMixinSubtypes()));
            }
        }
        return l.toArray(new ExtendedNodeType[l.size()]);
    }

    public boolean isNodeType(String typeName) {
        if (getName().equals(typeName) || Constants.NT_BASE.equals(typeName)) {
            return true;
        }
        ExtendedNodeType[] d = getDeclaredSupertypes();
        for (int i = 0; i < d.length; i++) {
            ExtendedNodeType s = d[i];
            if (s.isNodeType(typeName)) {
                return true;
            }
        }
        return false;
    }

    public List<ExtendedItemDefinition>  getItems() {
        List<ExtendedItemDefinition> l = new ArrayList<ExtendedItemDefinition>();
        l.addAll(getDeclaredItems());

        ExtendedNodeType[] supertypes = getSupertypes();
        for (int i = 0; i < supertypes.length ; i++) {
            l.addAll(supertypes[i].getDeclaredItems());
        }

        return l;
    }

    public List<ExtendedItemDefinition>  getDeclaredItems() {
        getPropertyDefinitionsAsMap();
        getChildNodeDefinitionsAsMap();
        List<ExtendedItemDefinition> res = new ArrayList<ExtendedItemDefinition>();
        for (ExtendedItemDefinition item : items) {
            if (!item.isOverride()) {
                res.add(item);
            }
        }
        return Collections.unmodifiableList(res);
    }

    public Map<String, ExtendedPropertyDefinition> getPropertyDefinitionsAsMap() {
        if (allProperties == null) {
          synchronized (this) {
            if (allProperties == null) {
              LinkedHashMap<String, ExtendedPropertyDefinition> props = new LinkedHashMap<String, ExtendedPropertyDefinition>();
   
                props.putAll(properties);
   
                ExtendedNodeType[] supertypes = getSupertypes();
                for (int i = supertypes.length-1; i >=0 ; i--) {
                    ExtendedNodeType nodeType = supertypes[i];
                    Map<String, ExtendedPropertyDefinition> c = new HashMap<String, ExtendedPropertyDefinition>(nodeType.getDeclaredPropertyDefinitionsAsMap());
                    Map<String, ExtendedPropertyDefinition> over = new HashMap<String, ExtendedPropertyDefinition>(properties);
                    over.keySet().retainAll(c.keySet());
                    for (ExtendedPropertyDefinition s : over.values()) {
                        s.setOverride(true);
                    }
                    c.keySet().removeAll(over.keySet());
                    props.putAll(c);
                }
               
                allProperties = Collections.unmodifiableMap(props);
            }
          }
        }

        return allProperties;
    }

    public Map<Integer,ExtendedPropertyDefinition> getUnstructuredPropertyDefinitions() {
        if (allUnstructuredProperties == null) {
            allUnstructuredProperties = new LinkedHashMap<Integer,ExtendedPropertyDefinition>();

            allUnstructuredProperties.putAll(unstructuredProperties);

            ExtendedNodeType[] supertypes = getSupertypes();
            for (int i = supertypes.length-1; i >=0 ; i--) {
                ExtendedNodeType nodeType = supertypes[i];
                Map<Integer,ExtendedPropertyDefinition> c = new HashMap<Integer,ExtendedPropertyDefinition>(nodeType.getDeclaredUnstructuredPropertyDefinitions());
                Map<Integer,ExtendedPropertyDefinition> over = new HashMap<Integer,ExtendedPropertyDefinition>(unstructuredProperties);
                over.keySet().retainAll(c.keySet());
                for (ExtendedPropertyDefinition s : over.values()) {
                    s.setOverride(true);
                }
                c.keySet().removeAll(over.keySet());
                allUnstructuredProperties.putAll(c);
            }
        }
        return Collections.unmodifiableMap(allUnstructuredProperties);
    }

    public ExtendedPropertyDefinition[] getPropertyDefinitions() {
        List<ExtendedPropertyDefinition> list = new ArrayList<ExtendedPropertyDefinition>();
        Set<String> keys = new HashSet<String>();

        final List<ExtendedItemDefinition> i = getItems();
        Collections.reverse(i);
        for (ExtendedItemDefinition item : i) {
            if (!item.isNode() && ("*".equals(item.getName()) || !keys.contains(item.getName()))) {
                list.add((ExtendedPropertyDefinition) item);
                keys.add(item.getName());
            }
        }
        Collections.reverse(list);
        return list.toArray(new ExtendedPropertyDefinition[list.size()]);
    }

    public Map<String, ExtendedPropertyDefinition> getDeclaredPropertyDefinitionsAsMap() {
        getPropertyDefinitionsAsMap();
        return properties;
    }

    public Map<Integer,ExtendedPropertyDefinition> getDeclaredUnstructuredPropertyDefinitions() {
        getUnstructuredPropertyDefinitions();
        return unstructuredProperties;
    }

    public ExtendedPropertyDefinition[] getDeclaredPropertyDefinitions() {
        List<ExtendedPropertyDefinition> list = new ArrayList<ExtendedPropertyDefinition>();

        final List<ExtendedItemDefinition> i = getDeclaredItems();
        for (ExtendedItemDefinition item : i) {
            if (!item.isNode()) { // && ("*".equals(item.getName()) || !keys.contains(item.getName()))) {
                    list.add((ExtendedPropertyDefinition) item);
            }
        }
        return list.toArray(new ExtendedPropertyDefinition[list.size()]);
    }

    public Map<String, ExtendedNodeDefinition> getChildNodeDefinitionsAsMap() {
        if (allNodes == null) {
            allNodes = new LinkedHashMap<String, ExtendedNodeDefinition>();
            ExtendedNodeType[] supertypes = getSupertypes();
            for (int i = supertypes.length-1; i >=0 ; i--) {
                ExtendedNodeType nodeType = supertypes[i];
                Map<String, ExtendedNodeDefinition> c = new HashMap<String, ExtendedNodeDefinition>(nodeType.getDeclaredChildNodeDefinitionsAsMap());
                Map<String, ExtendedNodeDefinition> over = new HashMap<String, ExtendedNodeDefinition>(nodes);
                over.keySet().retainAll(c.keySet());
                for (ExtendedNodeDefinition s : over.values()) {
                    s.setOverride(true);
                }
                c.keySet().removeAll(over.keySet());
                allNodes.putAll(c);
            }

            allNodes.putAll(nodes);
        }

        return Collections.unmodifiableMap(allNodes);
    }

    public Map<String,ExtendedNodeDefinition> getUnstructuredChildNodeDefinitions() {
        if (allUnstructuredNodes == null) {
            allUnstructuredNodes = new ConcurrentHashMap<String,ExtendedNodeDefinition>();
            allUnstructuredNodes.putAll(unstructuredNodes);

            ExtendedNodeType[] supertypes = getSupertypes();
            for (int i = supertypes.length-1; i >=0 ; i--) {
                ExtendedNodeType nodeType = supertypes[i];
                Map<String,ExtendedNodeDefinition> c = new HashMap<String,ExtendedNodeDefinition>(nodeType.getDeclaredUnstructuredChildNodeDefinitions());
                Map<String,ExtendedNodeDefinition> over = new HashMap<String,ExtendedNodeDefinition>(unstructuredNodes);
                over.keySet().retainAll(c.keySet());
                for (ExtendedNodeDefinition s : over.values()) {
                    s.setOverride(true);
                }
                c.keySet().removeAll(over.keySet());
                allUnstructuredNodes.putAll(c);
            }
        }
        return Collections.unmodifiableMap(allUnstructuredNodes);
    }

    public ExtendedNodeDefinition[] getChildNodeDefinitions() {
        List<ExtendedNodeDefinition> list = new ArrayList<ExtendedNodeDefinition>();
        Set<String> keys = new HashSet<String>();
        final List<ExtendedItemDefinition> i = getItems();
        Collections.reverse(i);
        for (ExtendedItemDefinition item : i) {
            if (item.isNode() && ("*".equals(item.getName()) || !keys.contains(item.getName()))) {
                list.add((ExtendedNodeDefinition) item);
                keys.add(item.getName());
            }
        }
        Collections.reverse(list);
        return list.toArray(new ExtendedNodeDefinition[list.size()]);
    }

    public Map<String, ExtendedNodeDefinition> getDeclaredChildNodeDefinitionsAsMap() {
        getChildNodeDefinitionsAsMap();
        return nodes;
    }

    public Map<String,ExtendedNodeDefinition> getDeclaredUnstructuredChildNodeDefinitions() {
        getUnstructuredChildNodeDefinitions();
        return unstructuredNodes;
    }

    public ExtendedNodeDefinition[] getDeclaredChildNodeDefinitions() {
        List<ExtendedNodeDefinition> list = new ArrayList<ExtendedNodeDefinition>();
        final List<ExtendedItemDefinition> i = getDeclaredItems();
        for (ExtendedItemDefinition item : i) {
            if (item.isNode()) { // && ("*".equals(item.getName()) || !keys.contains(item.getName()))) {
                    list.add((ExtendedNodeDefinition) item);
            }
        }
        return list.toArray(new ExtendedNodeDefinition[list.size()]);
    }

    public List<String> getGroupedItems() {
        return groupedItems;
    }

    public void setGroupedItems(List<String> groupedItems) {
        this.groupedItems = groupedItems;
    }

    public boolean canSetProperty(String propertyName, Value value) {
        if (value == null) {
            // setting a property to null is equivalent of removing it
            return canRemoveItem(propertyName);
        }
        try {
            ExtendedPropertyDefinition def = getPropertyDefinitionsAsMap()
                    .containsKey(propertyName) ? getPropertyDefinitionsAsMap().get(propertyName)
                    : getMatchingPropDef(getUnstructuredPropertyDefinitions().values(),
                            value.getType(), false);
            if (def == null) {
                def = getMatchingPropDef(getUnstructuredPropertyDefinitions().values(),
                        PropertyType.UNDEFINED, false);
            }
            if (def != null) {
                if (def.isMultiple() || def.isProtected()) {
                    return false;
                }
                int targetType;
                if (def.getRequiredType() != PropertyType.UNDEFINED
                        && def.getRequiredType() != value.getType()) {
                    // type conversion required
                    targetType = def.getRequiredType();
                } else {
                    // no type conversion required
                    targetType = value.getType();
                }
                // perform type conversion as necessary and create InternalValue
                // from (converted) Value
                InternalValue internalValue = null;
                if (targetType != value.getType()) {
                    // type conversion required, but Jahia cannot do it, because we have no valueFactory, resolver, store or session object here
                    // Value targetVal = ValueHelper.convert(
                    // value, targetType,
                    // valueFactory);
                    if (value.getType() != PropertyType.BINARY
                            && !((value.getType() == PropertyType.PATH || value.getType() == PropertyType.NAME) && !(value instanceof QValueValue))) {
                        internalValue = InternalValue.create(value, null, null);
                    }
                } else {
                    // no type conversion required
                    if (value.getType() != PropertyType.BINARY
                            && !((value.getType() == PropertyType.PATH || value.getType() == PropertyType.NAME) && !(value instanceof QValueValue))) {
                        internalValue = InternalValue.create(value, null, null);
                    }
                }
                if (internalValue != null) {
                    checkSetPropertyValueConstraints(def, new InternalValue[] { internalValue });
                }
                return true;
            }
        } catch (RepositoryException e) {
            // fall through
        }
        return false;
    }

    public boolean canSetProperty(String propertyName, Value[] values) {
        if (values == null) {
            // setting a property to null is equivalent of removing it
            return canRemoveItem(propertyName);
        }
        try {
            // determine type of values
            int type = PropertyType.UNDEFINED;
            for (Value value : values) {
                if (value == null) {
                    // skip null values as those would be purged
                    continue;
                }
                if (type == PropertyType.UNDEFINED) {
                    type = value.getType();
                } else if (type != value.getType()) {
                    // inhomogeneous types
                    return false;
                }
            }
            ExtendedPropertyDefinition def = getPropertyDefinitionsAsMap()
                    .containsKey(propertyName) ? getPropertyDefinitionsAsMap().get(propertyName)
                    : getMatchingPropDef(getUnstructuredPropertyDefinitions().values(), type, true);
            if (def == null) {
                def = getMatchingPropDef(getUnstructuredPropertyDefinitions().values(),
                        PropertyType.UNDEFINED, true);
            }
            if (def != null) {
                if (!def.isMultiple() || def.isProtected()) {
                    return false;
                }
                int targetType;
                if (def.getRequiredType() != PropertyType.UNDEFINED
                        && def.getRequiredType() != type) {
                    // type conversion required, but Jahia cannot do it, because we have no valueFactory, resolver, store or session object here
                    targetType = def.getRequiredType();
                } else {
                    // no type conversion required
                    targetType = type;
                }
                List<InternalValue> list = new ArrayList<InternalValue>();
                for (Value value : values) {
                    if (value != null) {
                        // perform type conversion as necessary and create InternalValue
                        // from (converted) Value
                        InternalValue internalValue = null;
                        if (targetType != value.getType()) {
                            // type conversion required
                            // Value targetVal = ValueHelper.convert(
                            // value, targetType,
                            // valueFactory);
                            if (value.getType() != PropertyType.BINARY
                                    && !((value.getType() == PropertyType.PATH || value.getType() == PropertyType.NAME) && !(value instanceof QValueValue))) {
                                internalValue = InternalValue.create(value, null, null);
                            }
                        } else {
                            // no type conversion required
                            if (value.getType() != PropertyType.BINARY
                                    && !((value.getType() == PropertyType.PATH || value.getType() == PropertyType.NAME) && !(value instanceof QValueValue))) {
                                internalValue = InternalValue.create(value, null, null);
                            }
                        }
                        list.add(internalValue);
                    }
                }
                if (!list.isEmpty()) {
                    InternalValue[] internalValues = list.toArray(new InternalValue[list.size()]);
                    checkSetPropertyValueConstraints(def, internalValues);
                }
                return true;
            }
        } catch (RepositoryException e) {
            // fall through
        }
        return false;
    }

    public boolean canAddChildNode(String childNodeName) {
        if (getChildNodeDefinitionsAsMap().containsKey(childNodeName)) {
            if (getChildNodeDefinitionsAsMap().get(childNodeName).getDefaultPrimaryType() != null) {
                return true;
            }
        }
        return false;
    }

    public boolean canAddChildNode(String childNodeName, String nodeTypeName) {
        try {
            ExtendedNodeType nt = NodeTypeRegistry.getInstance().getNodeType(nodeTypeName);
            if (!nt.isAbstract() && !nt.isMixin()) {
                if (getChildNodeDefinitionsAsMap().containsKey(childNodeName)) {
                    if (canAddChildNode(nt,getChildNodeDefinitionsAsMap().get(childNodeName)))  {
                        return true;
                    }
                }
                Collection<ExtendedNodeDefinition> unstruct = getUnstructuredChildNodeDefinitions().values();
                for (ExtendedNodeDefinition definition : unstruct) {
                    if (canAddChildNode(nt,definition))  {
                        return true;
                    }
                }
            }
        } catch (RepositoryException e) {
            // fall through
        }
        return false;
    }
   
    private boolean canAddChildNode(ExtendedNodeType nt, ExtendedNodeDefinition nodeDef) {
        String[] epd = nodeDef.getRequiredPrimaryTypeNames();
        for (String s : epd) {
            if (!nt.isNodeType(s)) {
                return false;
            }
        }
        return true;
    }   

    public boolean canRemoveItem(String s) {
        try {
            checkRemoveItemConstraints(s);
            return true;
        } catch (RepositoryException re) {
            // fall through
        }
        return false;
    }

    public boolean canRemoveNode(String nodeName) {
        try {
            checkRemoveNodeConstraints(nodeName);
            return true;
        } catch (RepositoryException re) {
            // fall through
        }
        return true;
    }

    public boolean canRemoveProperty(String propertyName) {
        try {
            checkRemovePropertyConstraints(propertyName);
            return true;
        } catch (RepositoryException re) {
            // fall through
        }
        return false;
    }

    void setPropertyDefinition(String name, ExtendedPropertyDefinition p) {
        if (name.equals("*")) {
            if (p.isMultiple()) {
                unstructuredProperties.put(256 + p.getRequiredType(), p);
            } else {
                unstructuredProperties.put(p.getRequiredType(), p);
            }
        } else {
            properties.put(name, p);
        }
        items.add(p);
    }

    public ExtendedPropertyDefinition getPropertyDefinition(String name) {
        return properties.get(name);
    }

    void setNodeDefinition(String name, ExtendedNodeDefinition p) {
        if (name.equals("*")) {
            StringBuffer s = new StringBuffer("");
            if (p.getRequiredPrimaryTypeNames() == null) {
                logger.error("Required primary type names is null for extended node definition " + p);
            }
            for (String s1 : p.getRequiredPrimaryTypeNames()) {
                s.append(s1).append(" ");
            }
            unstructuredNodes.put(s.toString().trim(), p);
        } else {
            nodes.put(name, p);
        }
        items.add(p);
    }

    public ExtendedNodeDefinition getNodeDefinition(String name) {
        return nodes.get(name);
    }

    public String getValidator() {
        return validator;
    }

    public void setValidator(String validator) {
        this.validator = validator;
    }

    public String getItemsType() {
        return itemsType;
    }

    public void setItemsType(String itemsType) {
        this.itemsType = itemsType;
    }

    public void addMixinExtend(String mixinExtension) {
        this.mixinExtendNames.add(mixinExtension);
    }

    public List<ExtendedNodeType> getMixinExtends() {
        return mixinExtend;
    }

    public JahiaTemplatesPackage getTemplatePackage() {
        JahiaTemplatesPackage pkg = null;
        if (!getSystemId().startsWith("system-")) {
            try {
                pkg = ServicesRegistry.getInstance()
                        .getJahiaTemplateManagerService().getTemplatePackage(
                                getSystemId());
            } catch (Exception e) {
                logger.warn(
                        "Unable to get the template package for the node with system id '"
                                + getSystemId() + "'", e);
            }
        }

        return pkg;
    }

    protected String getResourceBundleId() {
        JahiaTemplatesPackage pkg = getTemplatePackage();
        return pkg != null ? "modules." + pkg.getRootFolder() + "." + pkg.getResourceBundleName() : "JahiaTypesResources";
    }

    public String getLabel(Locale locale) {
        String label = labels.get(locale);
        if (label == null) {
            String key = getName().replace(':', '_');
            String tpl = getTemplatePackage() != null ? getTemplatePackage().getName() : null;
            label = new JahiaResourceBundle(getResourceBundleId(), locale, tpl, JahiaTemplatesRBLoader
                    .getInstance(Thread.currentThread().getContextClassLoader(), tpl)).getString(key, StringUtils.substringAfter(getName(),":"));
            labels.put(locale, label);
        }
        return label;
    }

    public String getDescription(Locale locale) {
        String description = descriptions.get(locale);
        if (description == null) {
            String key = getName().replace(':', '_') + "_description";
            String tpl = getTemplatePackage() != null ? getTemplatePackage().getName() : null;
            description = new JahiaResourceBundle(getResourceBundleId(), locale, tpl, JahiaTemplatesRBLoader
                    .getInstance(Thread.currentThread().getContextClassLoader(), tpl)).getString(key, "");
            descriptions.put(locale, description);
        }
        return description;
    }

    public NodeTypeDefinition getNodeTypeDefinition() {
        return new Definition();
    }

    public String getLocalName() {
         return this.name.getLocalName();
    }

    public String getPrefix() {
        return this.name.getPrefix();
    }

    class Definition implements NodeTypeDefinition {
        public String getName() {
            return name.toString();
        }

        public String[] getDeclaredSupertypeNames() {
            String[] d = declaredSupertypeNames;

            ExtendedPropertyDefinition[] defs = ExtendedNodeType.this.getDeclaredPropertyDefinitions();
            for (ExtendedPropertyDefinition def : defs) {
                if (def.isInternationalized()) {
                    String[] newRes = new String[d.length+1];
                    System.arraycopy(d, 0, newRes, 0, d.length);
                    newRes[d.length] = "jmix:i18n";
                    return newRes;
                }
            }

            return d;
        }

        public boolean isAbstract() {
            return isAbstract;
        }

        public boolean isMixin() {
            return isMixin;
        }

        public boolean hasOrderableChildNodes() {
            return hasOrderableChildNodes;
        }

        public boolean isQueryable() {
            return true;
        }

        public String getPrimaryItemName() {
            return primaryItemName;
        }

        public PropertyDefinition[] getDeclaredPropertyDefinitions() {
            ExtendedPropertyDefinition[] defs = ExtendedNodeType.this.getDeclaredPropertyDefinitions();
            List<PropertyDefinition> r = new ArrayList<PropertyDefinition>();
            for (final ExtendedPropertyDefinition def : defs) {
                if (!def.isInternationalized() && !def.isOverride()) {
                    r.add(new PropertyDefinition() {
                        public int getRequiredType() {
                            return def.getRequiredType() != PropertyType.REFERENCE ? def.getRequiredType() : PropertyType.WEAKREFERENCE;
                        }

                        public String[] getValueConstraints() {
                            return def.getValueConstraints();
                        }

                        public Value[] getDefaultValues() {
                            return def.getDefaultValues();
                        }

                        public boolean isMultiple() {
                            return def.isMultiple();
                        }

                        public String[] getAvailableQueryOperators() {
                            return def.getAvailableQueryOperators();
                        }

                        public boolean isFullTextSearchable() {
                            return def.isFullTextSearchable();
                        }

                        public boolean isQueryOrderable() {
                            return def.isQueryOrderable();
                        }

                        public NodeType getDeclaringNodeType() {
                            return def.getDeclaringNodeType();
                        }

                        public String getName() {
                            return def.getName();
                        }

                        public boolean isAutoCreated() {
                            return def.isAutoCreated();
                        }

                        public boolean isMandatory() {
                            return false;
                        }

                        public int getOnParentVersion() {
                            return def.getOnParentVersion();
                        }

                        public boolean isProtected() {
                            return false;
                        }
                    });
                }
            }
            return r.toArray(new PropertyDefinition[r.size()]);
        }

        public NodeDefinition[] getDeclaredChildNodeDefinitions() {
            ExtendedNodeDefinition[] defs = ExtendedNodeType.this.getDeclaredChildNodeDefinitions();


            List<NodeDefinition> r = new ArrayList<NodeDefinition>();
            for (final ExtendedNodeDefinition def : defs) {
                if (!def.isOverride()) {
                    r.add(new NodeDefinition() {
                        public NodeType[] getRequiredPrimaryTypes() {
                            return def.getRequiredPrimaryTypes();
                        }

                        public String[] getRequiredPrimaryTypeNames() {
                            return def.getRequiredPrimaryTypeNames();
                        }

                        public NodeType getDefaultPrimaryType() {
                            return def.getDefaultPrimaryType();
                        }

                        public String getDefaultPrimaryTypeName() {
                            return def.getDefaultPrimaryTypeName();
                        }

                        public boolean allowsSameNameSiblings() {
                            return def.allowsSameNameSiblings();
                        }

                        public NodeType getDeclaringNodeType() {
                            return def.getDeclaringNodeType();
                        }

                        public String getName() {
                            return def.getName();
                        }

                        public boolean isAutoCreated() {
                            return false;
                        }

                        public boolean isMandatory() {
                            return false;
                        }

                        public int getOnParentVersion() {
                            return def.getOnParentVersion();
                        }

                        public boolean isProtected() {
                            return false;
                        }
                    });
                }
            }
            return r.toArray(new NodeDefinition[r.size()]);
        }
    }
   
    /**
     * @param s
     * @throws ConstraintViolationException
     */
    private void checkRemoveItemConstraints(String s) throws ConstraintViolationException {
        ExtendedItemDefinition def = getPropertyDefinitionsAsMap().get(name);
        if (def == null) {
            def = getChildNodeDefinitionsAsMap().get(name);
        }
        if (def != null) {
            if (def.isMandatory()) {
                throw new ConstraintViolationException("can't remove mandatory item");
            }
            if (def.isProtected()) {
                throw new ConstraintViolationException("can't remove protected item");
            }
        }
    }

    /**
     * @param name
     * @throws ConstraintViolationException
     */
    private void checkRemoveNodeConstraints(String name) throws ConstraintViolationException {
        ExtendedNodeDefinition def = getChildNodeDefinitionsAsMap().get(name);
        if (def != null) {
                if (def.isMandatory()) {
                    throw new ConstraintViolationException("can't remove mandatory node");
                }
                if (def.isProtected()) {
                    throw new ConstraintViolationException("can't remove protected node");
                }
        }
    }

    /**
     * @param propertyName
     * @throws ConstraintViolationException
     */
    private void checkRemovePropertyConstraints(String propertyName)
            throws ConstraintViolationException {
        ExtendedPropertyDefinition def = getPropertyDefinitionsAsMap().get(propertyName);
        if (def != null) {
            if (def.isMandatory()) {
                throw new ConstraintViolationException("can't remove mandatory property");
            }
            if (def.isProtected()) {
                throw new ConstraintViolationException("can't remove protected property");
            }
        }
    }   
   
    private ExtendedPropertyDefinition getMatchingPropDef(Collection<ExtendedPropertyDefinition> defs, int type,
            boolean multiValued) {
        ExtendedPropertyDefinition match = null;
        for (ExtendedPropertyDefinition pd : defs) {
            int reqType = pd.getRequiredType();
            // match type
            if (reqType == PropertyType.UNDEFINED || type == PropertyType.UNDEFINED
                    || reqType == type) {
                // match multiValued flag
                if (multiValued == pd.isMultiple()) {
                    // found match
                    if (pd.getRequiredType() != PropertyType.UNDEFINED) {
                        // found best possible match, get outta here
                        return pd;
                    } else {
                        if (match == null) {
                            match = pd;
                        }
                    }
                }
            }
        }
        return match;
    }
   
    /**
     * Tests if the value constraints defined in the property definition
     * <code>pd</code> are satisfied by the the specified <code>values</code>.
     * <p/>
     * Note that the <i>protected</i> flag is not checked. Also note that no
     * type conversions are attempted if the type of the given values does not
     * match the required type as specified in the given definition.
     */
    private static void checkSetPropertyValueConstraints(ExtendedPropertyDefinition pd,
                                                        InternalValue[] values)
            throws ConstraintViolationException, RepositoryException {
        // check multi-value flag
        if (!pd.isMultiple() && values != null && values.length > 1) {
            throw new ConstraintViolationException("the property is not multi-valued");
        }

        ValueConstraint[] constraints = pd.getValueConstraintObjects();
        if (constraints == null || constraints.length == 0) {
            // no constraints to check
            return;
        }
        if (values != null && values.length > 0) {
            // check value constraints on every value
            for (InternalValue value : values) {
                // constraints are OR-ed together
                boolean satisfied = false;
                ConstraintViolationException cve = null;
                for (ValueConstraint constraint : constraints) {
                    try {
                        constraint.check(value);
                        satisfied = true;
                        break;
                    } catch (ConstraintViolationException e) {
                        cve = e;
                    }
                }
                if (!satisfied) {
                    // re-throw last exception we encountered
                    throw cve;
                }
            }
        }
    }   
   
    public boolean equals(Object obj) {
        if (this == obj) return true;
       
        if (obj != null && this.getClass() == obj.getClass()) {
            final ExtendedNodeType castOther = (ExtendedNodeType) obj;
            return new EqualsBuilder()
                .append(this.getName(), castOther.getName())
                .isEquals();
        }
        return false;
    }

    public int hashCode() {
        return new HashCodeBuilder()
                .append(getName())
                .toHashCode();
    }
   
    public void clearLabels() {
        labels.clear();
    }
}
TOP

Related Classes of org.jahia.services.content.nodetypes.ExtendedNodeType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.