Package org.apache.jackrabbit.ocm.mapper.model

Source Code of org.apache.jackrabbit.ocm.mapper.model.ClassDescriptor

/*
* 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.ocm.mapper.model;


import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.ocm.exception.JcrMappingException;
import org.apache.jackrabbit.ocm.reflection.ReflectionUtils;

/**
*
* ClassDescriptor is used by the mapper to read general information on a class
*
* @author <a href="mailto:christophe.lombart@sword-technologies.com">Lombart Christophe </a>
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
*/
public class ClassDescriptor {

  private static final Log log = LogFactory.getLog(ClassDescriptor.class);

    private static final String NODETYPE_PER_HIERARCHY = "nodetypeperhierarchy";
    private static final String NODETYPE_PER_CONCRETECLASS = "nodetypeperconcreteclass";

    private MappingDescriptor mappingDescriptor;
    private ClassDescriptor superClassDescriptor;
    private Collection descendantClassDescriptors = new ArrayList();

    private String className;
    private String jcrType;
    private String jcrSuperTypes;
    private String[] jcrMixinTypes = new String[0];
    private FieldDescriptor idFieldDescriptor;
    private FieldDescriptor pathFieldDescriptor;
    private FieldDescriptor uuidFieldDescriptor;

    private Map fieldDescriptors = new HashMap();
    private Map beanDescriptors = new HashMap();
    private Map collectionDescriptors = new HashMap();

    private Map fieldNames = new HashMap();

    private String superClassName;
    private String extendsStrategy;
    private boolean isAbstract = false;
    private boolean hasDescendant = false;
    private boolean hasDiscriminator = true;


    private boolean isInterface=false;
    private List interfaces = new ArrayList();

    public void setAbstract(boolean flag) {
        this.isAbstract = flag;
    }

    public boolean isAbstract() {
        return this.isAbstract;
    }

    public void setInterface(boolean flag) {
         this.isInterface = flag;
    }

    public boolean isInterface() {
          return isInterface;
    }

    public boolean hasInterfaces()
    {
         return this.interfaces.size() > 0;
    }

    public void setDiscriminator(boolean flag)
    {
        this.hasDiscriminator = flag;
    }

    public boolean hasDiscriminator() {
      return this.hasDiscriminator;
}

    public boolean usesNodeTypePerHierarchyStrategy() {
        return NODETYPE_PER_HIERARCHY.equals(this.extendsStrategy);
    }

    public boolean usesNodeTypePerConcreteClassStrategy() {
        return NODETYPE_PER_CONCRETECLASS.equals(this.extendsStrategy);
    }
    /**
     * @return Returns the className.
     */
    public String getClassName() {
        return className;
    }

    /**
     * @param className The className to set.
     */
    public void setClassName(String className) {
        this.className = className;
    }

    /**
     * @return Returns the jcrType.
     */
    public String getJcrType() {
        return jcrType;
    }

    /**
     * @param jcrType The jcrType to set.
     */
    public void setJcrType(String jcrType) {
      if (jcrType != null && ! jcrType.equals(""))
      {
         this.jcrType = jcrType;
      }
    }

    /**
     * Add a new FielDescriptor
     * @param fieldDescriptor the new field descriptor to add
     */
    public void addFieldDescriptor(FieldDescriptor fieldDescriptor) {
        fieldDescriptor.setClassDescriptor(this);
        if (fieldDescriptor.isId()) {
            this.idFieldDescriptor = fieldDescriptor;
        }
        if (fieldDescriptor.isPath()) {
            this.pathFieldDescriptor = fieldDescriptor;
        }
        if (fieldDescriptor.isUuid()) {
            this.uuidFieldDescriptor = fieldDescriptor;
        }

        fieldDescriptors.put(fieldDescriptor.getFieldName(), fieldDescriptor);
        fieldNames.put(fieldDescriptor.getFieldName(), fieldDescriptor.getJcrName());
    }

    public void addImplementDescriptor(ImplementDescriptor implementDescriptor)
    {
        interfaces.add(implementDescriptor.getInterfaceName());
    }

