Package org.chromattic.core.mapping

Source Code of org.chromattic.core.mapping.TypeMappingBuilder

/*
* Copyright (C) 2003-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.chromattic.core.mapping;

import org.chromattic.api.annotations.NodeMapping;
import org.chromattic.api.annotations.Property;
import org.chromattic.api.annotations.Name;
import org.chromattic.api.annotations.OneToOne;
import org.chromattic.api.annotations.MappedBy;
import org.chromattic.api.annotations.OneToMany;
import org.chromattic.api.annotations.ManyToOne;
import org.chromattic.api.annotations.Create;
import org.chromattic.api.annotations.RelatedMappedBy;
import org.chromattic.api.annotations.Id;
import org.chromattic.api.annotations.Path;
import org.chromattic.api.annotations.Destroy;
import org.chromattic.api.annotations.Properties;
import org.chromattic.api.annotations.FindById;
import org.chromattic.api.annotations.Mixin;
import org.chromattic.api.annotations.WorkspaceName;
import org.chromattic.api.RelationshipType;
import org.chromattic.core.mapping.jcr.JCRNodeAttributeMapping;
import org.chromattic.core.mapping.jcr.JCRPropertyMapping;
import org.chromattic.core.mapping.value.SimpleMapping;
import org.chromattic.core.mapping.value.NamedOneToOneMapping;
import org.chromattic.core.mapping.value.NamedManyToOneMapping;
import org.chromattic.core.mapping.value.RelationshipMapping;
import org.chromattic.core.mapping.value.ManyToOneMapping;
import org.chromattic.core.mapping.value.OneToManyMapping;
import org.chromattic.core.mapping.value.NamedOneToManyMapping;
import org.chromattic.core.mapping.value.PropertyMapMapping;
import org.chromattic.core.NodeAttributeType;
import org.chromattic.core.bean.BeanInfo;
import org.chromattic.core.bean.PropertyInfo;
import org.chromattic.core.bean.MapPropertyInfo;
import org.chromattic.core.bean.MultiValuedPropertyInfo;
import org.chromattic.core.bean.SingleValuedPropertyInfo;
import org.chromattic.core.bean.ValueInfo;
import org.chromattic.core.bean.SimpleValueInfo;
import org.chromattic.core.bean.SimpleType;
import org.chromattic.core.bean.BeanValueInfo;
import org.reflext.api.ClassTypeInfo;
import org.reflext.api.AnnotationIntrospector;
import org.reflext.api.MethodInfo;
import org.reflext.api.VoidTypeInfo;
import org.reflext.api.TypeInfo;
import org.reflext.api.introspection.MethodIntrospector;
import org.reflext.api.introspection.HierarchyScope;

import java.util.Set;
import java.util.HashSet;
import java.util.List;

/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
* @version $Revision$
*/
public class TypeMappingBuilder {

  /** . */
  private final ClassTypeInfo javaClass;

  public TypeMappingBuilder(ClassTypeInfo javaClass) {
    this.javaClass = javaClass;
  }

  public TypeMapping build() {
    return _build();
  }

