| /* |
| * 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.server.core.serializer.xml; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamWriter; |
| |
| import org.apache.olingo.commons.api.edm.EdmAction; |
| import org.apache.olingo.commons.api.edm.EdmActionImport; |
| import org.apache.olingo.commons.api.edm.EdmAnnotatable; |
| import org.apache.olingo.commons.api.edm.EdmAnnotation; |
| import org.apache.olingo.commons.api.edm.EdmAnnotations; |
| import org.apache.olingo.commons.api.edm.EdmBindingTarget; |
| import org.apache.olingo.commons.api.edm.EdmComplexType; |
| import org.apache.olingo.commons.api.edm.EdmEntityContainer; |
| import org.apache.olingo.commons.api.edm.EdmEntitySet; |
| import org.apache.olingo.commons.api.edm.EdmEntityType; |
| import org.apache.olingo.commons.api.edm.EdmEnumType; |
| import org.apache.olingo.commons.api.edm.EdmFunction; |
| import org.apache.olingo.commons.api.edm.EdmFunctionImport; |
| import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef; |
| import org.apache.olingo.commons.api.edm.EdmMember; |
| import org.apache.olingo.commons.api.edm.EdmNavigationProperty; |
| import org.apache.olingo.commons.api.edm.EdmNavigationPropertyBinding; |
| import org.apache.olingo.commons.api.edm.EdmOperation; |
| import org.apache.olingo.commons.api.edm.EdmParameter; |
| import org.apache.olingo.commons.api.edm.EdmProperty; |
| import org.apache.olingo.commons.api.edm.EdmReferentialConstraint; |
| import org.apache.olingo.commons.api.edm.EdmReturnType; |
| import org.apache.olingo.commons.api.edm.EdmSchema; |
| import org.apache.olingo.commons.api.edm.EdmSingleton; |
| import org.apache.olingo.commons.api.edm.EdmStructuredType; |
| import org.apache.olingo.commons.api.edm.EdmTerm; |
| import org.apache.olingo.commons.api.edm.EdmType; |
| import org.apache.olingo.commons.api.edm.EdmTypeDefinition; |
| import org.apache.olingo.commons.api.edm.FullQualifiedName; |
| import org.apache.olingo.commons.api.edm.TargetType; |
| import org.apache.olingo.commons.api.edm.annotation.EdmApply; |
| import org.apache.olingo.commons.api.edm.annotation.EdmCast; |
| import org.apache.olingo.commons.api.edm.annotation.EdmConstantExpression; |
| import org.apache.olingo.commons.api.edm.annotation.EdmDynamicExpression; |
| import org.apache.olingo.commons.api.edm.annotation.EdmExpression; |
| import org.apache.olingo.commons.api.edm.annotation.EdmIf; |
| import org.apache.olingo.commons.api.edm.annotation.EdmIsOf; |
| import org.apache.olingo.commons.api.edm.annotation.EdmLabeledElement; |
| import org.apache.olingo.commons.api.edm.annotation.EdmLabeledElementReference; |
| import org.apache.olingo.commons.api.edm.annotation.EdmLogicalOrComparisonExpression; |
| import org.apache.olingo.commons.api.edm.annotation.EdmNavigationPropertyPath; |
| import org.apache.olingo.commons.api.edm.annotation.EdmNot; |
| import org.apache.olingo.commons.api.edm.annotation.EdmPath; |
| import org.apache.olingo.commons.api.edm.annotation.EdmPropertyPath; |
| import org.apache.olingo.commons.api.edm.annotation.EdmPropertyValue; |
| import org.apache.olingo.commons.api.edm.annotation.EdmRecord; |
| import org.apache.olingo.commons.api.edm.annotation.EdmUrlRef; |
| import org.apache.olingo.commons.api.edm.constants.EdmTypeKind; |
| import org.apache.olingo.commons.api.edmx.EdmxReference; |
| import org.apache.olingo.commons.api.edmx.EdmxReferenceInclude; |
| import org.apache.olingo.commons.api.edmx.EdmxReferenceIncludeAnnotation; |
| import org.apache.olingo.server.api.ServiceMetadata; |
| import org.apache.olingo.server.api.serializer.ODataSerializer; |
| import org.apache.olingo.server.api.serializer.SerializerException; |
| |
| public class MetadataDocumentXmlSerializer { |
| |
| private static final String TRUE = "true"; |
| private static final String XML_EXTENDS = "Extends"; |
| private static final String XML_TARGET = "Target"; |
| private static final String XML_PATH = "Path"; |
| private static final String XML_NAVIGATION_PROPERTY_BINDING = "NavigationPropertyBinding"; |
| private static final String XML_VALUE = "Value"; |
| private static final String XML_MEMBER = "Member"; |
| private static final String XML_UNDERLYING_TYPE = "UnderlyingType"; |
| private static final String XML_IS_FLAGS = "IsFlags"; |
| private static final String XML_ENUM_TYPE = "EnumType"; |
| private static final String XML_PROPERTY_REF = "PropertyRef"; |
| private static final String XML_KEY = "Key"; |
| private static final String XML_SCALE = "Scale"; |
| private static final String XML_SRID = "SRID"; |
| private static final String XML_PRECISION = "Precision"; |
| private static final String XML_MAX_LENGTH = "MaxLength"; |
| private static final String XML_DEFAULT_VALUE = "DefaultValue"; |
| private static final String XML_UNICODE = "Unicode"; |
| private static final String XML_PROPERTY = "Property"; |
| private static final String XML_PARTNER = "Partner"; |
| private static final String XML_NULLABLE = "Nullable"; |
| private static final String XML_NAVIGATION_PROPERTY = "NavigationProperty"; |
| private static final String XML_HAS_STREAM = "HasStream"; |
| private static final String XML_BASE_TYPE = "BaseType"; |
| private static final String XML_COMPLEX_TYPE = "ComplexType"; |
| private static final String XML_RETURN_TYPE = "ReturnType"; |
| private static final String XML_TYPE = "Type"; |
| private static final String XML_PARAMETER = "Parameter"; |
| private static final String XML_IS_COMPOSABLE = "IsComposable"; |
| private static final String XML_IS_BOUND = "IsBound"; |
| private static final String XML_ENTITY_TYPE = "EntityType"; |
| private static final String XML_SINGLETON_TYPE = XML_TYPE; |
| private static final String XML_SINGLETON = "Singleton"; |
| private static final String XML_ACTION = "Action"; |
| private static final String XML_ACTION_IMPORT = "ActionImport"; |
| private static final String XML_INCLUDE_IN_SERVICE_DOCUMENT = "IncludeInServiceDocument"; |
| private static final String XML_ENTITY_SET = "EntitySet"; |
| private static final String XML_FUNCTION = "Function"; |
| private static final String XML_FUNCTION_IMPORT = "FunctionImport"; |
| private static final String XML_NAME = "Name"; |
| private static final String XML_ENTITY_CONTAINER = "EntityContainer"; |
| private static final String XML_ALIAS = "Alias"; |
| private static final String XML_NAMESPACE = "Namespace"; |
| private static final String XML_TYPE_DEFINITION = "TypeDefinition"; |
| private static final String XML_ANNOTATION = "Annotation"; |
| private static final String REFERENCE = "Reference"; |
| private static final String INCLUDE = "Include"; |
| private static final String INCLUDE_ANNOTATIONS = "IncludeAnnotations"; |
| private static final String XML_TERM_NAMESPACE = "TermNamespace"; |
| private static final String XML_TARGET_NAMESPACE = "TargetNamespace"; |
| private static final String XML_QUALIFIER = "Qualifier"; |
| private static final String URI = "Uri"; |
| private static final String SCHEMA = "Schema"; |
| private static final String DATA_SERVICES = "DataServices"; |
| private static final String ABSTRACT = "Abstract"; |
| |
| private static final String XML_ANNOTATIONS = "Annotations"; |
| private static final String OPEN_TYPE = "OpenType"; |
| |
| private static final String EDMX = "Edmx"; |
| private static final String PREFIX_EDMX = "edmx"; |
| private static final String NS_EDMX = "http://docs.oasis-open.org/odata/ns/edmx"; |
| |
| private static final String NS_EDM = "http://docs.oasis-open.org/odata/ns/edm"; |
| private static final String XML_ENTITY_SET_PATH = "EntitySetPath"; |
| private static final String XML_CONTAINS_TARGET = "ContainsTarget"; |
| private static final String XML_TERM_ATT = "Term"; |
| private static final String XML_QUALIFIER_ATT = "Qualifier"; |
| private static final String XML_PROPERTY_VALUE = "PropertyValue"; |
| private static final String XML_BASE_TERM = "BaseTerm"; |
| private static final String XML_APPLIES_TO = "AppliesTo"; |
| |
| private final ServiceMetadata serviceMetadata; |
| private final Map<String, String> namespaceToAlias = new HashMap<>(); |
| |
| public MetadataDocumentXmlSerializer(final ServiceMetadata serviceMetadata) throws SerializerException { |
| if (serviceMetadata == null || serviceMetadata.getEdm() == null) { |
| throw new SerializerException("Service Metadata and EDM must not be null for a service.", |
| SerializerException.MessageKeys.NULL_METADATA_OR_EDM); |
| } |
| this.serviceMetadata = serviceMetadata; |
| } |
| |
| public void writeMetadataDocument(final XMLStreamWriter writer) throws XMLStreamException { |
| writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0"); |
| writer.setPrefix(PREFIX_EDMX, NS_EDMX); |
| writer.setDefaultNamespace(NS_EDMX); |
| writer.writeStartElement(PREFIX_EDMX, EDMX, NS_EDMX); |
| writer.writeAttribute("Version", "4.0"); |
| writer.writeNamespace(PREFIX_EDMX, NS_EDMX); |
| |
| appendReference(writer); |
| appendDataServices(writer); |
| |
| writer.writeEndDocument(); |
| } |
| |
| private void appendDataServices(final XMLStreamWriter writer) throws XMLStreamException { |
| writer.setDefaultNamespace(NS_EDM); |
| writer.writeStartElement(NS_EDMX, DATA_SERVICES); |
| for (EdmSchema schema : serviceMetadata.getEdm().getSchemas()) { |
| appendSchema(writer, schema); |
| } |
| writer.writeEndElement(); |
| } |
| |
| private void appendSchema(final XMLStreamWriter writer, final EdmSchema schema) throws XMLStreamException { |
| writer.writeStartElement(NS_EDM, SCHEMA); |
| writer.writeDefaultNamespace(NS_EDM); |
| writer.writeAttribute(XML_NAMESPACE, schema.getNamespace()); |
| if (schema.getAlias() != null) { |
| writer.writeAttribute(XML_ALIAS, schema.getAlias()); |
| namespaceToAlias.put(schema.getNamespace(), schema.getAlias()); |
| } |
| |
| // EnumTypes |
| appendEnumTypes(writer, schema.getEnumTypes()); |
| |
| // TypeDefinitions |
| appendTypeDefinitions(writer, schema.getTypeDefinitions()); |
| |
| // EntityTypes |
| appendEntityTypes(writer, schema.getEntityTypes()); |
| |
| // ComplexTypes |
| appendComplexTypes(writer, schema.getComplexTypes()); |
| |
| // Actions |
| appendActions(writer, schema.getActions()); |
| |
| // Functions |
| appendFunctions(writer, schema.getFunctions()); |
| |
| appendTerms(writer, schema.getTerms()); |
| |
| // EntityContainer |
| appendEntityContainer(writer, schema.getEntityContainer()); |
| |
| // AnnotationGroups |
| appendAnnotationGroups(writer, schema.getAnnotationGroups()); |
| |
| appendAnnotations(writer, schema); |
| |
| writer.writeEndElement(); |
| } |
| |
| private void appendTerms(final XMLStreamWriter writer, final List<EdmTerm> terms) throws XMLStreamException { |
| for (EdmTerm term : terms) { |
| writer.writeStartElement(XML_TERM_ATT); |
| |
| writer.writeAttribute(XML_NAME, term.getName()); |
| |
| writer.writeAttribute(XML_TYPE, getAliasedFullQualifiedName(term.getType(), false)); |
| |
| if (term.getBaseTerm() != null) { |
| writer.writeAttribute(XML_BASE_TERM, getAliasedFullQualifiedName(term.getBaseTerm().getFullQualifiedName(), |
| false)); |
| } |
| |
| if (term.getAppliesTo() != null && !term.getAppliesTo().isEmpty()) { |
| String appliesToString = ""; |
| boolean first = true; |
| for (TargetType target : term.getAppliesTo()) { |
| if (first) { |
| first = false; |
| appliesToString = target.toString(); |
| } else { |
| appliesToString = appliesToString + " " + target.toString(); |
| } |
| } |
| writer.writeAttribute(XML_APPLIES_TO, appliesToString); |
| } |
| |
| // Facets |
| if (!term.isNullable()) { |
| writer.writeAttribute(XML_NULLABLE, "" + term.isNullable()); |
| } |
| |
| if (term.getDefaultValue() != null) { |
| writer.writeAttribute(XML_DEFAULT_VALUE, term.getDefaultValue()); |
| } |
| |
| if (term.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + term.getMaxLength()); |
| } |
| |
| if (term.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + term.getPrecision()); |
| } |
| |
| if (term.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + term.getScale()); |
| } |
| |
| appendAnnotations(writer, term); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendAnnotationGroups(final XMLStreamWriter writer, final List<EdmAnnotations> annotationGroups) |
| throws XMLStreamException { |
| for (EdmAnnotations annotationGroup : annotationGroups) { |
| appendAnnotationGroup(writer, annotationGroup); |
| } |
| } |
| |
| private void appendAnnotationGroup(final XMLStreamWriter writer, final EdmAnnotations annotationGroup) |
| throws XMLStreamException { |
| writer.writeStartElement(XML_ANNOTATIONS); |
| writer.writeAttribute(XML_TARGET, annotationGroup.getTargetPath()); |
| if (annotationGroup.getQualifier() != null) { |
| writer.writeAttribute(XML_QUALIFIER_ATT, annotationGroup.getQualifier()); |
| } |
| appendAnnotations(writer, annotationGroup); |
| writer.writeEndElement(); |
| } |
| |
| private void appendAnnotations(final XMLStreamWriter writer, final EdmAnnotatable annotatable) |
| throws XMLStreamException { |
| List<EdmAnnotation> annotations = annotatable.getAnnotations(); |
| if (annotations != null && !annotations.isEmpty()) { |
| for (EdmAnnotation annotation : annotations) { |
| writer.writeStartElement(XML_ANNOTATION); |
| if (annotation.getTerm() != null) { |
| writer.writeAttribute(XML_TERM_ATT, getAliasedFullQualifiedName(annotation.getTerm().getFullQualifiedName(), |
| false)); |
| } |
| if (annotation.getQualifier() != null) { |
| writer.writeAttribute(XML_QUALIFIER_ATT, annotation.getQualifier()); |
| } |
| appendExpression(writer, annotation.getExpression()); |
| appendAnnotations(writer, annotation); |
| writer.writeEndElement(); |
| } |
| } |
| } |
| |
| private void appendExpression(final XMLStreamWriter writer, |
| final EdmExpression expression) throws XMLStreamException { |
| if (expression == null) { |
| return; |
| } |
| if (expression.isConstant()) { |
| appendConstantExpression(writer, expression.asConstant()); |
| } else if (expression.isDynamic()) { |
| appendDynamicExpression(writer, expression.asDynamic()); |
| } else { |
| throw new IllegalArgumentException("Unkown expressiontype in metadata"); |
| } |
| } |
| |
| private void appendDynamicExpression(final XMLStreamWriter writer, final EdmDynamicExpression dynExp) |
| throws XMLStreamException { |
| writer.writeStartElement(dynExp.getExpressionName()); |
| switch (dynExp.getExpressionType()) { |
| // Logical |
| case And: |
| appendLogicalOrComparisonExpression(writer, dynExp.asAnd()); |
| break; |
| case Or: |
| appendLogicalOrComparisonExpression(writer, dynExp.asOr()); |
| break; |
| case Not: |
| appendNotExpression(writer, dynExp.asNot()); |
| break; |
| // Comparison |
| case Eq: |
| appendLogicalOrComparisonExpression(writer, dynExp.asEq()); |
| break; |
| case Ne: |
| appendLogicalOrComparisonExpression(writer, dynExp.asNe()); |
| break; |
| case Gt: |
| appendLogicalOrComparisonExpression(writer, dynExp.asGt()); |
| break; |
| case Ge: |
| appendLogicalOrComparisonExpression(writer, dynExp.asGe()); |
| break; |
| case Lt: |
| appendLogicalOrComparisonExpression(writer, dynExp.asLt()); |
| break; |
| case Le: |
| appendLogicalOrComparisonExpression(writer, dynExp.asLe()); |
| break; |
| case AnnotationPath: |
| writer.writeCharacters(dynExp.asAnnotationPath().getValue()); |
| break; |
| case Apply: |
| EdmApply asApply = dynExp.asApply(); |
| writer.writeAttribute(XML_FUNCTION, asApply.getFunction()); |
| for (EdmExpression parameter : asApply.getParameters()) { |
| appendExpression(writer, parameter); |
| } |
| appendAnnotations(writer, asApply); |
| break; |
| case Cast: |
| EdmCast asCast = dynExp.asCast(); |
| writer.writeAttribute(XML_TYPE, getAliasedFullQualifiedName(asCast.getType(), false)); |
| |
| if (asCast.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + asCast.getMaxLength()); |
| } |
| |
| if (asCast.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + asCast.getPrecision()); |
| } |
| |
| if (asCast.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + asCast.getScale()); |
| } |
| appendExpression(writer, asCast.getValue()); |
| appendAnnotations(writer, asCast); |
| break; |
| case Collection: |
| for (EdmExpression item : dynExp.asCollection().getItems()) { |
| appendExpression(writer, item); |
| } |
| break; |
| case If: |
| EdmIf asIf = dynExp.asIf(); |
| appendExpression(writer, asIf.getGuard()); |
| appendExpression(writer, asIf.getThen()); |
| appendExpression(writer, asIf.getElse()); |
| appendAnnotations(writer, asIf); |
| break; |
| case IsOf: |
| EdmIsOf asIsOf = dynExp.asIsOf(); |
| writer.writeAttribute(XML_TYPE, getAliasedFullQualifiedName(asIsOf.getType(), false)); |
| |
| if (asIsOf.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + asIsOf.getMaxLength()); |
| } |
| |
| if (asIsOf.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + asIsOf.getPrecision()); |
| } |
| |
| if (asIsOf.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + asIsOf.getScale()); |
| } |
| appendExpression(writer, asIsOf.getValue()); |
| appendAnnotations(writer, asIsOf); |
| break; |
| case LabeledElement: |
| EdmLabeledElement asLabeledElement = dynExp.asLabeledElement(); |
| writer.writeAttribute(XML_NAME, asLabeledElement.getName()); |
| appendExpression(writer, asLabeledElement.getValue()); |
| appendAnnotations(writer, asLabeledElement); |
| break; |
| case LabeledElementReference: |
| EdmLabeledElementReference asLabeledElementReference = dynExp.asLabeledElementReference(); |
| writer.writeCharacters(asLabeledElementReference.getValue()); |
| break; |
| case Null: |
| appendAnnotations(writer, dynExp.asNull()); |
| break; |
| case NavigationPropertyPath: |
| EdmNavigationPropertyPath asNavigationPropertyPath = dynExp.asNavigationPropertyPath(); |
| writer.writeCharacters(asNavigationPropertyPath.getValue()); |
| break; |
| case Path: |
| EdmPath asPath = dynExp.asPath(); |
| writer.writeCharacters(asPath.getValue()); |
| break; |
| case PropertyPath: |
| EdmPropertyPath asPropertyPath = dynExp.asPropertyPath(); |
| writer.writeCharacters(asPropertyPath.getValue()); |
| break; |
| case Record: |
| EdmRecord asRecord = dynExp.asRecord(); |
| EdmStructuredType type = asRecord.getType(); |
| if (type != null) { |
| writer.writeAttribute(XML_TYPE, getAliasedFullQualifiedName(type, false)); |
| } |
| for (EdmPropertyValue propValue : asRecord.getPropertyValues()) { |
| writer.writeStartElement(XML_PROPERTY_VALUE); |
| writer.writeAttribute(XML_PROPERTY, propValue.getProperty()); |
| appendExpression(writer, propValue.getValue()); |
| appendAnnotations(writer, propValue); |
| writer.writeEndElement(); |
| } |
| appendAnnotations(writer, asRecord); |
| break; |
| case UrlRef: |
| EdmUrlRef asUrlRef = dynExp.asUrlRef(); |
| appendExpression(writer, asUrlRef.getValue()); |
| appendAnnotations(writer, asUrlRef); |
| break; |
| default: |
| throw new IllegalArgumentException("Unkown ExpressionType for dynamic expression: " + dynExp.getExpressionType()); |
| } |
| |
| writer.writeEndElement(); |
| } |
| |
| private void appendNotExpression(final XMLStreamWriter writer, final EdmNot exp) throws XMLStreamException { |
| appendExpression(writer, exp.getLeftExpression()); |
| appendAnnotations(writer, exp); |
| } |
| |
| private void appendLogicalOrComparisonExpression(final XMLStreamWriter writer, |
| final EdmLogicalOrComparisonExpression exp) |
| throws XMLStreamException { |
| appendExpression(writer, exp.getLeftExpression()); |
| appendExpression(writer, exp.getRightExpression()); |
| appendAnnotations(writer, exp); |
| } |
| |
| private void appendConstantExpression(final XMLStreamWriter writer, final EdmConstantExpression constExp) |
| throws XMLStreamException { |
| writer.writeStartElement(constExp.getExpressionName()); |
| writer.writeCharacters(constExp.getValueAsString()); |
| writer.writeEndElement(); |
| } |
| |
| private void appendTypeDefinitions(final XMLStreamWriter writer, final List<EdmTypeDefinition> typeDefinitions) |
| throws XMLStreamException { |
| for (EdmTypeDefinition definition : typeDefinitions) { |
| writer.writeStartElement(XML_TYPE_DEFINITION); |
| writer.writeAttribute(XML_NAME, definition.getName()); |
| writer.writeAttribute(XML_UNDERLYING_TYPE, getFullQualifiedName(definition.getUnderlyingType(), false)); |
| |
| // Facets |
| if (definition.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + definition.getMaxLength()); |
| } |
| |
| if (definition.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + definition.getPrecision()); |
| } |
| |
| if (definition.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + definition.getScale()); |
| } |
| |
| appendAnnotations(writer, definition); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendEntityContainer(final XMLStreamWriter writer, final EdmEntityContainer container) |
| throws XMLStreamException { |
| if (container != null) { |
| writer.writeStartElement(XML_ENTITY_CONTAINER); |
| |
| writer.writeAttribute(XML_NAME, container.getName()); |
| FullQualifiedName parentContainerName = container.getParentContainerName(); |
| if (parentContainerName != null) { |
| String parentContainerNameString; |
| if (namespaceToAlias.get(parentContainerName.getNamespace()) != null) { |
| parentContainerNameString = |
| namespaceToAlias.get(parentContainerName.getNamespace()) + "." + parentContainerName.getName(); |
| } else { |
| parentContainerNameString = parentContainerName.getFullQualifiedNameAsString(); |
| } |
| writer.writeAttribute(XML_EXTENDS, parentContainerNameString); |
| } |
| |
| // EntitySets |
| appendEntitySets(writer, container.getEntitySets()); |
| |
| // ActionImports |
| appendActionImports(writer, container.getActionImports()); |
| |
| // FunctionImports |
| String containerNamespace; |
| if (namespaceToAlias.get(container.getNamespace()) != null) { |
| containerNamespace = namespaceToAlias.get(container.getNamespace()); |
| } else { |
| containerNamespace = container.getNamespace(); |
| } |
| appendFunctionImports(writer, container.getFunctionImports(), containerNamespace); |
| |
| // Singletons |
| appendSingletons(writer, container.getSingletons()); |
| |
| // Annotations |
| appendAnnotations(writer, container); |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendFunctionImports(final XMLStreamWriter writer, final List<EdmFunctionImport> functionImports, |
| final String containerNamespace) throws XMLStreamException { |
| for (EdmFunctionImport functionImport : functionImports) { |
| writer.writeStartElement(XML_FUNCTION_IMPORT); |
| writer.writeAttribute(XML_NAME, functionImport.getName()); |
| |
| String functionFQNString; |
| FullQualifiedName functionFqn = functionImport.getFunctionFqn(); |
| if (namespaceToAlias.get(functionFqn.getNamespace()) != null) { |
| functionFQNString = namespaceToAlias.get(functionFqn.getNamespace()) + "." + functionFqn.getName(); |
| } else { |
| functionFQNString = functionFqn.getFullQualifiedNameAsString(); |
| } |
| writer.writeAttribute(XML_FUNCTION, functionFQNString); |
| |
| EdmEntitySet returnedEntitySet = functionImport.getReturnedEntitySet(); |
| if (returnedEntitySet != null) { |
| String returnedEntitySetNamespace = returnedEntitySet.getEntityContainer().getNamespace(); |
| if ((null != returnedEntitySetNamespace && returnedEntitySetNamespace.equals(containerNamespace)) || ( |
| namespaceToAlias.get(returnedEntitySetNamespace) != null && |
| namespaceToAlias.get(returnedEntitySetNamespace).equals(containerNamespace))) { |
| writer.writeAttribute(XML_ENTITY_SET, returnedEntitySet.getName()); |
| } else { |
| writer.writeAttribute(XML_ENTITY_SET, containerNamespace + "." + returnedEntitySet.getName()); |
| } |
| } |
| // Default is false and we do not write the default |
| if (functionImport.isIncludeInServiceDocument()) { |
| writer.writeAttribute(XML_INCLUDE_IN_SERVICE_DOCUMENT, "" + functionImport.isIncludeInServiceDocument()); |
| } |
| appendAnnotations(writer, functionImport); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendActionImports(final XMLStreamWriter writer, final List<EdmActionImport> actionImports) |
| throws XMLStreamException { |
| for (EdmActionImport actionImport : actionImports) { |
| writer.writeStartElement(XML_ACTION_IMPORT); |
| writer.writeAttribute(XML_NAME, actionImport.getName()); |
| writer.writeAttribute(XML_ACTION, getAliasedFullQualifiedName(actionImport.getUnboundAction(), false)); |
| appendAnnotations(writer, actionImport); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendSingletons(final XMLStreamWriter writer, final List<EdmSingleton> singletons) |
| throws XMLStreamException { |
| for (EdmSingleton singleton : singletons) { |
| writer.writeStartElement(XML_SINGLETON); |
| writer.writeAttribute(XML_NAME, singleton.getName()); |
| writer.writeAttribute(XML_SINGLETON_TYPE, getAliasedFullQualifiedName(singleton.getEntityType(), false)); |
| |
| appendNavigationPropertyBindings(writer, singleton); |
| appendAnnotations(writer, singleton); |
| writer.writeEndElement(); |
| } |
| |
| } |
| |
| private void appendNavigationPropertyBindings(final XMLStreamWriter writer, final EdmBindingTarget bindingTarget) |
| throws XMLStreamException { |
| if (bindingTarget.getNavigationPropertyBindings() != null) { |
| for (EdmNavigationPropertyBinding binding : bindingTarget.getNavigationPropertyBindings()) { |
| writer.writeEmptyElement(XML_NAVIGATION_PROPERTY_BINDING); |
| writer.writeAttribute(XML_PATH, binding.getPath()); |
| writer.writeAttribute(XML_TARGET, binding.getTarget()); |
| } |
| } |
| } |
| |
| private void appendEntitySets(final XMLStreamWriter writer, final List<EdmEntitySet> entitySets) |
| throws XMLStreamException { |
| for (EdmEntitySet entitySet : entitySets) { |
| writer.writeStartElement(XML_ENTITY_SET); |
| writer.writeAttribute(XML_NAME, entitySet.getName()); |
| writer.writeAttribute(XML_ENTITY_TYPE, getAliasedFullQualifiedName(entitySet.getEntityType(), false)); |
| if (!entitySet.isIncludeInServiceDocument()) { |
| writer.writeAttribute(XML_INCLUDE_IN_SERVICE_DOCUMENT, "" + entitySet.isIncludeInServiceDocument()); |
| } |
| |
| appendNavigationPropertyBindings(writer, entitySet); |
| appendAnnotations(writer, entitySet); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendFunctions(final XMLStreamWriter writer, final List<EdmFunction> functions) |
| throws XMLStreamException { |
| for (EdmFunction function : functions) { |
| writer.writeStartElement(XML_FUNCTION); |
| writer.writeAttribute(XML_NAME, function.getName()); |
| if (function.getEntitySetPath() != null) { |
| writer.writeAttribute(XML_ENTITY_SET_PATH, function.getEntitySetPath()); |
| } |
| if (function.isBound()) { |
| writer.writeAttribute(XML_IS_BOUND, "" + function.isBound()); |
| } |
| |
| if (function.isComposable()) { |
| writer.writeAttribute(XML_IS_COMPOSABLE, "" + function.isComposable()); |
| } |
| |
| appendOperationParameters(writer, function); |
| |
| appendOperationReturnType(writer, function); |
| |
| appendAnnotations(writer, function); |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendOperationReturnType(final XMLStreamWriter writer, final EdmOperation operation) |
| throws XMLStreamException { |
| EdmReturnType returnType = operation.getReturnType(); |
| if (returnType != null) { |
| writer.writeEmptyElement(XML_RETURN_TYPE); |
| String returnTypeFqnString; |
| if (EdmTypeKind.PRIMITIVE.equals(returnType.getType().getKind())) { |
| returnTypeFqnString = getFullQualifiedName(returnType.getType(), returnType.isCollection()); |
| } else { |
| returnTypeFqnString = getAliasedFullQualifiedName(returnType.getType(), returnType.isCollection()); |
| } |
| writer.writeAttribute(XML_TYPE, returnTypeFqnString); |
| |
| appendReturnTypeFacets(writer, returnType); |
| } |
| } |
| |
| private void appendOperationParameters(final XMLStreamWriter writer, final EdmOperation operation) |
| throws XMLStreamException { |
| for (String parameterName : operation.getParameterNames()) { |
| EdmParameter parameter = operation.getParameter(parameterName); |
| writer.writeStartElement(XML_PARAMETER); |
| writer.writeAttribute(XML_NAME, parameterName); |
| String typeFqnString; |
| if (EdmTypeKind.PRIMITIVE.equals(parameter.getType().getKind())) { |
| typeFqnString = getFullQualifiedName(parameter.getType(), parameter.isCollection()); |
| } else { |
| typeFqnString = getAliasedFullQualifiedName(parameter.getType(), parameter.isCollection()); |
| } |
| writer.writeAttribute(XML_TYPE, typeFqnString); |
| |
| appendParameterFacets(writer, parameter); |
| |
| appendAnnotations(writer, parameter); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendActions(final XMLStreamWriter writer, final List<EdmAction> actions) throws XMLStreamException { |
| for (EdmAction action : actions) { |
| writer.writeStartElement(XML_ACTION); |
| writer.writeAttribute(XML_NAME, action.getName()); |
| if (action.getEntitySetPath() != null) { |
| writer.writeAttribute(XML_ENTITY_SET_PATH, action.getEntitySetPath()); |
| } |
| writer.writeAttribute(XML_IS_BOUND, "" + action.isBound()); |
| |
| appendOperationParameters(writer, action); |
| |
| appendOperationReturnType(writer, action); |
| |
| appendAnnotations(writer, action); |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendReturnTypeFacets(final XMLStreamWriter writer, final EdmReturnType returnType) |
| throws XMLStreamException { |
| if (!returnType.isNullable()) { |
| writer.writeAttribute(XML_NULLABLE, "" + returnType.isNullable()); |
| } |
| if (returnType.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + returnType.getMaxLength()); |
| } |
| if (returnType.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + returnType.getPrecision()); |
| } |
| if (returnType.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + returnType.getScale()); |
| } |
| } |
| |
| private void appendParameterFacets(final XMLStreamWriter writer, final EdmParameter parameter) |
| throws XMLStreamException { |
| if (!parameter.isNullable()) { |
| writer.writeAttribute(XML_NULLABLE, "" + parameter.isNullable()); |
| } |
| if (parameter.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + parameter.getMaxLength()); |
| } |
| if (parameter.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + parameter.getPrecision()); |
| } |
| if (parameter.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + parameter.getScale()); |
| } |
| } |
| |
| private void appendComplexTypes(final XMLStreamWriter writer, final List<EdmComplexType> complexTypes) |
| throws XMLStreamException { |
| for (EdmComplexType complexType : complexTypes) { |
| writer.writeStartElement(XML_COMPLEX_TYPE); |
| writer.writeAttribute(XML_NAME, complexType.getName()); |
| |
| if (complexType.getBaseType() != null) { |
| writer.writeAttribute(XML_BASE_TYPE, getAliasedFullQualifiedName(complexType.getBaseType(), false)); |
| } |
| |
| if (complexType.isAbstract()) { |
| writer.writeAttribute(ABSTRACT, TRUE); |
| } |
| |
| if (complexType.isOpenType()) { |
| writer.writeAttribute(OPEN_TYPE, TRUE); |
| } |
| |
| appendProperties(writer, complexType); |
| |
| appendNavigationProperties(writer, complexType); |
| |
| appendAnnotations(writer, complexType); |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendEntityTypes(final XMLStreamWriter writer, final List<EdmEntityType> entityTypes) |
| throws XMLStreamException { |
| for (EdmEntityType entityType : entityTypes) { |
| writer.writeStartElement(XML_ENTITY_TYPE); |
| writer.writeAttribute(XML_NAME, entityType.getName()); |
| |
| if (entityType.hasStream()) { |
| writer.writeAttribute(XML_HAS_STREAM, "" + entityType.hasStream()); |
| } |
| |
| if (entityType.getBaseType() != null) { |
| writer.writeAttribute(XML_BASE_TYPE, getAliasedFullQualifiedName(entityType.getBaseType(), false)); |
| } |
| |
| if (entityType.isAbstract()) { |
| writer.writeAttribute(ABSTRACT, TRUE); |
| } |
| |
| if (entityType.isOpenType()) { |
| writer.writeAttribute(OPEN_TYPE, TRUE); |
| } |
| |
| appendKey(writer, entityType); |
| |
| appendProperties(writer, entityType); |
| |
| appendNavigationProperties(writer, entityType); |
| |
| appendAnnotations(writer, entityType); |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendNavigationProperties(final XMLStreamWriter writer, final EdmStructuredType type) |
| throws XMLStreamException { |
| List<String> navigationPropertyNames = new ArrayList<>(type.getNavigationPropertyNames()); |
| if (type.getBaseType() != null) { |
| navigationPropertyNames.removeAll(type.getBaseType().getNavigationPropertyNames()); |
| } |
| for (String navigationPropertyName : navigationPropertyNames) { |
| EdmNavigationProperty navigationProperty = type.getNavigationProperty(navigationPropertyName); |
| |
| writer.writeStartElement(XML_NAVIGATION_PROPERTY); |
| writer.writeAttribute(XML_NAME, navigationPropertyName); |
| writer.writeAttribute(XML_TYPE, getAliasedFullQualifiedName(navigationProperty.getType(), navigationProperty |
| .isCollection())); |
| if (!navigationProperty.isNullable()) { |
| writer.writeAttribute(XML_NULLABLE, "" + navigationProperty.isNullable()); |
| } |
| |
| if (navigationProperty.getPartner() != null) { |
| EdmNavigationProperty partner = navigationProperty.getPartner(); |
| writer.writeAttribute(XML_PARTNER, partner.getName()); |
| } |
| |
| if (navigationProperty.containsTarget()) { |
| writer.writeAttribute(XML_CONTAINS_TARGET, "" + navigationProperty.containsTarget()); |
| } |
| |
| if (navigationProperty.getReferentialConstraints() != null) { |
| for (EdmReferentialConstraint constraint : navigationProperty.getReferentialConstraints()) { |
| writer.writeStartElement("ReferentialConstraint"); |
| writer.writeAttribute(XML_PROPERTY, constraint.getPropertyName()); |
| writer.writeAttribute("ReferencedProperty", constraint.getReferencedPropertyName()); |
| appendAnnotations(writer, constraint); |
| writer.writeEndElement(); |
| } |
| } |
| |
| appendAnnotations(writer, navigationProperty); |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendProperties(final XMLStreamWriter writer, final EdmStructuredType type) throws XMLStreamException { |
| List<String> propertyNames = new ArrayList<>(type.getPropertyNames()); |
| if (type.getBaseType() != null) { |
| propertyNames.removeAll(type.getBaseType().getPropertyNames()); |
| } |
| for (String propertyName : propertyNames) { |
| EdmProperty property = type.getStructuralProperty(propertyName); |
| writer.writeStartElement(XML_PROPERTY); |
| writer.writeAttribute(XML_NAME, propertyName); |
| String fqnString; |
| if (property.isPrimitive()) { |
| fqnString = getFullQualifiedName(property.getType(), property.isCollection()); |
| } else { |
| fqnString = getAliasedFullQualifiedName(property.getType(), property.isCollection()); |
| } |
| writer.writeAttribute(XML_TYPE, fqnString); |
| |
| // Facets |
| if (!property.isNullable()) { |
| writer.writeAttribute(XML_NULLABLE, "" + property.isNullable()); |
| } |
| |
| if (!property.isUnicode()) { |
| writer.writeAttribute(XML_UNICODE, "" + property.isUnicode()); |
| } |
| |
| if (property.getDefaultValue() != null) { |
| writer.writeAttribute(XML_DEFAULT_VALUE, property.getDefaultValue()); |
| } |
| |
| if (property.getMaxLength() != null) { |
| writer.writeAttribute(XML_MAX_LENGTH, "" + property.getMaxLength()); |
| } |
| |
| if (property.getPrecision() != null) { |
| writer.writeAttribute(XML_PRECISION, "" + property.getPrecision()); |
| } |
| |
| if (property.getScale() != null) { |
| writer.writeAttribute(XML_SCALE, "" + property.getScale()); |
| } |
| |
| if (property.getSrid() != null) { |
| writer.writeAttribute(XML_SRID, "" + property.getSrid()); |
| } |
| |
| appendAnnotations(writer, property); |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendKey(final XMLStreamWriter writer, final EdmEntityType entityType) throws XMLStreamException { |
| List<EdmKeyPropertyRef> keyPropertyRefs = entityType.getKeyPropertyRefs(); |
| if (keyPropertyRefs != null && !keyPropertyRefs.isEmpty()) { |
| // Resolve Base Type key as it is shown in derived type |
| EdmEntityType baseType = entityType.getBaseType(); |
| if (baseType != null && baseType.getKeyPropertyRefs() != null && !(baseType.getKeyPropertyRefs().isEmpty())) { |
| return; |
| } |
| |
| writer.writeStartElement(XML_KEY); |
| for (EdmKeyPropertyRef keyRef : keyPropertyRefs) { |
| writer.writeEmptyElement(XML_PROPERTY_REF); |
| |
| writer.writeAttribute(XML_NAME, keyRef.getName()); |
| |
| if (keyRef.getAlias() != null) { |
| writer.writeAttribute(XML_ALIAS, keyRef.getAlias()); |
| } |
| } |
| writer.writeEndElement(); |
| } |
| } |
| |
| private void appendEnumTypes(final XMLStreamWriter writer, final List<EdmEnumType> enumTypes) |
| throws XMLStreamException { |
| for (EdmEnumType enumType : enumTypes) { |
| writer.writeStartElement(XML_ENUM_TYPE); |
| writer.writeAttribute(XML_NAME, enumType.getName()); |
| writer.writeAttribute(XML_IS_FLAGS, Boolean.toString(enumType.isFlags())); |
| writer.writeAttribute(XML_UNDERLYING_TYPE, getFullQualifiedName(enumType.getUnderlyingType(), false)); |
| |
| for (String memberName : enumType.getMemberNames()) { |
| writer.writeStartElement(XML_MEMBER); |
| writer.writeAttribute(XML_NAME, memberName); |
| |
| EdmMember member = enumType.getMember(memberName); |
| if (member.getValue() != null) { |
| writer.writeAttribute(XML_VALUE, member.getValue()); |
| } |
| |
| appendAnnotations(writer, member); |
| writer.writeEndElement(); |
| } |
| |
| writer.writeEndElement(); |
| } |
| } |
| |
| private String getFullQualifiedName(final EdmType type, final boolean isCollection) { |
| final String name = type.getFullQualifiedName().getFullQualifiedNameAsString(); |
| return isCollection ? "Collection(" + name + ")" : name; |
| } |
| |
| private String getAliasedFullQualifiedName(final EdmType type, final boolean isCollection) { |
| FullQualifiedName fqn = type.getFullQualifiedName(); |
| return getAliasedFullQualifiedName(fqn, isCollection); |
| } |
| |
| private String getAliasedFullQualifiedName(final FullQualifiedName fqn, final boolean isCollection) { |
| final String name; |
| if (namespaceToAlias.get(fqn.getNamespace()) != null) { |
| name = namespaceToAlias.get(fqn.getNamespace()) + "." + fqn.getName(); |
| } else { |
| name = fqn.getFullQualifiedNameAsString(); |
| } |
| |
| return isCollection ? "Collection(" + name + ")" : name; |
| } |
| |
| /** |
| * Appends references, e.g., to the OData Core Vocabulary, as defined in the OData specification |
| * and mentioned in its Common Schema Definition Language (CSDL) document. |
| */ |
| private void appendReference(final XMLStreamWriter writer) throws XMLStreamException { |
| for (final EdmxReference reference : serviceMetadata.getReferences()) { |
| writer.writeStartElement(PREFIX_EDMX, REFERENCE, NS_EDMX); |
| writer.writeAttribute(URI, reference.getUri().toASCIIString()); |
| |
| List<EdmxReferenceInclude> includes = reference.getIncludes(); |
| for (EdmxReferenceInclude include : includes) { |
| writer.writeStartElement(PREFIX_EDMX, INCLUDE, NS_EDMX); |
| writer.writeAttribute(XML_NAMESPACE, include.getNamespace()); |
| if (include.getAlias() != null) { |
| namespaceToAlias.put(include.getNamespace(), include.getAlias()); |
| // Reference Aliases are ignored for now since they are not V2 compatible |
| writer.writeAttribute(XML_ALIAS, include.getAlias()); |
| } |
| writer.writeEndElement(); |
| } |
| |
| List<EdmxReferenceIncludeAnnotation> includeAnnotations = reference.getIncludeAnnotations(); |
| for (EdmxReferenceIncludeAnnotation includeAnnotation : includeAnnotations) { |
| writer.writeStartElement(PREFIX_EDMX, INCLUDE_ANNOTATIONS, NS_EDMX); |
| writer.writeAttribute(XML_TERM_NAMESPACE, includeAnnotation.getTermNamespace()); |
| if (includeAnnotation.getQualifier() != null) { |
| writer.writeAttribute(XML_QUALIFIER, includeAnnotation.getQualifier()); |
| } |
| if (includeAnnotation.getTargetNamespace() != null) { |
| writer.writeAttribute(XML_TARGET_NAMESPACE, includeAnnotation.getTargetNamespace()); |
| } |
| writer.writeEndElement(); |
| } |
| |
| writer.writeEndElement(); |
| } |
| } |
| } |