    /**
     * Get the FieldDescriptor to used for a specific java bean attribute
     * @param fieldName The java bean attribute name
     *
     * @return the {@link FieldDescriptor} found or null
     */
    public FieldDescriptor getFieldDescriptor(String fieldName) {
        return (FieldDescriptor) this.fieldDescriptors.get(fieldName);
    }

    /**
     *
     * @return all {@link FieldDescriptor} defined in this ClassDescriptor
     */
    public Collection getFieldDescriptors() {
        return this.fieldDescriptors.values();
    }

    /**
     * Add a new BeanDescriptor
     * @param beanDescriptor the new bean descriptor to add
     */

    public void addBeanDescriptor(BeanDescriptor beanDescriptor) {
        beanDescriptor.setClassDescriptor(this);
        beanDescriptors.put(beanDescriptor.getFieldName(), beanDescriptor);
        fieldNames.put(beanDescriptor.getFieldName(), beanDescriptor.getJcrName());
    }

    /**
     * Get the BeanDescriptor to used for a specific java bean attribute
     * @param fieldName The java bean attribute name
     *
     * @return the {@link BeanDescriptor} found or null
     */
    public BeanDescriptor getBeanDescriptor(String fieldName) {
        return (BeanDescriptor) this.beanDescriptors.get(fieldName);
    }

    /**
     * @return all {@link BeanDescriptor} defined in this ClassDescriptor
     */
    public Collection getBeanDescriptors() {
        return this.beanDescriptors.values();
    }

    /**
     * Add a new CollectionDescriptor
     * @param collectionDescriptor the new collection descriptor to add
     */

    public void addCollectionDescriptor(CollectionDescriptor collectionDescriptor) {
        collectionDescriptor.setClassDescriptor(this);
        collectionDescriptors.put(collectionDescriptor.getFieldName(), collectionDescriptor);
        fieldNames.put(collectionDescriptor.getFieldName(), collectionDescriptor.getJcrName());
    }

    /**
     * Get the CollectionDescriptor to used for a specific java bean attribute
     * @param fieldName The java bean attribute name
     *
     * @return the {@link CollectionDescriptor} found or null
     */
    public CollectionDescriptor getCollectionDescriptor(String fieldName) {
        return (CollectionDescriptor) this.collectionDescriptors.get(fieldName);
    }

    /**
     * @return all {@link BeanDescriptor} defined in this ClassDescriptor
     */
    public Collection getCollectionDescriptors() {
        return this.collectionDescriptors.values();
    }

    /**
     * @return the fieldDescriptor ID
     */
    public FieldDescriptor getIdFieldDescriptor() {
        return idFieldDescriptor;
    }

    /**
     * @return the fieldDescriptor path
     */
    public FieldDescriptor getPathFieldDescriptor() {
        if (null != this.pathFieldDescriptor) {
            return this.pathFieldDescriptor;
        }

        if (null != this.superClassDescriptor) {
            return this.superClassDescriptor.getPathFieldDescriptor();
        }

        return null;
    }

    /**
     * @return the fieldDescriptor path
     */
    public FieldDescriptor getUuidFieldDescriptor() {
        if (null != this.uuidFieldDescriptor) {
            return this.uuidFieldDescriptor;
        }

        if (null != this.superClassDescriptor) {
            return this.superClassDescriptor.getUuidFieldDescriptor();
        }

        return null;
    }

    /**
     * Check if this class has an ID
     * @return true if the class has an ID
     */
    public boolean hasIdField() {
        return (this.idFieldDescriptor != null && ! this.idFieldDescriptor.equals(""));
    }

    /**
     * Get the JCR name used for one of the object attributes
     * @param fieldName the object attribute name (can be an atomic field, bean field or a collection field)
     * @return the JCR name found
     */
    public String getJcrName(String fieldName) {
        String jcrName =  (String) this.fieldNames.get(fieldName);
        if (this.isInterface && jcrName == null)
        {
            return this.getJcrNameFromDescendants(this, fieldName);
        }

        return jcrName;
    }