  private TypeMapping _build() {
    NodeMapping nodeMapping = javaClass.getDeclaredAnnotation(NodeMapping.class);
    if (nodeMapping == null) {
      throw new IllegalStateException("Class " + javaClass + " is not annotated ");
    }

    //
    String primaryNodeTypeName = nodeMapping.name();
    Set<PropertyMapping> propertyMappings = new HashSet<PropertyMapping>();
    Set<MethodMapping> methodMappings = new HashSet<MethodMapping>();
    BeanInfo info = new BeanInfo(javaClass);

    //
    Mixin mixin = new AnnotationIntrospector<Mixin>(Mixin.class).resolve(javaClass);
    Set<String> mixinNames = new HashSet<String>();
    if (mixin != null) {
      for (String mixinName : mixin.name()) {
        mixinNames.add(mixinName);
      }
    }

    // Property
    for (PropertyInfo propertyInfo : info.getProperties(Property.class)) {
      Property propertyAnnotation = propertyInfo.getAnnotation(Property.class);

      //
      ValueInfo value;
      if (propertyInfo instanceof SingleValuedPropertyInfo) {
        SingleValuedPropertyInfo svp = (SingleValuedPropertyInfo)propertyInfo;
        value = svp.getValue();
      } else if (propertyInfo instanceof MultiValuedPropertyInfo) {
        MultiValuedPropertyInfo mvp = (MultiValuedPropertyInfo)propertyInfo;
        value = mvp.getElementValue();
      } else {
        throw new IllegalStateException();
      }

      //
      if (value instanceof SimpleValueInfo) {
        JCRPropertyMapping memberMapping = new JCRPropertyMapping(propertyAnnotation.name());
        SimpleMapping<JCRPropertyMapping> simpleMapping = new SimpleMapping<JCRPropertyMapping>(memberMapping);
        PropertyMapping<SimpleMapping<JCRPropertyMapping>> propertyMapping = new PropertyMapping<SimpleMapping<JCRPropertyMapping>>(propertyInfo, simpleMapping);
        propertyMappings.add(propertyMapping);
      } else {
        throw new IllegalStateException("Cannot map property type " + value);
      }
    }

    // Property map
    for (PropertyInfo propertyInfo : info.getProperties(Properties.class)) {
      Properties propertyAnnotation = propertyInfo.getAnnotation(Properties.class);
      if (propertyInfo instanceof MapPropertyInfo) {
        MapPropertyInfo mapPropertyInfo = (MapPropertyInfo)propertyInfo;
        PropertyMapMapping simpleMapping = new PropertyMapMapping();
        PropertyMapping<PropertyMapMapping> propertyMapping = new PropertyMapping<PropertyMapMapping>(mapPropertyInfo, simpleMapping);
        propertyMappings.add(propertyMapping);

      } else {
        throw new IllegalStateException();
      }
    }

    // Node attributes
    for (PropertyInfo propertyInfo : info.getProperties()) {
      NodeAttributeType nat = null;
      if (propertyInfo.getAnnotation(Name.class) != null) {
        nat = NodeAttributeType.NAME;
      } else if (propertyInfo.getAnnotation(Id.class) != null) {
        nat = NodeAttributeType.ID;
      } else if (propertyInfo.getAnnotation(Path.class) != null) {
        if (propertyInfo.getAnnotation(Property.class) == null) {
          // Check it's not a property
          nat = NodeAttributeType.PATH;
        }
      } else if (propertyInfo.getAnnotation(WorkspaceName.class) != null) {
        nat = NodeAttributeType.WORKSPACE_NAME;
      }
      if (nat != null) {
        if (propertyInfo instanceof SingleValuedPropertyInfo) {
          SingleValuedPropertyInfo svpi = (SingleValuedPropertyInfo)propertyInfo;
          ValueInfo vi = svpi.getValue();
          if (vi instanceof SimpleValueInfo) {
            SimpleValueInfo svi = (SimpleValueInfo)vi;
            JCRNodeAttributeMapping memberMapping = new JCRNodeAttributeMapping(nat);
            SimpleType simpleType = svi.getSimpleType();
            if (nat == NodeAttributeType.PATH) {
              if (simpleType != SimpleType.PATH) {
                throw new IllegalStateException("Type " + simpleType + " is not accepted for path attribute mapping");
              }
            } else {
              if (simpleType != SimpleType.STRING) {
                throw new IllegalStateException("Type " + simpleType + " is not accepted for attribute mapping");
              }
            }
            SimpleMapping<JCRNodeAttributeMapping> simpleMapping = new SimpleMapping<JCRNodeAttributeMapping>(memberMapping);
            PropertyMapping<SimpleMapping<JCRNodeAttributeMapping>> propertyMapping = new PropertyMapping<SimpleMapping<JCRNodeAttributeMapping>>(propertyInfo, simpleMapping);
            propertyMappings.add(propertyMapping);
          } else {
            throw new IllegalStateException();
          }
        } else {
          throw new IllegalStateException();
        }
      }
    }

    // One to one
    for (PropertyInfo propertyInfo : info.getProperties(OneToOne.class)) {

      if (propertyInfo instanceof SingleValuedPropertyInfo) {
        SingleValuedPropertyInfo svpi = (SingleValuedPropertyInfo)propertyInfo;
        ValueInfo vi = svpi.getValue();
        if (vi instanceof BeanValueInfo) {
          BeanValueInfo bvi = (BeanValueInfo)vi;
          ClassTypeInfo typeInfo = bvi.getTypeInfo();
          OneToOne oneToOneAnn = propertyInfo.getAnnotation(OneToOne.class);

          // The mapped by of a one to one mapping discrimines between the parent and the child
          RelationshipMapping hierarchyMapping;
          MappedBy mappedBy = propertyInfo.getAnnotation(MappedBy.class);
          if (mappedBy != null) {
            hierarchyMapping = new NamedOneToOneMapping(typeInfo, mappedBy.value(), RelationshipType.HIERARCHIC, true);
          } else {
            RelatedMappedBy relatedMappedBy = propertyInfo.getAnnotation(RelatedMappedBy.class);
            if (relatedMappedBy != null) {
              hierarchyMapping = new NamedOneToOneMapping(typeInfo, relatedMappedBy.value(), RelationshipType.HIERARCHIC, false);
            } else {
              throw new IllegalStateException("No related by mapping found for property " + propertyInfo + " when introspecting " + info);
            }
          }
          PropertyMapping<RelationshipMapping> oneToOneMapping = new PropertyMapping<RelationshipMapping>(propertyInfo, hierarchyMapping);
          propertyMappings.add(oneToOneMapping);
        } else {
          throw new IllegalStateException();
        }
      } else {
        throw new IllegalStateException();
      }
    }

    // One to many
    for (PropertyInfo propertyInfo : info.getProperties(OneToMany.class)) {
      OneToMany oneToManyAnn = propertyInfo.getAnnotation(OneToMany.class);
      if (propertyInfo instanceof MultiValuedPropertyInfo) {
        MultiValuedPropertyInfo multiValuedProperty = (MultiValuedPropertyInfo)propertyInfo;

        //
        if (multiValuedProperty instanceof MapPropertyInfo) {
          MapPropertyInfo mapProperty = (MapPropertyInfo)multiValuedProperty;
          if (!(mapProperty.getKeyValue() instanceof SimpleValueInfo)) {
            throw new IllegalStateException("Wrong key value type " + mapProperty.getKeyValue());
          }
          SimpleValueInfo svi = (SimpleValueInfo)mapProperty.getKeyValue();
          if (svi.getSimpleType() != SimpleType.STRING) {
            throw new IllegalStateException();
          }
        }

        //
        ValueInfo beanElementType = multiValuedProperty.getElementValue();
        if (beanElementType instanceof BeanValueInfo) {
          BeanValueInfo bvi = (BeanValueInfo)beanElementType;

          //
          OneToManyMapping mapping;
          RelationshipType type = oneToManyAnn.type();
          if (type == RelationshipType.HIERARCHIC) {
            MappedBy mappedBy = propertyInfo.getAnnotation(MappedBy.class);
            if (mappedBy != null) {
              throw new IllegalStateException();
            }
            mapping = new OneToManyMapping(bvi.getTypeInfo(), RelationshipType.HIERARCHIC);
          } else {
            RelatedMappedBy mappedBy = propertyInfo.getAnnotation(RelatedMappedBy.class);
            if (mappedBy == null) {
              throw new IllegalStateException();
            }
            mapping = new NamedOneToManyMapping(bvi.getTypeInfo(), mappedBy.value(), type);
          }

          //
          PropertyMapping<OneToManyMapping> oneToManyMapping = new PropertyMapping<OneToManyMapping>(propertyInfo, mapping);
          propertyMappings.add(oneToManyMapping);
        }
      }
    }

    // Many to one
    for (PropertyInfo propertyInfo : info.getProperties(ManyToOne.class)) {
      if (propertyInfo instanceof SingleValuedPropertyInfo) {
        SingleValuedPropertyInfo svpi = (SingleValuedPropertyInfo)propertyInfo;
        ValueInfo vi = svpi.getValue();
        if (vi instanceof BeanValueInfo) {
          BeanValueInfo bvi = (BeanValueInfo)vi;

          //
          ManyToOne manyToOneAnn = propertyInfo.getAnnotation(ManyToOne.class);
          RelationshipType type = manyToOneAnn.type();

          //
          if (type == RelationshipType.HIERARCHIC) {
            RelationshipMapping hierarchyMapping = new ManyToOneMapping(bvi.getTypeInfo(), RelationshipType.HIERARCHIC);
            PropertyMapping<RelationshipMapping> manyToOneMapping = new PropertyMapping<RelationshipMapping>(propertyInfo, hierarchyMapping);
            propertyMappings.add(manyToOneMapping);
          } else {
            MappedBy mappedBy = propertyInfo.getAnnotation(MappedBy.class);
            if (mappedBy == null) {
              throw new IllegalStateException();
            }
            NamedManyToOneMapping referenceMapping = new NamedManyToOneMapping(bvi.getTypeInfo(), mappedBy.value(), type);
            PropertyMapping<NamedManyToOneMapping> manyToOneMapping = new PropertyMapping<NamedManyToOneMapping>(propertyInfo, referenceMapping);
            propertyMappings.add(manyToOneMapping);
          }
        }
      } else {
        throw new IllegalStateException();
      }
    }

    //
    MethodIntrospector introspector = new MethodIntrospector(HierarchyScope.ALL);

    // Create
    for (MethodInfo method : introspector.resolveMethods(javaClass, Create.class)) {
      if (!method.isStatic()) {
        List<TypeInfo> parameterTypes = method.getParameterTypes();
        if (parameterTypes.size() < 2) {
          if (parameterTypes.size() == 1) {
            TypeInfo argTI = parameterTypes.get(0);
            if (argTI instanceof ClassTypeInfo) {
              ClassTypeInfo argCTI = (ClassTypeInfo)argTI;
              if (!argCTI.getName().equals(String.class.getName())) {
                throw new IllegalStateException();
              }
            } else {
              throw new IllegalStateException();
            }
          }
          ClassTypeInfo cti = (ClassTypeInfo)javaClass.resolve(method.getReturnType());
          methodMappings.add(new CreateMapping(method, cti));
        } else {
          throw new IllegalStateException();
        }
      }
    }

    // Destroy
    for (MethodInfo method : introspector.resolveMethods(javaClass, Destroy.class)) {
      if (!method.isStatic()) {
        List<TypeInfo> parameterTypes = method.getParameterTypes();
        if (parameterTypes.size() != 0) {
          throw new IllegalStateException();
        }
        if (!(method.getReturnType() instanceof VoidTypeInfo)) {
          throw new IllegalStateException();
        }
        methodMappings.add(new DestroyMapping(method));
      }
    }

    // Find by id
    for (MethodInfo method : introspector.resolveMethods(javaClass, FindById.class)) {
      if (!method.isStatic()) {
        List<TypeInfo> parameterTypes = method.getParameterTypes();
        if (parameterTypes.size() == 1) {
          TypeInfo argTI = parameterTypes.get(0);
          if (argTI instanceof ClassTypeInfo) {
            ClassTypeInfo argCTI = (ClassTypeInfo)argTI;
            if (argCTI.getName().equals(String.class.getName())) {
              ClassTypeInfo cti = (ClassTypeInfo)javaClass.resolve(method.getReturnType());
              methodMappings.add(new FindByIdMapping(method, cti));
            } else {
              throw new IllegalStateException();
            }
          } else {
            throw new IllegalStateException();
          }
        }
      }
    }

    //
    return new TypeMapping(
      javaClass,
      propertyMappings,
      methodMappings,
      primaryNodeTypeName,
      mixinNames);
  }
}
TOP

Related Classes of org.chromattic.core.mapping.TypeMappingBuilder

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.