| /******************************************************************************* |
| * 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.annotation.processor.core.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.annotation.processor.core.util.AnnotationHelper; |
| import org.apache.olingo.odata2.annotation.processor.core.util.ClassHelper; |
| import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType; |
| import org.apache.olingo.odata2.api.annotation.edm.EdmConcurrencyControl; |
| 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.EdmFacets; |
| 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.EdmConcurrencyMode; |
| 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.Facets; |
| 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; |
| |
| /** |
| * 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(final Collection<Class<?>> annotatedClasses) throws ODataException { |
| |
| this.annotatedClasses = new ArrayList<Class<?>>(annotatedClasses.size()); |
| for (Class<?> aClass : annotatedClasses) { |
| if (ANNOTATION_HELPER.isEdmAnnotated(aClass)) { |
| this.annotatedClasses.add(aClass); |
| } |
| } |
| |
| init(); |
| } |
| |
| public AnnotationEdmProvider(final String packageToScan) throws ODataException { |
| annotatedClasses = ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() { |
| @Override |
| public boolean isClassValid(final Class<?> c) { |
| return ANNOTATION_HELPER.isEdmAnnotated(c); |
| } |
| }); |
| |
| init(); |
| } |
| |
| private void init() throws ODataException { |
| for (Class<?> aClass : annotatedClasses) { |
| updateSchema(aClass); |
| handleEntityContainer(aClass); |
| } |
| |
| finish(); |
| } |
| |
| @Override |
| public Association getAssociation(final 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(final String entityContainer, final FullQualifiedName association, |
| final String sourceEntitySetName, final 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(final 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(final 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(final String entityContainer, final 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(final 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(final String entityContainer, final 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(final 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(final Class<?> aClass, final 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(final String namespace, final 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(final Class<?> aClass, final EdmComplexType et) { |
| SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass); |
| TypeBuilder typeBuilder = TypeBuilder.init(et, aClass); |
| b.addComplexType(typeBuilder.buildComplexType()); |
| } |
| |
| private void handleEntityContainer(final 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, aClass)); |
| } |
| } |
| } |
| |
| private EntitySet createEntitySet(final FullQualifiedName typeName, final Class<?> entitySetClass) { |
| String entitySetName = ANNOTATION_HELPER.extractEntitySetName(entitySetClass); |
| return new EntitySet().setName(entitySetName).setEntityType(typeName); |
| } |
| |
| private FullQualifiedName createFqnForEntityType(final Class<?> annotatedClass, final EdmEntityType entityType) { |
| return ANNOTATION_HELPER.extractEntityTypeFqn(annotatedClass); |
| } |
| |
| private void finish() throws ODataException { |
| // |
| 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(final FullQualifiedName fqn) { |
| namespace = fqn.getNamespace(); |
| name = fqn.getName(); |
| } |
| |
| public static TypeBuilder init(final EdmEntityType entity, final Class<?> aClass) { |
| return new TypeBuilder(ANNOTATION_HELPER.extractEntityTypeFqn(entity, aClass)).withClass(aClass); |
| } |
| |
| public static TypeBuilder init(final EdmComplexType entity, final Class<?> aClass) { |
| return new TypeBuilder(ANNOTATION_HELPER.extractComplexTypeFqn(entity, aClass)).withClass(aClass); |
| } |
| |
| private TypeBuilder withClass(final Class<?> aClass) { |
| baseEntityType = createBaseEntityFqn(aClass); |
| |
| if (Modifier.isAbstract(aClass.getModifiers())) { |
| 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(final PropertyRef property) { |
| keyProperties.add(property); |
| return this; |
| } |
| |
| public TypeBuilder addProperty(final Property property) { |
| properties.add(property); |
| return this; |
| } |
| |
| public TypeBuilder addNavigationProperty(final NavigationProperty property) { |
| navProperties.add(property); |
| return this; |
| } |
| |
| public TypeBuilder setAbstract(final 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(final EdmProperty et, final Field field) { |
| PropertyRef keyProperty = new PropertyRef(); |
| String entityName = et.name(); |
| if (entityName.isEmpty()) { |
| entityName = getCanonicalName(field); |
| } |
| return keyProperty.setName(entityName); |
| } |
| |
| private Property createProperty(final EdmProperty ep, final Field field, final String defaultNamespace) { |
| if (isAnnotatedEntity(field.getType())) { |
| return createComplexProperty(field, defaultNamespace); |
| } else { |
| return createSimpleProperty(ep, field); |
| } |
| } |
| |
| private Property createSimpleProperty(final EdmProperty ep, final 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)); |
| sp.setFacets(createFacets(ep.facets(), field.getAnnotation(EdmConcurrencyControl.class))); |
| return sp; |
| } |
| |
| private Facets createFacets(final EdmFacets facets, final EdmConcurrencyControl concurrencyControl) { |
| Facets resultFacets = new Facets().setNullable(facets.nullable()); |
| if(facets.maxLength() > -1) { |
| resultFacets.setMaxLength(facets.maxLength()); |
| } |
| if(facets.precision() > -1) { |
| resultFacets.setPrecision(facets.precision()); |
| } |
| if(facets.scale() > -1) { |
| resultFacets.setScale(facets.scale()); |
| } |
| if (concurrencyControl != null) { |
| resultFacets.setConcurrencyMode(EdmConcurrencyMode.Fixed); |
| } |
| return resultFacets; |
| } |
| |
| private Property createComplexProperty(final Field field, final 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(final String namespace, final EdmNavigationProperty enp, |
| final 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(final 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(final 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(final Class<?> aClass) { |
| Class<?> baseEntityClass = checkForBaseEntityClass(aClass); |
| if (baseEntityClass == null) { |
| return null; |
| } |
| return ANNOTATION_HELPER.extractEntityTypeFqn(baseEntityClass); |
| } |
| |
| private Association createAssociation(final Field field, final 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(final Field field) { |
| return ANNOTATION_HELPER.getCanonicalName(field); |
| } |
| |
| private boolean isAnnotatedEntity(final 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(final String namespace) { |
| this.namespace = namespace; |
| } |
| |
| public static SchemaBuilder init(final String namespace) { |
| return new SchemaBuilder(namespace); |
| } |
| |
| public SchemaBuilder addEntityType(final EntityType type) { |
| entityTypes.add(type); |
| return this; |
| } |
| |
| public SchemaBuilder addEntityContainer(final EntityContainer container) { |
| entityContainers.add(container); |
| return this; |
| } |
| |
| public SchemaBuilder addComplexType(final ComplexType createEntityType) { |
| complexTypes.add(createEntityType); |
| return this; |
| } |
| |
| public void addAssociations(final 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(final Association associationOne, final 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(final String namespace, final String containerName) { |
| this.namespace = namespace; |
| name = containerName; |
| } |
| |
| public String getNamespace() { |
| return namespace; |
| } |
| |
| public static ContainerBuilder init(final String namespace, final String containerName) { |
| return new ContainerBuilder(namespace, containerName); |
| } |
| |
| public ContainerBuilder addEntitySet(final EntitySet entitySet) { |
| entitySets.add(entitySet); |
| return this; |
| } |
| |
| public void addAssociationSets(final Collection<Association> associations) throws ODataException { |
| 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(final AssociationEnd end) throws ODataException { |
| for (EntitySet entitySet : entitySets) { |
| if (entitySet.getEntityType().equals(end.getType())) { |
| return entitySet.getName(); |
| } |
| } |
| throw new ODataException("No entity set found for " + end.getType()); |
| } |
| } |
| } |