    private String getJcrNameFromDescendants(ClassDescriptor classDescriptor, String fieldName )
    {
        Iterator  descendants = classDescriptor.getDescendantClassDescriptors().iterator();
        while (descendants.hasNext())
        {
              ClassDescriptor descendant = (ClassDescriptor) descendants.next();
              String jcrName =  (String) descendant.fieldNames.get(fieldName);
              if(jcrName != null)
              {
                   return jcrName;
              }
              return this.getJcrNameFromDescendants(descendant, fieldName);
        }
        return null;


    }

    public Map getFieldNames() {
        return this.fieldNames;
    }

    /** Get the JCR node super types.
     *
     * @return jcrSuperTypes
     */
    public String getJcrSuperTypes() {
        return jcrSuperTypes;
    }

    /** Setter for JCR super types.
     *
     * @param superTypes Comma separated list of JCR node super types
     */
    public void setJcrSuperTypes(String superTypes) {

      if (superTypes != null && ! superTypes.equals(""))
      {
         this.jcrSuperTypes = superTypes;
      }

    }

    /**
     * Retrieve the mixin types.
     *
     * @return array of mixin types
     */
    public String[] getJcrMixinTypes() {
        return this.jcrMixinTypes;
    }

    /**
     * Sets a comma separated list of mixin types.
     *
     * @param mixinTypes command separated list of mixins
     */
    public void setJcrMixinTypes(String[] mixinTypes) {
        if (null != mixinTypes && mixinTypes.length == 1) {
            jcrMixinTypes = mixinTypes[0].split(" *, *");
        }
    }
    public void setJcrMixinTypes(String mixinTypes) {
      if (mixinTypes != null && ! mixinTypes.equals(""))
      {
          jcrMixinTypes = mixinTypes.split(" *, *");
      }
    }
    /**
     * @return Returns the mappingDescriptor.
     */
    public MappingDescriptor getMappingDescriptor() {
        return mappingDescriptor;
    }

    /**
     * @param mappingDescriptor The mappingDescriptor to set.
     */
    public void setMappingDescriptor(MappingDescriptor mappingDescriptor) {
        this.mappingDescriptor = mappingDescriptor;
    }

    /**
     * Revisit information in this descriptor and fills in more.
     */
    public void afterPropertiesSet() {
        validateClassName();
        lookupSuperDescriptor();
        lookupInheritanceSettings();

    }

  private void validateClassName() {
    try {
            ReflectionUtils.forName(this.className);
    } catch (JcrMappingException e) {
       throw new JcrMappingException("Class used in descriptor not found : " + className);
    }
  }


  private void lookupSuperDescriptor() {
        if (null != superClassDescriptor) {
            this.hasDiscriminator = superClassDescriptor.hasDiscriminator();
            if (! this.isInterface)
            {
                this.fieldDescriptors = mergeFields(this.fieldDescriptors, this.superClassDescriptor.getFieldDescriptors());
                this.beanDescriptors = mergeBeans(this.beanDescriptors, this.superClassDescriptor.getBeanDescriptors());
                this.collectionDescriptors = mergeCollections(this.collectionDescriptors, this.superClassDescriptor.getCollectionDescriptors());
                this.fieldNames.putAll(this.superClassDescriptor.getFieldNames());
            }

        }
    }

    private void lookupInheritanceSettings() {
        if ((null != this.superClassDescriptor) || (this.hasDescendants()) || this.hasInterfaces()) {
            if (this.hasDiscriminator()) {
                this.extendsStrategy = NODETYPE_PER_HIERARCHY;
            }
            else {
                this.extendsStrategy = NODETYPE_PER_CONCRETECLASS;
            }
        }
    }


    /**
     * @return return the super class name if defined in mapping, or
     * <tt>null</tt> if not set
     */
    public String getExtend() {
        return this.superClassName;
    }

    /**
     * @param className
     */
    public void setExtend(String className) {
        if (className != null && className.length() == 0) {
            className = null;
        }
      this.superClassName = className;
    }

