You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2013/12/05 13:31:44 UTC
[51/52] Renamed project
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/12ea18ae/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java
new file mode 100644
index 0000000..97f5b53
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java
@@ -0,0 +1,773 @@
+/*******************************************************************************
+ * 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.olingo.odata2.core.annotation.edm;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.FullQualifiedName;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationAttribute;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationElement;
+import org.apache.olingo.odata2.api.edm.provider.Association;
+import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSet;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSetEnd;
+import org.apache.olingo.odata2.api.edm.provider.ComplexProperty;
+import org.apache.olingo.odata2.api.edm.provider.ComplexType;
+import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainer;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainerInfo;
+import org.apache.olingo.odata2.api.edm.provider.EntitySet;
+import org.apache.olingo.odata2.api.edm.provider.EntityType;
+import org.apache.olingo.odata2.api.edm.provider.FunctionImport;
+import org.apache.olingo.odata2.api.edm.provider.Key;
+import org.apache.olingo.odata2.api.edm.provider.NavigationProperty;
+import org.apache.olingo.odata2.api.edm.provider.Property;
+import org.apache.olingo.odata2.api.edm.provider.PropertyRef;
+import org.apache.olingo.odata2.api.edm.provider.Schema;
+import org.apache.olingo.odata2.api.edm.provider.SimpleProperty;
+import org.apache.olingo.odata2.api.edm.provider.Using;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
+import org.apache.olingo.odata2.core.annotation.util.ClassHelper;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+/**
+ * Provider for the entity data model used in the reference scenario
+ *
+ */
+public class AnnotationEdmProvider extends EdmProvider {
+
+ private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
+
+ private final List<Class<?>> annotatedClasses;
+ private final Map<String, EntityContainer> name2Container = new HashMap<String, EntityContainer>();
+ private final Map<String, ContainerBuilder> containerName2ContainerBuilder = new HashMap<String, ContainerBuilder>();
+ private final Map<String, Schema> namespace2Schema = new HashMap<String, Schema>();
+ private EntityContainer defaultContainer;
+
+ public AnnotationEdmProvider(Collection<Class<?>> annotatedClasses) {
+
+ this.annotatedClasses = new ArrayList<Class<?>>(annotatedClasses.size());
+ for (Class<?> aClass : annotatedClasses) {
+ if (ANNOTATION_HELPER.isEdmAnnotated(aClass)) {
+ this.annotatedClasses.add(aClass);
+ }
+ }
+
+ init();
+ }
+
+ public AnnotationEdmProvider(String packageToScan) {
+ this.annotatedClasses = ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() {
+ @Override
+ public boolean isClassValid(Class<?> c) {
+ return ANNOTATION_HELPER.isEdmAnnotated(c);
+ }
+ });
+
+ init();
+ }
+
+ private void init() {
+ for (Class<?> aClass : annotatedClasses) {
+ updateSchema(aClass);
+ handleEntityContainer(aClass);
+ }
+
+ finish();
+ }
+
+ @Override
+ public Association getAssociation(FullQualifiedName edmFQName) throws ODataException {
+ Schema schema = namespace2Schema.get(edmFQName.getNamespace());
+ if (schema != null) {
+ List<Association> associations = schema.getAssociations();
+ for (Association association : associations) {
+ if (association.getName().equals(edmFQName.getName())) {
+ return association;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public AssociationSet getAssociationSet(String entityContainer, FullQualifiedName association,
+ String sourceEntitySetName, String sourceEntitySetRole) throws ODataException {
+ EntityContainer container = name2Container.get(entityContainer);
+ if (container != null) {
+ List<AssociationSet> associations = container.getAssociationSets();
+ for (AssociationSet associationSet : associations) {
+ if (associationSet.getAssociation().equals(association)) {
+ final AssociationSetEnd endOne = associationSet.getEnd1();
+ if (endOne.getRole().equals(sourceEntitySetRole)
+ && endOne.getEntitySet().equals(sourceEntitySetName)) {
+ return associationSet;
+ }
+ final AssociationSetEnd endTwo = associationSet.getEnd2();
+ if (endTwo.getRole().equals(sourceEntitySetRole)
+ && endTwo.getEntitySet().equals(sourceEntitySetName)) {
+ return associationSet;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ComplexType getComplexType(FullQualifiedName edmFQName) throws ODataException {
+ Schema schema = namespace2Schema.get(edmFQName.getNamespace());
+ if (schema != null) {
+ List<ComplexType> complexTypes = schema.getComplexTypes();
+ for (ComplexType complexType : complexTypes) {
+ if (complexType.getName().equals(edmFQName.getName())) {
+ return complexType;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public EntityContainerInfo getEntityContainerInfo(String name) throws ODataException {
+ EntityContainer container = name2Container.get(name);
+ if (container == null) {
+ // use default container (if set)
+ container = defaultContainer;
+ }
+ if (container != null) {
+ EntityContainerInfo info = new EntityContainerInfo();
+ info.setName(container.getName());
+ info.setDefaultEntityContainer(container.isDefaultEntityContainer());
+ info.setExtendz(container.getExtendz());
+ info.setAnnotationAttributes(container.getAnnotationAttributes());
+ info.setAnnotationElements(container.getAnnotationElements());
+
+ return info;
+ }
+
+ return null;
+ }
+
+ @Override
+ public EntitySet getEntitySet(String entityContainer, String name) throws ODataException {
+ EntityContainer container = name2Container.get(entityContainer);
+ if (container != null) {
+ List<EntitySet> entitySets = container.getEntitySets();
+ for (EntitySet entitySet : entitySets) {
+ if (entitySet.getName().equals(name)) {
+ return entitySet;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public EntityType getEntityType(FullQualifiedName edmFQName) throws ODataException {
+ Schema schema = namespace2Schema.get(edmFQName.getNamespace());
+ if (schema != null) {
+ List<EntityType> complexTypes = schema.getEntityTypes();
+ for (EntityType complexType : complexTypes) {
+ if (complexType.getName().equals(edmFQName.getName())) {
+ return complexType;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public FunctionImport getFunctionImport(String entityContainer, String name) throws ODataException {
+ EntityContainer container = name2Container.get(entityContainer);
+ if (container != null) {
+ List<FunctionImport> functionImports = container.getFunctionImports();
+ for (FunctionImport functionImport : functionImports) {
+ if (functionImport.getName().equals(name)) {
+ return functionImport;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public List<Schema> getSchemas() throws ODataException {
+ return new ArrayList<Schema>(namespace2Schema.values());
+ }
+
+ //
+ //
+ //
+ private Map<String, SchemaBuilder> namespace2SchemaBuilder = new HashMap<String, SchemaBuilder>();
+
+ private void updateSchema(Class<?> aClass) {
+ EdmEntityType et = aClass.getAnnotation(EdmEntityType.class);
+ if (et != null) {
+ updateSchema(aClass, et);
+ }
+ EdmComplexType ect = aClass.getAnnotation(EdmComplexType.class);
+ if (ect != null) {
+ updateSchema(aClass, ect);
+ }
+ }
+
+ private void updateSchema(Class<?> aClass, EdmEntityType et) {
+ SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass);
+ TypeBuilder typeBuilder = TypeBuilder.init(et, aClass);
+ b.addEntityType(typeBuilder.buildEntityType());
+ b.addAssociations(typeBuilder.buildAssociations());
+ }
+
+ private SchemaBuilder getSchemaBuilder(String namespace, Class<?> aClass) {
+ String usedNamespace = namespace;
+ if(usedNamespace.isEmpty()) {
+ usedNamespace = ANNOTATION_HELPER.getCanonicalNamespace(aClass);
+ }
+ SchemaBuilder builder = namespace2SchemaBuilder.get(usedNamespace);
+ if (builder == null) {
+ builder = SchemaBuilder.init(usedNamespace);
+ namespace2SchemaBuilder.put(usedNamespace, builder);
+ }
+ return builder;
+ }
+
+ private void updateSchema(Class<?> aClass, EdmComplexType et) {
+ SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass);
+ TypeBuilder typeBuilder = TypeBuilder.init(et, aClass);
+ b.addComplexType(typeBuilder.buildComplexType());
+ }
+
+ private void handleEntityContainer(Class<?> aClass) {
+ EdmEntityType entityType = aClass.getAnnotation(EdmEntityType.class);
+ if (entityType != null) {
+ FullQualifiedName typeName = createFqnForEntityType(aClass, entityType);
+ String containerName = ANNOTATION_HELPER.extractContainerName(aClass);
+ ContainerBuilder builder = containerName2ContainerBuilder.get(containerName);
+ if (builder == null) {
+ builder = ContainerBuilder.init(typeName.getNamespace(), containerName);
+ containerName2ContainerBuilder.put(containerName, builder);
+ }
+ EdmEntitySet entitySet = aClass.getAnnotation(EdmEntitySet.class);
+ if (entitySet != null) {
+ builder.addEntitySet(createEntitySet(typeName, entitySet));
+ }
+ }
+ }
+
+ private EntitySet createEntitySet(FullQualifiedName typeName, EdmEntitySet entitySet) {
+ return new EntitySet().setName(entitySet.name()).setEntityType(typeName);
+ }
+
+ private FullQualifiedName createFqnForEntityType(Class<?> annotatedClass, EdmEntityType entityType) {
+ return ANNOTATION_HELPER.extractEntityTypeFqn(annotatedClass);
+ }
+
+ private void finish() {
+ //
+ Collection<ContainerBuilder> containers = containerName2ContainerBuilder.values();
+ for (ContainerBuilder containerBuilder : containers) {
+ SchemaBuilder schemaBuilder = namespace2SchemaBuilder.get(containerBuilder.getNamespace());
+ containerBuilder.addAssociationSets(schemaBuilder.name2Associations.values());
+ final EntityContainer container = containerBuilder.build();
+ schemaBuilder.addEntityContainer(container);
+ name2Container.put(container.getName(), container);
+ if (container.isDefaultEntityContainer()) {
+ defaultContainer = container;
+ }
+ }
+ //
+ Collection<SchemaBuilder> schemaBuilders = namespace2SchemaBuilder.values();
+ for (SchemaBuilder schemaBuilder : schemaBuilders) {
+ final Schema schema = schemaBuilder.build();
+ namespace2Schema.put(schema.getNamespace(), schema);
+ }
+ }
+
+ //
+ //
+ //
+ static class TypeBuilder {
+
+ final private String namespace;
+ final private String name;
+ private boolean isAbstract = false;
+ private boolean isMediaResource = false;
+ private FullQualifiedName baseEntityType = null;
+ private final List<PropertyRef> keyProperties = new ArrayList<PropertyRef>();
+ private final List<Property> properties = new ArrayList<Property>();
+ private final List<NavigationProperty> navProperties = new ArrayList<NavigationProperty>();
+ private final List<Association> associations = new ArrayList<Association>();
+
+ public TypeBuilder(FullQualifiedName fqn) {
+ this.namespace = fqn.getNamespace();
+ this.name = fqn.getName();
+ }
+
+ public static TypeBuilder init(EdmEntityType entity, Class<?> aClass) {
+ return new TypeBuilder(ANNOTATION_HELPER.extractEntityTypeFqn(entity, aClass)).withClass(aClass);
+ }
+
+ public static TypeBuilder init(EdmComplexType entity, Class<?> aClass) {
+ return new TypeBuilder(ANNOTATION_HELPER.extractComplexTypeFqn(entity, aClass)).withClass(aClass);
+ }
+
+ private TypeBuilder withClass(Class<?> aClass) {
+ baseEntityType = createBaseEntityFqn(aClass);
+
+ if (Modifier.isAbstract(aClass.getModifiers())) {
+ this.isAbstract = true;
+ }
+
+ Field[] fields = aClass.getDeclaredFields();
+ for (Field field : fields) {
+ EdmProperty ep = field.getAnnotation(EdmProperty.class);
+ if (ep != null) {
+ properties.add(createProperty(ep, field, namespace));
+ EdmKey eti = field.getAnnotation(EdmKey.class);
+ if (eti != null) {
+ keyProperties.add(createKeyProperty(ep, field));
+ }
+ }
+ EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
+ if (enp != null) {
+ final NavigationProperty navProperty = createNavigationProperty(namespace, enp, field);
+ navProperties.add(navProperty);
+ Association association = createAssociation(field, navProperty);
+ associations.add(association);
+ }
+ EdmMediaResourceContent emrc = field.getAnnotation(EdmMediaResourceContent.class);
+ if (emrc != null) {
+ isMediaResource = true;
+ }
+ }
+
+ return this;
+ }
+
+ public TypeBuilder addProperty(PropertyRef property) {
+ keyProperties.add(property);
+ return this;
+ }
+
+ public TypeBuilder addProperty(Property property) {
+ properties.add(property);
+ return this;
+ }
+
+ public TypeBuilder addNavigationProperty(NavigationProperty property) {
+ navProperties.add(property);
+ return this;
+ }
+
+ public TypeBuilder setAbstract(boolean isAbstract) {
+ this.isAbstract = isAbstract;
+ return this;
+ }
+
+ public ComplexType buildComplexType() {
+ ComplexType complexType = new ComplexType();
+ if (baseEntityType != null) {
+ complexType.setBaseType(baseEntityType);
+ }
+ return complexType.setName(name).setProperties(properties);
+ }
+
+ public EntityType buildEntityType() {
+ EntityType entityType = new EntityType();
+ if (baseEntityType != null) {
+ entityType.setBaseType(baseEntityType);
+ }
+ if (!keyProperties.isEmpty()) {
+ entityType.setKey(new Key().setKeys(keyProperties));
+ }
+ if (!navProperties.isEmpty()) {
+ entityType.setNavigationProperties(navProperties);
+ }
+ return entityType.setName(name)
+ .setAbstract(isAbstract)
+ .setHasStream(isMediaResource)
+ .setProperties(properties);
+ }
+
+ public Collection<Association> buildAssociations() {
+ return Collections.unmodifiableCollection(associations);
+ }
+
+ private PropertyRef createKeyProperty(EdmProperty et, Field field) {
+ PropertyRef keyProperty = new PropertyRef();
+ String entityName = et.name();
+ if (entityName.isEmpty()) {
+ entityName = getCanonicalName(field);
+ }
+ return keyProperty.setName(entityName);
+ }
+
+ private Property createProperty(EdmProperty ep, Field field, String defaultNamespace) {
+ if (isAnnotatedEntity(field.getType())) {
+ return createComplexProperty(field, defaultNamespace);
+ } else {
+ return createSimpleProperty(ep, field);
+ }
+ }
+
+ private Property createSimpleProperty(EdmProperty ep, Field field) {
+ SimpleProperty sp = new SimpleProperty();
+ String entityName = ANNOTATION_HELPER.getPropertyName(field);
+ sp.setName(entityName);
+ //
+ EdmType type = ep.type();
+ if (type == EdmType.NULL) {
+ type = getEdmType(field.getType());
+ }
+ sp.setType(ANNOTATION_HELPER.mapTypeKind(type));
+
+ return sp;
+ }
+
+ private Property createComplexProperty(Field field, String defaultNamespace) {
+ ComplexProperty cp = new ComplexProperty();
+ // settings from property
+ String entityName = ANNOTATION_HELPER.getPropertyName(field);
+ cp.setName(entityName);
+
+ // settings from related complex entity
+ EdmComplexType ece = field.getType().getAnnotation(EdmComplexType.class);
+ String complexEntityNamespace = ece.namespace();
+ if (complexEntityNamespace.isEmpty()) {
+ complexEntityNamespace = defaultNamespace;
+ }
+ cp.setType(new FullQualifiedName(complexEntityNamespace, ece.name()));
+
+ return cp;
+ }
+
+ private NavigationProperty createNavigationProperty(String namespace, EdmNavigationProperty enp, Field field) {
+ NavigationProperty navProp = new NavigationProperty();
+ navProp.setName(ANNOTATION_HELPER.getPropertyName(field));
+ String fromRole = ANNOTATION_HELPER.extractFromRoleName(enp, field);
+ navProp.setFromRole(fromRole);
+
+ String toRole = ANNOTATION_HELPER.extractToRoleName(enp, field);
+ navProp.setToRole(toRole);
+
+ String relationshipName = ANNOTATION_HELPER.extractRelationshipName(enp, field);
+ navProp.setRelationship(new FullQualifiedName(namespace, relationshipName));
+
+ return navProp;
+ }
+
+// private EdmSimpleTypeKind getEdmSimpleType(Class<?> type) {
+// if (type == String.class) {
+// return EdmType.String;
+// } else if (type == boolean.class || type == Boolean.class) {
+// return EdmType.Boolean;
+// } else if (type == byte.class || type == Byte.class) {
+// return EdmType.SByte;
+// } else if (type == short.class || type == Short.class) {
+// return EdmType.Int16;
+// } else if (type == int.class || type == Integer.class) {
+// return EdmType.Int32;
+// } else if (type == long.class || type == Long.class) {
+// return EdmType.Int64;
+// } else if (type == double.class || type == Double.class) {
+// return EdmType.Double;
+// } else if (type == float.class || type == Float.class) {
+// return EdmType.Single;
+// } else if (type == BigInteger.class || type == BigDecimal.class) {
+// return EdmType.Decimal;
+// } else if (type == Byte[].class || type == byte[].class) {
+// return EdmType.Binary;
+// } else if (type == Date.class) {
+// return EdmType.DateTime;
+// } else if (type == Calendar.class) {
+// return EdmType.DateTimeOffset;
+// } else if (type == UUID.class) {
+// return EdmType.Guid;
+// } else {
+// throw new UnsupportedOperationException("Not yet supported type '" + type + "'.");
+// }
+// }
+
+ private EdmType getEdmType(Class<?> type) {
+ if (type == String.class) {
+ return EdmType.STRING;
+ } else if (type == boolean.class || type == Boolean.class) {
+ return EdmType.BOOLEAN;
+ } else if (type == byte.class || type == Byte.class) {
+ return EdmType.SBYTE;
+ } else if (type == short.class || type == Short.class) {
+ return EdmType.INT16;
+ } else if (type == int.class || type == Integer.class) {
+ return EdmType.INT32;
+ } else if (type == long.class || type == Long.class) {
+ return EdmType.INT64;
+ } else if (type == double.class || type == Double.class) {
+ return EdmType.DOUBLE;
+ } else if (type == float.class || type == Float.class) {
+ return EdmType.SINGLE;
+ } else if (type == BigInteger.class || type == BigDecimal.class) {
+ return EdmType.DECIMAL;
+ } else if (type == Byte[].class || type == byte[].class) {
+ return EdmType.BINARY;
+ } else if (type == Date.class) {
+ return EdmType.DATE_TIME;
+ } else if (type == Calendar.class) {
+ return EdmType.DATE_TIME_OFFSET;
+ } else if (type == UUID.class) {
+ return EdmType.GUID;
+ } else {
+ throw new UnsupportedOperationException("Not yet supported type '" + type + "'.");
+ }
+ }
+
+
+ private Class<?> checkForBaseEntityClass(Class<?> aClass) {
+ Class<?> superClass = aClass.getSuperclass();
+ if (superClass == Object.class) {
+ return null;
+ } else {
+ EdmEntityType edmEntity = superClass.getAnnotation(EdmEntityType.class);
+ if (edmEntity == null) {
+ return checkForBaseEntityClass(superClass);
+ } else {
+ return superClass;
+ }
+ }
+ }
+
+ private FullQualifiedName createBaseEntityFqn(Class<?> aClass) {
+ Class<?> baseEntityClass = checkForBaseEntityClass(aClass);
+ if (baseEntityClass == null) {
+ return null;
+ }
+ return ANNOTATION_HELPER.extractEntityTypeFqn(baseEntityClass);
+ }
+
+ private Association createAssociation(Field field, NavigationProperty navProperty) {
+ Association association = new Association();
+ EdmNavigationProperty navigation = field.getAnnotation(EdmNavigationProperty.class);
+
+ AssociationEnd fromEnd = new AssociationEnd();
+ fromEnd.setRole(navProperty.getFromRole());
+ String typeName = ANNOTATION_HELPER.extractEntityTypeName(field.getDeclaringClass());
+ fromEnd.setType(new FullQualifiedName(namespace, typeName));
+ fromEnd.setMultiplicity(EdmMultiplicity.ONE);
+ association.setEnd1(fromEnd);
+
+ AssociationEnd toEnd = new AssociationEnd();
+ toEnd.setRole(navProperty.getToRole());
+ String toTypeName = ANNOTATION_HELPER.extractEntitTypeName(navigation, field);
+ toEnd.setType(new FullQualifiedName(namespace, toTypeName));
+ toEnd.setMultiplicity(ANNOTATION_HELPER.getMultiplicity(navigation, field));
+ association.setEnd2(toEnd);
+
+ String associationName = navProperty.getRelationship().getName();
+ association.setName(associationName);
+ return association;
+ }
+
+ private String getCanonicalName(Field field) {
+ return ANNOTATION_HELPER.getCanonicalName(field);
+ }
+
+ private boolean isAnnotatedEntity(Class<?> clazz) {
+ return ANNOTATION_HELPER.isEdmTypeAnnotated(clazz);
+ }
+ }
+
+ static class SchemaBuilder {
+
+ final private String namespace;
+ // private String alias;
+ private final List<Using> usings = new ArrayList<Using>();
+ private final List<EntityType> entityTypes = new ArrayList<EntityType>();
+ private final List<ComplexType> complexTypes = new ArrayList<ComplexType>();
+ private final Map<String, Association> name2Associations = new HashMap<String, Association>();
+ private final List<EntityContainer> entityContainers = new ArrayList<EntityContainer>();
+ private final List<AnnotationAttribute> annotationAttributes = new ArrayList<AnnotationAttribute>();
+ private final List<AnnotationElement> annotationElements = new ArrayList<AnnotationElement>();
+
+ private SchemaBuilder(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public static SchemaBuilder init(String namespace) {
+ return new SchemaBuilder(namespace);
+ }
+
+ public SchemaBuilder addEntityType(EntityType type) {
+ entityTypes.add(type);
+ return this;
+ }
+
+ public SchemaBuilder addEntityContainer(EntityContainer container) {
+ entityContainers.add(container);
+ return this;
+ }
+
+ public SchemaBuilder addComplexType(ComplexType createEntityType) {
+ complexTypes.add(createEntityType);
+ return this;
+ }
+
+ public void addAssociations(Collection<Association> associations) {
+ for (Association association : associations) {
+ final String relationshipName = association.getName();
+ if (name2Associations.containsKey(relationshipName)) {
+ association = mergeAssociations(name2Associations.get(relationshipName), association);
+ }
+ name2Associations.put(relationshipName, association);
+ }
+ }
+
+ private Association mergeAssociations(Association associationOne, Association associationTwo) {
+ AssociationEnd oneEnd1 = associationOne.getEnd1();
+ AssociationEnd oneEnd2 = associationOne.getEnd2();
+ AssociationEnd twoEnd1 = associationTwo.getEnd1();
+ AssociationEnd twoEnd2 = associationTwo.getEnd2();
+ AssociationEnd[] oneEnds = new AssociationEnd[] { oneEnd1, oneEnd2 };
+
+ for (AssociationEnd associationEnd : oneEnds) {
+ if (associationEnd.getRole().equals(twoEnd1.getRole())) {
+ if (twoEnd1.getMultiplicity() == EdmMultiplicity.MANY) {
+ associationEnd.setMultiplicity(EdmMultiplicity.MANY);
+ }
+ } else if (associationEnd.getRole().equals(twoEnd2.getRole())) {
+ if (twoEnd2.getMultiplicity() == EdmMultiplicity.MANY) {
+ associationEnd.setMultiplicity(EdmMultiplicity.MANY);
+ }
+ }
+ }
+
+ return associationOne;
+ }
+
+ public Schema build() {
+ Schema s = new Schema();
+ s.setUsings(usings);
+ s.setEntityTypes(entityTypes);
+ s.setComplexTypes(complexTypes);
+ s.setAssociations(new ArrayList<Association>(name2Associations.values()));
+ s.setEntityContainers(entityContainers);
+ s.setAnnotationAttributes(annotationAttributes);
+ s.setAnnotationElements(annotationElements);
+ s.setNamespace(namespace);
+ return s;
+ }
+ }
+
+ private static class ContainerBuilder {
+
+ final private String name;
+ final private String namespace;
+ private boolean defaultContainer = true;
+ private final List<EntitySet> entitySets = new ArrayList<EntitySet>();
+ private final List<AssociationSet> associationSets = new ArrayList<AssociationSet>();
+ private final List<FunctionImport> functionImports = new ArrayList<FunctionImport>();
+
+ // private Documentation documentation;
+
+ private ContainerBuilder(String namespace, String containerName) {
+ this.namespace = namespace;
+ name = containerName;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public static ContainerBuilder init(String namespace, String containerName) {
+ return new ContainerBuilder(namespace, containerName);
+ }
+
+ public ContainerBuilder setDefaultContainer(boolean isDefault) {
+ defaultContainer = isDefault;
+ return this;
+ }
+
+ public ContainerBuilder addEntitySet(EntitySet entitySet) {
+ entitySets.add(entitySet);
+ return this;
+ }
+
+ public void addAssociationSets(Collection<Association> associations) {
+ for (Association association : associations) {
+ AssociationSet as = new AssociationSet();
+ as.setName(association.getName());
+ FullQualifiedName asAssociationFqn = new FullQualifiedName(namespace, association.getName());
+ as.setAssociation(asAssociationFqn);
+
+ AssociationSetEnd asEnd1 = new AssociationSetEnd();
+ asEnd1.setEntitySet(getEntitySetName(association.getEnd1()));
+ asEnd1.setRole(association.getEnd1().getRole());
+ as.setEnd1(asEnd1);
+
+ AssociationSetEnd asEnd2 = new AssociationSetEnd();
+ asEnd2.setEntitySet(getEntitySetName(association.getEnd2()));
+ asEnd2.setRole(association.getEnd2().getRole());
+ as.setEnd2(asEnd2);
+
+ associationSets.add(as);
+ }
+ }
+
+ public EntityContainer build() {
+ EntityContainer ec = new EntityContainer();
+ ec.setName(name);
+ ec.setDefaultEntityContainer(defaultContainer);
+ ec.setEntitySets(entitySets);
+ ec.setAssociationSets(associationSets);
+ ec.setFunctionImports(functionImports);
+ return ec;
+ }
+
+ private String getEntitySetName(AssociationEnd end) {
+ for (EntitySet entitySet : entitySets) {
+ if (entitySet.getEntityType().equals(end.getType())) {
+ return entitySet.getName();
+ }
+ }
+ throw new ODataRuntimeException("No entity set found for " + end.getType());
+ }
+ }
+}