    /**
     * @return Returns the superClassDescriptor.
     */
    public ClassDescriptor getSuperClassDescriptor() {
        return superClassDescriptor;
    }

    public Collection getDescendantClassDescriptors() {
           return this.descendantClassDescriptors;
    }

    /**
     * If the node type per concrete class strategy is used, we need to find a descendant class descriptor assigned to a node type
     * This method is not used in other situation.
     *
     * @param nodeType the node type for which the classdescriptor is required
     * @return the classdescriptor found or null
     *
     * @todo : maybe we have to review this implementation to have better performance.
     */
    public ClassDescriptor getDescendantClassDescriptor(String nodeType) {
        Iterator iterator = this.descendantClassDescriptors.iterator();
        while (iterator.hasNext()) {
            ClassDescriptor descendantClassDescriptor = (ClassDescriptor) iterator.next();

            if (nodeType.equals(descendantClassDescriptor.getJcrType())) {
                return descendantClassDescriptor;
            }

            if (descendantClassDescriptor.hasDescendants()) {
                ClassDescriptor classDescriptor = descendantClassDescriptor.getDescendantClassDescriptor(nodeType);
                if (classDescriptor != null) {
                    return classDescriptor;
                }
            }
        }
        return null;
    }

    public void addDescendantClassDescriptor(ClassDescriptor classDescriptor) {
           this.descendantClassDescriptors.add(classDescriptor);
           this.hasDescendant = true;
    }

    public boolean hasDescendants() {
          return this.hasDescendant;
    }

    /**
     * @param superClassDescriptor The superClassDescriptor to set.
     */
    public void setSuperClassDescriptor(ClassDescriptor superClassDescriptor) {
        this.superClassDescriptor= superClassDescriptor;
        superClassDescriptor.addDescendantClassDescriptor(this);
    }


    public Collection getImplements()
    {
          return interfaces;
    }

    private Map mergeFields(Map existing, Collection superSource) {
        if (null == superSource) {
            return existing;
        }

        Map merged = new HashMap(existing);
        for(Iterator it = superSource.iterator(); it.hasNext();) {
            FieldDescriptor fieldDescriptor = (FieldDescriptor) it.next();
            if (!merged.containsKey(fieldDescriptor.getFieldName())) {
                merged.put(fieldDescriptor.getFieldName(), fieldDescriptor);
            }
//            else {
//                log.warn("Field name conflict in " + this.className + " - field : " +fieldDescriptor.getFieldName() + " -  this  field name is also defined  in the ancestor class : " + this.getExtend());
//            }
        }

        return merged;
    }


    private Map mergeBeans(Map existing, Collection superSource) {
        if (null == superSource) {
            return existing;
        }

        Map merged = new HashMap(existing);
        for(Iterator it = superSource.iterator(); it.hasNext();) {
            BeanDescriptor beanDescriptor = (BeanDescriptor) it.next();
            if (!merged.containsKey(beanDescriptor.getFieldName())) {
                merged.put(beanDescriptor.getFieldName(), beanDescriptor);
            }
//            else {
//                log.warn("Bean name conflict in " + this.className + " - field : " +beanDescriptor.getFieldName() + " -  this  field name is also defined  in the ancestor class : " + this.getExtend());
//            }
        }

        return merged;
    }

    private Map mergeCollections(Map existing, Collection superSource) {
        if (null == superSource) {
            return existing;
        }

        Map merged = new HashMap(existing);
        for(Iterator it = superSource.iterator(); it.hasNext();) {
            CollectionDescriptor collectionDescriptor = (CollectionDescriptor) it.next();
            if (!merged.containsKey(collectionDescriptor.getFieldName())) {
                merged.put(collectionDescriptor.getFieldName(), collectionDescriptor);
            }
        }

        return merged;
    }



  public String toString() {
    return "Class Descriptor : " this.getClassName();
  }
}
TOP

Related Classes of org.apache.jackrabbit.ocm.mapper.model.ClassDescriptor

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.