You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/08/04 16:57:40 UTC
[04/13] olingo-odata4 git commit: OLINGO-640: Adding support for
ATOM+XML Serializer and De-Serializer
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
new file mode 100644
index 0000000..de50032
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
@@ -0,0 +1,1038 @@
+/*
+ * 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.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.ODataErrorDetail;
+import org.apache.olingo.commons.api.data.ComplexValue;
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.data.Linked;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
+import org.apache.olingo.server.api.ODataServerError;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
+import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+import org.apache.olingo.server.core.serializer.SerializerResultImpl;
+import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
+import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
+import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ODataXmlSerializer implements ODataSerializer {
+ private static final String DATA = "d";
+ private static final String CONTEXT = "context";
+ /** The default character set is UTF-8. */
+ public static final String DEFAULT_CHARSET = "UTF-8";
+ private static final String ATOM = "a";
+ private static final String NS_ATOM = "http://www.w3.org/2005/Atom";
+ private static final String METADATA = "m";
+ private static final String NS_METADATA = "http://docs.oasis-open.org/odata/ns/metadata";
+ private static final String NS_DATA = "http://docs.oasis-open.org/odata/ns/data";
+ private static final String NS_SCHEMA = "http://docs.oasis-open.org/odata/ns/scheme";
+
+ private static final Logger log = LoggerFactory.getLogger(ODataXmlSerializer.class);
+
+ @Override
+ public SerializerResult serviceDocument(final ServiceMetadata metadata, final String serviceRoot)
+ throws SerializerException {
+ CircleStreamBuffer buffer;
+ XMLStreamWriter xmlStreamWriter = null;
+
+ try {
+ buffer = new CircleStreamBuffer();
+ xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(),
+ DEFAULT_CHARSET);
+ ServiceDocumentXmlSerializer serializer = new ServiceDocumentXmlSerializer(metadata, serviceRoot);
+ serializer.writeServiceDocument(xmlStreamWriter);
+ xmlStreamWriter.flush();
+ xmlStreamWriter.close();
+
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ log.error(e.getMessage(), e);
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ } finally {
+ if (xmlStreamWriter != null) {
+ try {
+ xmlStreamWriter.close();
+ } catch (XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+ }
+ }
+
+ @Override
+ public SerializerResult metadataDocument(final ServiceMetadata serviceMetadata) throws SerializerException {
+ CircleStreamBuffer buffer;
+ XMLStreamWriter xmlStreamWriter = null;
+
+ try {
+ buffer = new CircleStreamBuffer();
+ xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(),
+ DEFAULT_CHARSET);
+ MetadataDocumentXmlSerializer serializer = new MetadataDocumentXmlSerializer(serviceMetadata);
+ serializer.writeMetadataDocument(xmlStreamWriter);
+ xmlStreamWriter.flush();
+ xmlStreamWriter.close();
+
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ log.error(e.getMessage(), e);
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ } finally {
+ if (xmlStreamWriter != null) {
+ try {
+ xmlStreamWriter.close();
+ } catch (XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+ }
+ }
+
+ @Override
+ public SerializerResult error(final ODataServerError error) throws SerializerException {
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+
+ if (error == null) {
+ throw new SerializerException("ODataError object MUST NOT be null!",
+ SerializerException.MessageKeys.NULL_INPUT);
+ }
+
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(),
+ DEFAULT_CHARSET);
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+
+ writer.writeStartElement("error");
+ writer.writeDefaultNamespace(NS_METADATA);
+ writeErrorDetails(String.valueOf(error.getStatusCode()), error.getMessage(), error.getTarget(), writer);
+ if (error.getDetails() != null && !error.getDetails().isEmpty()) {
+ writer.writeStartElement("details");
+ for (ODataErrorDetail inner:error.getDetails()) {
+ writeErrorDetails(inner.getCode(), inner.getMessage(), inner.getTarget(), writer);
+ }
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+ writer.writeEndDocument();
+
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ private void writeErrorDetails(String code, String message, String target, XMLStreamWriter writer)
+ throws XMLStreamException {
+ if (code != null) {
+ writer.writeStartElement("code");
+ writer.writeCharacters(String.valueOf(code));
+ writer.writeEndElement();
+ }
+
+ writer.writeStartElement("message");
+ writer.writeCharacters(message);
+ writer.writeEndElement();
+
+ if (target != null) {
+ writer.writeStartElement("target");
+ writer.writeCharacters(target);
+ writer.writeEndElement();
+ }
+ }
+
+ @Override
+ public SerializerResult entityCollection(final ServiceMetadata metadata,
+ final EdmEntityType entityType, final EntityCollection entitySet,
+ final EntityCollectionSerializerOptions options) throws SerializerException {
+
+ final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+ if (options.onlyReferences()) {
+ ReferenceCollectionSerializerOptions rso = ReferenceCollectionSerializerOptions.with()
+ .contextURL(contextURL).build();
+ return entityReferenceCollection(metadata, entityType, entitySet, rso);
+ }
+
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writer.writeStartElement(ATOM, "feed", NS_ATOM);
+ writer.writeNamespace(ATOM, NS_ATOM);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ writer.writeNamespace(DATA, NS_DATA);
+
+ writer.writeAttribute(METADATA, NS_METADATA, "context",
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ writeMetadataETag(metadata, writer);
+
+ writer.writeStartElement(ATOM, "id", NS_ATOM);
+ writer.writeCharacters(options.getId());
+ writer.writeEndElement();
+
+ if (options != null && options.getCount() != null && options.getCount().getValue()
+ && entitySet.getCount() != null) {
+ writeCount(entitySet, writer);
+ }
+ if (entitySet.getNext() != null) {
+ writeNextLink(entitySet, writer);
+ }
+
+ writeEntitySet(metadata, entityType, entitySet,
+ options.getExpand(), options.getSelect(), options.onlyReferences(), writer);
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ @Override
+ public SerializerResult entity(final ServiceMetadata metadata, final EdmEntityType entityType,
+ final Entity entity, final EntitySerializerOptions options) throws SerializerException {
+ final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+
+ if (options.onlyReferences()) {
+ ReferenceSerializerOptions rso = ReferenceSerializerOptions.with()
+ .contextURL(contextURL).build();
+ return entityReference(metadata, entityType, entity, rso);
+ }
+
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writeEntity(metadata, entityType, entity, contextURL,
+ options == null ? null : options.getExpand(),
+ options == null ? null : options.getSelect(),
+ options == null ? false : options.onlyReferences(), writer, true);
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ private ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException {
+ if (contextURL == null) {
+ throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL);
+ }
+ return contextURL;
+ }
+
+ private void writeMetadataETag(final ServiceMetadata metadata, XMLStreamWriter writer)
+ throws XMLStreamException {
+ if (metadata != null
+ && metadata.getServiceMetadataETagSupport() != null
+ && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) {
+ writer.writeAttribute(METADATA, NS_METADATA, "metadata-etag",
+ metadata.getServiceMetadataETagSupport().getMetadataETag());
+ }
+ }
+
+ protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
+ final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
+ final boolean onlyReference, final XMLStreamWriter writer) throws XMLStreamException,
+ SerializerException {
+ for (final Entity entity : entitySet.getEntities()) {
+ writeEntity(metadata, entityType, entity, null, expand, select, false, writer, false);
+ }
+ }
+
+ protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
+ final Entity entity, final ContextURL contextURL, final ExpandOption expand,
+ final SelectOption select, final boolean onlyReference, final XMLStreamWriter writer,
+ final boolean top) throws XMLStreamException, SerializerException {
+
+ writer.writeStartElement(ATOM, "entry", NS_ATOM);
+ if (top) {
+ writer.writeNamespace(ATOM, NS_ATOM);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ writer.writeNamespace(DATA, NS_DATA);
+
+ if (contextURL != null) { // top-level entity
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ writeMetadataETag(metadata, writer);
+
+ }
+ }
+ if (entity.getETag() != null) {
+ writer.writeAttribute(METADATA, NS_METADATA, "etag", entity.getETag());
+ }
+
+ writer.writeStartElement(NS_ATOM, "id");
+ writer.writeCharacters(entity.getId().toASCIIString());
+ writer.writeEndElement();
+
+ writerAuthorInfo(entity.getTitle(), writer);
+
+ writer.writeStartElement(NS_ATOM, "link");
+ writer.writeAttribute("rel", "edit");
+ writer.writeAttribute("href", entity.getId().toASCIIString());
+ writer.writeEndElement();
+
+ if (entityType.hasStream()) {
+ writer.writeStartElement(NS_ATOM, "content");
+ writer.writeAttribute("type", entity.getMediaContentType());
+ if (entity.getMediaContentSource() != null) {
+ writer.writeAttribute("src", entity.getMediaContentSource().toString());
+ } else {
+ String id = entity.getId().toASCIIString();
+ if (id.endsWith("/")) {
+ writer.writeAttribute("src", id+"$value");
+ } else {
+ writer.writeAttribute("src", id+"/$value");
+ }
+ }
+ writer.writeEndElement();
+ }
+
+ // write media links
+ for (Link link:entity.getMediaEditLinks()) {
+ writeLink(writer, link);
+ }
+
+ EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
+ writeNavigationProperties(metadata, resolvedType, entity, expand, writer);
+
+ writer.writeStartElement(ATOM, "category", NS_ATOM);
+ writer.writeAttribute("scheme", NS_SCHEMA);
+ writer.writeAttribute("term", "#"+resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
+ writer.writeEndElement();
+
+ // In the case media, content is sibiling
+ if (!entityType.hasStream()) {
+ writer.writeStartElement(NS_ATOM, "content");
+ writer.writeAttribute("type", "application/xml");
+ }
+
+ writer.writeStartElement(METADATA, "properties", NS_METADATA);
+ writeProperties(metadata, resolvedType, entity.getProperties(), select, writer);
+ writer.writeEndElement(); // properties
+
+ if (!entityType.hasStream()) { // content
+ writer.writeEndElement();
+ }
+ writer.writeEndElement(); //entry
+ }
+
+ private void writerAuthorInfo(final String title, final XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeStartElement(NS_ATOM, "title");
+ if (title != null) {
+ writer.writeCharacters(title);
+ }
+ writer.writeEndElement();
+ writer.writeStartElement(NS_ATOM, "summary");
+ writer.writeEndElement();
+
+ writer.writeStartElement(NS_ATOM, "updated");
+ writer.writeCharacters(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+ .format(new Date(System.currentTimeMillis())));
+ writer.writeEndElement();
+
+ writer.writeStartElement(NS_ATOM, "author");
+ writer.writeStartElement(NS_ATOM, "name");
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+
+ protected EdmEntityType resolveEntityType(final ServiceMetadata metadata, final EdmEntityType baseType,
+ final String derivedTypeName) throws SerializerException {
+ if (derivedTypeName == null ||
+ baseType.getFullQualifiedName().getFullQualifiedNameAsString().equals(derivedTypeName)) {
+ return baseType;
+ }
+ EdmEntityType derivedType = metadata.getEdm().getEntityType(new FullQualifiedName(derivedTypeName));
+ if (derivedType == null) {
+ throw new SerializerException("EntityType not found",
+ SerializerException.MessageKeys.UNKNOWN_TYPE, derivedTypeName);
+ }
+ EdmEntityType type = derivedType.getBaseType();
+ while (type != null) {
+ if (type.getFullQualifiedName().getFullQualifiedNameAsString()
+ .equals(baseType.getFullQualifiedName().getFullQualifiedNameAsString())) {
+ return derivedType;
+ }
+ type = type.getBaseType();
+ }
+ throw new SerializerException("Wrong base type",
+ SerializerException.MessageKeys.WRONG_BASE_TYPE, derivedTypeName, baseType
+ .getFullQualifiedName().getFullQualifiedNameAsString());
+ }
+
+ protected EdmComplexType resolveComplexType(final ServiceMetadata metadata, final EdmComplexType baseType,
+ final String derivedTypeName) throws SerializerException {
+ if (derivedTypeName == null ||
+ baseType.getFullQualifiedName().getFullQualifiedNameAsString().equals(derivedTypeName)) {
+ return baseType;
+ }
+ EdmComplexType derivedType = metadata.getEdm().getComplexType(new FullQualifiedName(derivedTypeName));
+ if (derivedType == null) {
+ throw new SerializerException("Complex Type not found",
+ SerializerException.MessageKeys.UNKNOWN_TYPE, derivedTypeName);
+ }
+ EdmComplexType type = derivedType.getBaseType();
+ while (type != null) {
+ if (type.getFullQualifiedName().getFullQualifiedNameAsString()
+ .equals(baseType.getFullQualifiedName().getFullQualifiedNameAsString())) {
+ return derivedType;
+ }
+ type = type.getBaseType();
+ }
+ throw new SerializerException("Wrong base type",
+ SerializerException.MessageKeys.WRONG_BASE_TYPE, derivedTypeName, baseType
+ .getFullQualifiedName().getFullQualifiedNameAsString());
+ }
+
+ protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
+ final List<Property> properties, final SelectOption select, final XMLStreamWriter writer)
+ throws XMLStreamException, SerializerException {
+ final boolean all = ExpandSelectHelper.isAll(select);
+ final Set<String> selected = all ? null :
+ ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
+ for (final String propertyName : type.getPropertyNames()) {
+ if (all || selected.contains(propertyName)) {
+ final EdmProperty edmProperty = type.getStructuralProperty(propertyName);
+ final Property property = findProperty(propertyName, properties);
+ final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null :
+ ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName);
+ writeProperty(metadata, edmProperty, property, selectedPaths, writer);
+ }
+ }
+ }
+
+ protected void writeNavigationProperties(final ServiceMetadata metadata,
+ final EdmStructuredType type, final Linked linked, final ExpandOption expand,
+ final XMLStreamWriter writer) throws SerializerException, XMLStreamException {
+ if (ExpandSelectHelper.hasExpand(expand)) {
+ final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
+ final Set<String> expanded = expandAll ? null :
+ ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
+ for (final String propertyName : type.getNavigationPropertyNames()) {
+ final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
+ final Link navigationLink = getOrCreateLink(linked, propertyName);
+ if (expandAll || expanded.contains(propertyName)) {
+ final ExpandItem innerOptions = expandAll ? null :
+ ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
+ if (innerOptions != null && innerOptions.getLevelsOption() != null) {
+ throw new SerializerException("Expand option $levels is not supported.",
+ SerializerException.MessageKeys.NOT_IMPLEMENTED);
+ }
+ if (navigationLink != null) {
+ writeLink(writer, navigationLink, false);
+ writer.writeStartElement(METADATA, "inline", NS_METADATA);
+ writeExpandedNavigationProperty(metadata, property, navigationLink,
+ innerOptions == null ? null : innerOptions.getExpandOption(),
+ innerOptions == null ? null : innerOptions.getSelectOption(),
+ innerOptions == null ? false: innerOptions.isRef(),
+ writer);
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ } else {
+ writeLink(writer, getOrCreateLink(linked, propertyName));
+ }
+ }
+ } else {
+ for (final String propertyName : type.getNavigationPropertyNames()) {
+ writeLink(writer, getOrCreateLink(linked, propertyName));
+ }
+ }
+ for (Link link:linked.getAssociationLinks()) {
+ writeLink(writer, link);
+ }
+ }
+
+ protected Link getOrCreateLink(final Linked linked, final String navigationPropertyName)
+ throws XMLStreamException {
+ Link link = linked.getNavigationLink(navigationPropertyName);
+ if (link == null) {
+ link = new Link();
+ link.setRel("http://docs.oasis-open.org/odata/ns/related/"+navigationPropertyName);
+ link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
+ link.setTitle(navigationPropertyName);
+ EntityCollection target = new EntityCollection();
+ link.setInlineEntitySet(target);
+ link.setHref(linked.getId().toASCIIString()+"/"+navigationPropertyName);
+ }
+ return link;
+ }
+
+ private void writeLink(final XMLStreamWriter writer, final Link link) throws XMLStreamException {
+ writeLink(writer, link, true);
+ }
+ private void writeLink(final XMLStreamWriter writer, final Link link, final boolean close)
+ throws XMLStreamException {
+ writer.writeStartElement(ATOM, "link", NS_ATOM);
+ writer.writeAttribute("rel", link.getRel());
+ if (link.getType() != null) {
+ writer.writeAttribute("type", link.getType());
+ }
+ if (link.getTitle() != null) {
+ writer.writeAttribute("title", link.getTitle());
+ }
+ writer.writeAttribute("href", link.getHref());
+ if (close) {
+ writer.writeEndElement();
+ }
+ }
+
+ protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
+ final EdmNavigationProperty property, final Link navigationLink,
+ final ExpandOption innerExpand, final SelectOption innerSelect, boolean onlyReference,
+ final XMLStreamWriter writer)
+ throws XMLStreamException, SerializerException {
+ if (property.isCollection()) {
+ if (navigationLink == null || navigationLink.getInlineEntitySet() == null) {
+ // nothing to write.
+ } else {
+ writer.writeStartElement(ATOM, "feed", NS_ATOM);
+ writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
+ innerSelect, onlyReference, writer);
+ writer.writeEndElement();
+ }
+ } else {
+ if (navigationLink == null || navigationLink.getInlineEntity() == null) {
+ // nothing to write
+ } else {
+ writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
+ innerExpand, innerSelect, onlyReference, writer, false);
+ }
+ }
+ }
+
+ protected void writeProperty(final ServiceMetadata metadata, final EdmProperty edmProperty,
+ final Property property,
+ final Set<List<String>> selectedPaths, final XMLStreamWriter writer) throws XMLStreamException,
+ SerializerException {
+ writer.writeStartElement(DATA, edmProperty.getName(), NS_DATA);
+ if (property == null || property.isNull()) {
+ if (edmProperty.isNullable() == Boolean.FALSE) {
+ throw new SerializerException("Non-nullable property not present!",
+ SerializerException.MessageKeys.MISSING_PROPERTY, edmProperty.getName());
+ } else {
+ writer.writeAttribute(METADATA, NS_METADATA, "null", "true");
+ }
+ } else {
+ writePropertyValue(metadata, edmProperty, property, selectedPaths, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ private String collectionType(EdmType type) {
+ return "#Collection("+type.getFullQualifiedName().getFullQualifiedNameAsString()+")";
+ }
+
+ private String complexType(ServiceMetadata metadata, EdmComplexType baseType, String definedType)
+ throws SerializerException {
+ EdmComplexType type = resolveComplexType(metadata, baseType, definedType);
+ return type.getFullQualifiedName().getFullQualifiedNameAsString();
+ }
+
+ private String derivedComplexType(ServiceMetadata metadata, EdmComplexType baseType, String definedType)
+ throws SerializerException {
+ String derived = baseType.getFullQualifiedName().getFullQualifiedNameAsString();
+ if (derived.equals(definedType)) {
+ return null;
+ }
+ return definedType;
+ }
+
+ private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
+ final Property property, final Set<List<String>> selectedPaths,
+ final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
+ try {
+ if (edmProperty.isPrimitive()) {
+ if (edmProperty.isCollection()) {
+ writer.writeAttribute(METADATA, NS_METADATA, "type", "#Collection("+edmProperty.getType().getName()+")");
+ writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
+ edmProperty.isNullable(), edmProperty.getMaxLength(),
+ edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
+ writer);
+ } else {
+ writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
+ edmProperty.isNullable(), edmProperty.getMaxLength(),
+ edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
+ writer);
+ }
+ } else if (edmProperty.isCollection()) {
+ writer.writeAttribute(METADATA, NS_METADATA, "type", collectionType(edmProperty.getType()));
+ writeComplexCollection(metadata, (EdmComplexType) edmProperty.getType(), property, selectedPaths, writer);
+ } else if (property.isComplex()) {
+ writer.writeAttribute(METADATA, NS_METADATA, "type",
+ "#"+complexType(metadata, (EdmComplexType) edmProperty.getType(), property.getType()));
+ writeComplexValue(metadata, (EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
+ selectedPaths, writer);
+ } else if (property.isEnum()) {
+ writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
+ edmProperty.isNullable(), edmProperty.getMaxLength(),
+ edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
+ writer);
+ } else {
+ throw new SerializerException("Property type not yet supported!",
+ SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
+ }
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new SerializerException("Wrong value for property!", e,
+ SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+ edmProperty.getName(), property.getValue().toString());
+ }
+ }
+
+ private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
+ final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
+ final Boolean isUnicode,
+ final XMLStreamWriter writer) throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
+ for (Object value : property.asCollection()) {
+ writer.writeStartElement(METADATA, "element", NS_METADATA);
+ switch (property.getValueType()) {
+ case COLLECTION_PRIMITIVE:
+ case COLLECTION_ENUM:
+ writePrimitiveValue(type, value, isNullable, maxLength, precision, scale, isUnicode, writer);
+ break;
+ case COLLECTION_GEOSPATIAL:
+ throw new SerializerException("Property type not yet supported!",
+ SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
+ default:
+ throw new SerializerException("Property type not yet supported!",
+ SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
+ }
+ writer.writeEndElement();
+ }
+ }
+
+ private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type,
+ final Property property, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
+ throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
+ for (Object value : property.asCollection()) {
+ writer.writeStartElement(METADATA, "element", NS_METADATA);
+ if (derivedComplexType(metadata, type, property.getType()) != null) {
+ writer.writeAttribute(METADATA, NS_METADATA, "type", property.getType());
+ }
+ switch (property.getValueType()) {
+ case COLLECTION_COMPLEX:
+ writeComplexValue(metadata, type, ((ComplexValue) value).getValue(), selectedPaths, writer);
+ break;
+ default:
+ throw new SerializerException("Property type not yet supported!",
+ SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
+ }
+ writer.writeEndElement();
+ }
+ }
+
+ private void writePrimitive(final EdmPrimitiveType type, final Property property,
+ final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
+ final Boolean isUnicode, final XMLStreamWriter writer)
+ throws EdmPrimitiveTypeException, XMLStreamException, SerializerException {
+ if (property.isPrimitive()) {
+ if (!(type instanceof EdmString)) {
+ writer.writeAttribute(METADATA, NS_METADATA, "type", type.getName());
+ }
+ writePrimitiveValue(type, property.asPrimitive(),
+ isNullable, maxLength, precision, scale, isUnicode, writer);
+ } else if (property.isGeospatial()) {
+ throw new SerializerException("Property type not yet supported!",
+ SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
+ } else if (property.isEnum()) {
+ writer.writeAttribute(METADATA, NS_METADATA, "type", "#"+type.getName());
+ writePrimitiveValue(type, property.asEnum(),
+ isNullable, maxLength, precision, scale, isUnicode, writer);
+ } else {
+ throw new SerializerException("Inconsistent property type!",
+ SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
+ }
+ }
+
+ protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue,
+ final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
+ final Boolean isUnicode,
+ final XMLStreamWriter writer) throws EdmPrimitiveTypeException, XMLStreamException {
+ final String value = type.valueToString(primitiveValue,
+ isNullable, maxLength, precision, scale, isUnicode);
+ if (value == null) {
+ writer.writeAttribute(DATA, NS_DATA, "null", "true");
+ } else if(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
+ writer.writeCharacters(value);
+ } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int16)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int32)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte)
+ || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Single)) {
+ writer.writeCharacters(value);
+ } else {
+ writer.writeCharacters(value);
+ }
+ }
+
+ protected void writeComplexValue(final ServiceMetadata metadata, final EdmComplexType type,
+ final List<Property> properties, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
+ throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
+ for (final String propertyName : type.getPropertyNames()) {
+ final Property property = findProperty(propertyName, properties);
+ if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
+ writeProperty(metadata, (EdmProperty) type.getProperty(propertyName), property,
+ selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
+ writer);
+ }
+ }
+ }
+
+ private Property findProperty(final String propertyName, final List<Property> properties) {
+ for (final Property property : properties) {
+ if (propertyName.equals(property.getName())) {
+ return property;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public SerializerResult primitive(final ServiceMetadata metadata, final EdmPrimitiveType type,
+ final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
+ final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writer.writeStartElement(METADATA, "value", NS_METADATA);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ if (contextURL != null) {
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ }
+ writeMetadataETag(metadata, writer);
+ if(property.isNull()) {
+ writer.writeAttribute(METADATA, NS_METADATA, "null", "true");
+ } else {
+ writePrimitive(type, property,
+ options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(),
+ options.isUnicode(),
+ writer);
+ }
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new SerializerException("Wrong value for property!", e,
+ SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+ property.getName(), property.getValue().toString());
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (XMLStreamException e) {
+ throw new SerializerException("Wrong value for property!", e,
+ SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+ property.getName(), property.getValue().toString());
+ }
+ }
+ }
+ }
+
+ @Override
+ public SerializerResult complex(final ServiceMetadata metadata, final EdmComplexType type,
+ final Property property, final ComplexSerializerOptions options) throws SerializerException {
+ final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+ try {
+ EdmComplexType resolvedType = resolveComplexType(metadata, type, property.getType());
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writer.writeStartElement(METADATA, "value", NS_METADATA);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ writer.writeNamespace(DATA, NS_DATA);
+ writer.writeAttribute(METADATA, NS_METADATA, "type", "#"
+ + resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ writeMetadataETag(metadata, writer);
+ if (property.isNull()) {
+ writer.writeAttribute(METADATA, NS_METADATA, "null", "true");
+ } else {
+ final List<Property> values = property.asComplex().getValue();
+ writeProperties(metadata, resolvedType, values, options == null ? null : options.getSelect(), writer);
+ }
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ @Override
+ public SerializerResult primitiveCollection(final ServiceMetadata metadata, final EdmPrimitiveType type,
+ final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
+ final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writer.writeStartElement(METADATA, "value", NS_METADATA);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ if (contextURL != null) {
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ }
+ writeMetadataETag(metadata, writer);
+ writer.writeAttribute(METADATA, NS_METADATA, "type", "#Collection("+type.getName()+")");
+ writePrimitiveCollection(type, property,
+ options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(),
+ options.isUnicode(),
+ writer);
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new SerializerException("Wrong value for property!", e,
+ SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+ property.getName(), property.getValue().toString());
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (XMLStreamException e) {
+ throw new SerializerException("Wrong value for property!", e,
+ SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+ property.getName(), property.getValue().toString());
+ }
+ }
+ }
+ }
+
+ @Override
+ public SerializerResult complexCollection(final ServiceMetadata metadata, final EdmComplexType type,
+ final Property property, final ComplexSerializerOptions options) throws SerializerException {
+ final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+
+ writer.writeStartElement(METADATA, "value", NS_METADATA);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ writer.writeNamespace(DATA, NS_DATA);
+ writer.writeAttribute(METADATA, NS_METADATA, "type", collectionType(type));
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ writeMetadataETag(metadata, writer);
+ writeComplexCollection(metadata, type, property, null, writer);
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new SerializerException("Wrong value for property!", e,
+ SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+ property.getName(), property.getValue().toString());
+ }
+ }
+
+ @Override
+ public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
+ final Entity entity, final ReferenceSerializerOptions options) throws SerializerException {
+ return entityReference(metadata, edmEntitySet.getEntityType(), entity, options);
+ }
+
+ protected SerializerResult entityReference(final ServiceMetadata metadata, final EdmEntityType entityType,
+ final Entity entity, ReferenceSerializerOptions options) throws SerializerException {
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writeReference(metadata, entityType, entity, options.getContextURL(), writer, true);
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ private void writeReference(ServiceMetadata metadata, EdmEntityType entityType,
+ Entity entity, ContextURL contextURL, XMLStreamWriter writer, boolean top) throws XMLStreamException {
+ writer.writeStartElement(METADATA, "ref", NS_METADATA);
+ if (top) {
+ writer.writeNamespace(METADATA, NS_METADATA);
+ if (contextURL != null) { // top-level entity
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
+ ContextURLBuilder.create(contextURL).toASCIIString());
+ }
+ }
+ writer.writeAttribute("id", entity.getId().toASCIIString());
+ writer.writeEndElement();
+ }
+
+ @Override
+ public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
+ final EntityCollection entityCollection, ReferenceCollectionSerializerOptions options)
+ throws SerializerException {
+ return entityReferenceCollection(metadata, edmEntitySet.getEntityType(), entityCollection, options);
+ }
+
+ protected SerializerResult entityReferenceCollection(final ServiceMetadata metadata,
+ final EdmEntityType entityType, final EntityCollection entitySet,
+ ReferenceCollectionSerializerOptions options) throws SerializerException {
+ CircleStreamBuffer buffer;
+ XMLStreamWriter writer = null;
+ try {
+ buffer = new CircleStreamBuffer();
+ writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writer.writeStartElement(ATOM, "feed", NS_ATOM);
+ writer.writeNamespace(ATOM, NS_ATOM);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ if (options.getContextURL() != null) { // top-level entity
+ writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, ContextURLBuilder.create(options.getContextURL())
+ .toASCIIString());
+ }
+ if (options != null && options.getCount() != null && options.getCount().getValue()
+ && entitySet.getCount() != null) {
+ writeCount(entitySet, writer);
+ }
+ if (entitySet.getNext() != null) {
+ writeNextLink(entitySet, writer);
+ }
+ for (final Entity entity : entitySet.getEntities()) {
+ writeReference(metadata, entityType, entity, options.getContextURL(), writer, false);
+ }
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ writer.close();
+ return SerializerResultImpl.with().content(buffer.getInputStream()).build();
+ } catch (final XMLStreamException e) {
+ throw new SerializerException("An I/O exception occurred.", e,
+ SerializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ private void writeCount(final EntityCollection entitySet, XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement(METADATA, "count", NS_METADATA);
+ writer.writeCharacters(String.valueOf(entitySet.getCount()));
+ writer.writeEndElement();
+ }
+
+ private void writeNextLink(final EntityCollection entitySet, XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement(ATOM, "link", NS_ATOM);
+ writer.writeAttribute("rel", "next");
+ writer.writeAttribute("href", entitySet.getNext().toASCIIString());
+ writer.writeEndElement();
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java
deleted file mode 100644
index 1e7349b..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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 javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.data.EntityCollection;
-import org.apache.olingo.commons.api.data.Property;
-import org.apache.olingo.commons.api.edm.EdmComplexType;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
-import org.apache.olingo.server.api.ODataServerError;
-import org.apache.olingo.server.api.ServiceMetadata;
-import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
-import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
-import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
-import org.apache.olingo.server.api.serializer.ODataSerializer;
-import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
-import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
-import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
-import org.apache.olingo.server.api.serializer.SerializerException;
-import org.apache.olingo.server.api.serializer.SerializerResult;
-import org.apache.olingo.server.core.serializer.SerializerResultImpl;
-import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ODataXmlSerializerImpl implements ODataSerializer {
-
- /** The default character set is UTF-8. */
- public static final String DEFAULT_CHARSET = "UTF-8";
-
- private static final Logger log = LoggerFactory.getLogger(ODataXmlSerializerImpl.class);
-
- @Override
- public SerializerResultImpl serviceDocument(final ServiceMetadata metadata, final String serviceRoot)
- throws SerializerException {
- throw new SerializerException("Service Document not implemented for XML format",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult metadataDocument(final ServiceMetadata serviceMetadata) throws SerializerException {
- CircleStreamBuffer buffer;
- XMLStreamWriter xmlStreamWriter = null;
-
- try {
- buffer = new CircleStreamBuffer();
- xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET);
- MetadataDocumentXmlSerializer serializer = new MetadataDocumentXmlSerializer(serviceMetadata);
- serializer.writeMetadataDocument(xmlStreamWriter);
- xmlStreamWriter.flush();
- xmlStreamWriter.close();
-
- return SerializerResultImpl.with().content(buffer.getInputStream()).build();
- } catch (final XMLStreamException e) {
- log.error(e.getMessage(), e);
- throw new SerializerException("An I/O exception occurred.", e,
- SerializerException.MessageKeys.IO_EXCEPTION);
- } finally {
- if (xmlStreamWriter != null) {
- try {
- xmlStreamWriter.close();
- } catch (XMLStreamException e) {
- throw new SerializerException("An I/O exception occurred.", e,
- SerializerException.MessageKeys.IO_EXCEPTION);
- }
- }
- }
- }
-
- @Override
- public SerializerResult entity(final ServiceMetadata metadata, final EdmEntityType entityType,
- final Entity entity, final EntitySerializerOptions options) throws SerializerException {
- throw new SerializerException("Entity serialization not implemented for XML format",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult entityCollection(final ServiceMetadata metadata,
- final EdmEntityType entityType, final EntityCollection entitySet,
- final EntityCollectionSerializerOptions options) throws SerializerException {
- throw new SerializerException("Entityset serialization not implemented for XML format",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult error(final ODataServerError error) throws SerializerException {
- throw new SerializerException("error serialization not implemented for XML format",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult primitive(final ServiceMetadata metadata, final EdmPrimitiveType type,
- final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
- throw new SerializerException("Serialization not implemented for XML format.",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult complex(final ServiceMetadata metadata, final EdmComplexType type,
- final Property property, final ComplexSerializerOptions options) throws SerializerException {
- throw new SerializerException("Serialization not implemented for XML format.",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult primitiveCollection(final ServiceMetadata metadata, final EdmPrimitiveType type,
- final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
- throw new SerializerException("Serialization not implemented for XML format.",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult complexCollection(final ServiceMetadata metadata, final EdmComplexType type,
- final Property property, final ComplexSerializerOptions options) throws SerializerException {
- throw new SerializerException("Serialization not implemented for XML format.",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntotySet,
- final Entity entity, final ReferenceSerializerOptions options) throws SerializerException {
- throw new SerializerException("Serialization not implemented for XML format.",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-
- @Override
- public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
- final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions optionsL)
- throws SerializerException {
- throw new SerializerException("Serialization not implemented for XML format.",
- SerializerException.MessageKeys.NOT_IMPLEMENTED);
- }
-}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializer.java
new file mode 100644
index 0000000..ed60f36
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializer.java
@@ -0,0 +1,143 @@
+/*
+ * 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 javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmFunctionImport;
+import org.apache.olingo.commons.api.edm.EdmSingleton;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+
+public class ServiceDocumentXmlSerializer {
+ public static final String KIND = "kind";
+
+ public static final String FUNCTION_IMPORT = "FunctionImport";
+ public static final String SINGLETON = "Singleton";
+ public static final String SERVICE_DOCUMENT = "ServiceDocument";
+
+ private static final String APP = "app";
+ private static final String NS_APP = "http://www.w3.org/2007/app";
+ private static final String ATOM = "atom";
+ private static final String NS_ATOM = "http://www.w3.org/2005/Atom";
+ private static final String METADATA = "metadata";
+ private static final String NS_METADATA = "http://docs.oasis-open.org/odata/ns/metadata";
+
+ private final ServiceMetadata metadata;
+ private final String serviceRoot;
+
+ public ServiceDocumentXmlSerializer(final ServiceMetadata metadata, final String serviceRoot) {
+ this.metadata = metadata;
+ this.serviceRoot = serviceRoot;
+ }
+
+ public void writeServiceDocument(final XMLStreamWriter writer) throws XMLStreamException {
+ final String metadataUri =
+ (serviceRoot == null ? "" : serviceRoot.endsWith("/") ? serviceRoot : (serviceRoot + "/"))
+ + Constants.METADATA;
+
+ writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
+ writer.writeStartElement(APP, "service", NS_APP);
+ writer.writeNamespace(ATOM, NS_ATOM);
+ writer.writeNamespace(APP, NS_APP);
+ writer.writeNamespace(METADATA, NS_METADATA);
+ writer.writeAttribute(METADATA, NS_METADATA, "context", metadataUri);
+
+ if (metadata != null
+ && metadata.getServiceMetadataETagSupport() != null
+ && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) {
+ writer.writeAttribute(METADATA, NS_METADATA, "metadata-etag",
+ metadata.getServiceMetadataETagSupport().getMetadataETag());
+ }
+
+ writer.writeStartElement(APP, "workspace", NS_APP);
+
+ final Edm edm = metadata.getEdm();
+
+ writer.writeStartElement(ATOM, "title", NS_APP);
+ writer.writeCharacters(edm.getEntityContainer(null).getFullQualifiedName().getFullQualifiedNameAsString());
+ writer.writeEndElement();
+
+ writeEntitySets(writer, edm);
+ writeFunctionImports(writer, edm);
+ writeSingletons(writer, edm);
+ writeServiceDocuments(writer);
+ writer.writeEndElement(); // end workspace
+ writer.writeEndElement(); // end service
+ }
+
+ private void writeServiceDocuments(XMLStreamWriter writer) throws XMLStreamException {
+
+ for (EdmxReference reference : this.metadata.getReferences()) {
+ writer.writeStartElement(METADATA , "service-document", NS_METADATA);
+ writer.writeAttribute("href", reference.getUri().toASCIIString());
+ writer.writeStartElement(ATOM, "title", NS_ATOM);
+ writer.writeCharacters(reference.getUri().toASCIIString());
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+
+ private void writeEntitySets(final XMLStreamWriter writer, final Edm edm) throws XMLStreamException {
+ EdmEntityContainer container = edm.getEntityContainer(null);
+ for (EdmEntitySet edmEntitySet : container.getEntitySets()) {
+ if (edmEntitySet.isIncludeInServiceDocument()) {
+ writer.writeStartElement(APP, "collection", NS_APP);
+ writer.writeAttribute("href", edmEntitySet.getName());
+ writer.writeStartElement(ATOM, "title", NS_ATOM);
+ writer.writeCharacters(edmEntitySet.getName());
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+ }
+
+ private void writeFunctionImports(final XMLStreamWriter writer, final Edm edm) throws XMLStreamException {
+ EdmEntityContainer container = edm.getEntityContainer(null);
+
+ for (EdmFunctionImport edmFunctionImport : container.getFunctionImports()) {
+ if (edmFunctionImport.isIncludeInServiceDocument()) {
+ writer.writeStartElement(METADATA, "function-import", NS_METADATA);
+ writer.writeAttribute("href", edmFunctionImport.getName());
+ writer.writeStartElement(ATOM, "title", NS_ATOM);
+ writer.writeCharacters(edmFunctionImport.getName());
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+ }
+
+ private void writeSingletons(final XMLStreamWriter writer, final Edm edm) throws XMLStreamException {
+ EdmEntityContainer container = edm.getEntityContainer(null);
+ for (EdmSingleton edmSingleton : container.getSingletons()) {
+ writer.writeStartElement(METADATA, "singleton", NS_METADATA);
+ writer.writeAttribute("href", edmSingleton.getName());
+ writer.writeStartElement(ATOM, "title", NS_ATOM);
+ writer.writeCharacters( edmSingleton.getName());
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
index d4af42a..0d17a5b 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
@@ -78,6 +78,8 @@ public class ContentNegotiatorTest {
{ ACCEPT_CASE_MIN_IEEE754, null, ACCEPT_CASE_MIN_IEEE754, null },
{ ACCEPT_CASE_MIN_UTF8_IEEE754, null, ACCEPT_CASE_MIN_UTF8_IEEE754, null },
{ ACCEPT_CASE_MIN_IEEE754, ACCEPT_CASE_MIN_IEEE754, ACCEPT_CASE_MIN , null },
+ { ACCEPT_CASE_XML, "xml", null, null },
+ { ACCEPT_CASE_XML, null, ACCEPT_CASE_XML, null }
};
String[][] casesMetadata = {
@@ -99,7 +101,6 @@ public class ContentNegotiatorTest {
{ null, "a/a", null, "b/b" },
{ null, "a/a;x=y", null, "a/a;v=w" },
{ null, null, "a/a;x=y", "a/a;v=w" },
- { null, "atom", null, null }, // not yet supported
{ null, null, ACCEPT_CASE_FULL, null }, // not yet supported
{ null, "a/b;charset=ISO-8859-1", null, "a/b" },
{ null, null, "a/b;charset=ISO-8859-1", "a/b" },
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
index 87a6554..3954a5a 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
@@ -50,8 +50,7 @@ public class ODataImplTest {
assertNotNull(odata.createDeserializer(ContentType.APPLICATION_JSON));
}
- @Test(expected = DeserializerException.class)
public void xmlDeserializer() throws DeserializerException {
- odata.createDeserializer(ContentType.APPLICATION_XML);
+ assertNotNull(odata.createDeserializer(ContentType.APPLICATION_XML));
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentXmlSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentXmlSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentXmlSerializerTest.java
index 4423308..9e9a04d 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentXmlSerializerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentXmlSerializerTest.java
@@ -45,6 +45,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlAliasInfo;
import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
import org.apache.olingo.commons.api.edm.provider.CsdlEnumMember;
@@ -73,7 +74,7 @@ import org.junit.Test;
public class MetadataDocumentXmlSerializerTest {
private static ODataSerializer serializer;
-
+
@BeforeClass
public static void init() throws SerializerException {
serializer = OData.newInstance().createSerializer(ContentType.APPLICATION_XML);
@@ -263,7 +264,7 @@ public class MetadataDocumentXmlSerializerTest {
+ "</ComplexType>"));
}
- private class LocalProvider extends CsdlAbstractEdmProvider {
+ static class LocalProvider extends CsdlAbstractEdmProvider {
private final static String nameSpace = "namespace";
private final FullQualifiedName nameETAbstract = new FullQualifiedName(nameSpace, "ETAbstract");
@@ -469,6 +470,15 @@ public class MetadataDocumentXmlSerializerTest {
}
@Override
+ public CsdlEntityContainerInfo getEntityContainerInfo(final FullQualifiedName entityContainerName)
+ throws ODataException {
+ if (entityContainerName == null) {
+ return new CsdlEntityContainerInfo().setContainerName(new FullQualifiedName("org.olingo", "container"));
+ }
+ return null;
+ }
+
+ @Override
public CsdlEntityContainer getEntityContainer() throws ODataException {
CsdlEntityContainer container = new CsdlEntityContainer();
container.setName("container");
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServerErrorXmlSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServerErrorXmlSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServerErrorXmlSerializerTest.java
new file mode 100644
index 0000000..6968b2b
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServerErrorXmlSerializerTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.ODataErrorDetail;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataServerError;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ServerErrorXmlSerializerTest {
+
+ ODataSerializer ser;
+
+ @Before
+ public void before() throws Exception {
+ ser = OData.newInstance().createSerializer(ContentType.APPLICATION_XML);
+ }
+
+ @Test
+ public void basicODataErrorWithCode() throws Exception {
+ ODataServerError error = new ODataServerError();
+ error.setCode("Code").setMessage("ErrorMessage");
+ InputStream stream = ser.error(error).getContent();
+ String jsonString = IOUtils.toString(stream);
+ assertEquals("<?xml version='1.0' encoding='UTF-8'?>"
+ + "<error xmlns=\"http://docs.oasis-open.org/odata/ns/metadata\">"
+ + "<code>0</code>"
+ + "<message>ErrorMessage</message>"
+ + "</error>",
+ jsonString);
+ }
+
+ @Test(expected = SerializerException.class)
+ public void nullErrorResultsInException() throws Exception {
+ ser.error(null);
+ }
+
+ @Test
+ public void singleDetailNothingSet() throws Exception {
+ ODataErrorDetail detail = new ODataErrorDetail();
+ detail.setCode("detail code");
+ detail.setMessage("detail message");
+
+ List<ODataErrorDetail> details = new ArrayList<ODataErrorDetail>();
+ details.add(detail);
+
+ ODataServerError error = new ODataServerError().setDetails(details);
+ error.setCode("code");
+ error.setMessage("err message");
+ error.setTarget("target");
+
+ InputStream stream = ser.error(error).getContent();
+ String jsonString = IOUtils.toString(stream);
+ assertEquals("<?xml version='1.0' encoding='UTF-8'?>"
+ + "<error xmlns=\"http://docs.oasis-open.org/odata/ns/metadata\">"
+ + "<code>0</code>"
+ + "<message>err message</message>"
+ + "<target>target</target>"
+ + "<details>"
+ + "<code>detail code</code>"
+ + "<message>detail message</message>"
+ + "</details>"
+ + "</error>",
+ jsonString);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializerTest.java
new file mode 100644
index 0000000..04bf11d
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/xml/ServiceDocumentXmlSerializerTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmFunctionImport;
+import org.apache.olingo.commons.api.edm.EdmSingleton;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ServiceMetadataImpl;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class ServiceDocumentXmlSerializerTest {
+ private static ODataSerializer serializer;
+
+ @BeforeClass
+ public static void init() throws SerializerException {
+ serializer = OData.newInstance().createSerializer(ContentType.APPLICATION_ATOM_XML);
+ }
+
+ @Test
+ public void writeServiceWithEmptyMockedEdm() throws Exception {
+ final Edm edm = mock(Edm.class);
+ EdmEntityContainer container = mock(EdmEntityContainer.class);
+ Mockito.stub(container.getFullQualifiedName()).toReturn(new FullQualifiedName("service.test"));
+ when(container.getEntitySets()).thenReturn(new ArrayList<EdmEntitySet>());
+ when(container.getFunctionImports()).thenReturn(new ArrayList<EdmFunctionImport>());
+ when(container.getSingletons()).thenReturn(new ArrayList<EdmSingleton>());
+ when(edm.getEntityContainer(null)).thenReturn(container);
+ ServiceMetadata metadata = mock(ServiceMetadata.class);
+ when(metadata.getEdm()).thenReturn(edm);
+
+ assertEquals("<?xml version='1.0' encoding='UTF-8'?>"
+ + "<app:service xmlns:atom=\"http://www.w3.org/2005/Atom\" "
+ + "xmlns:app=\"http://www.w3.org/2007/app\" "
+ + "xmlns:metadata=\"http://docs.oasis-open.org/odata/ns/metadata\" "
+ + "metadata:context=\"http://host/svc/$metadata\">"
+ + "<app:workspace><atom:title>service.test</atom:title></app:workspace>"
+ + "</app:service>",
+ IOUtils.toString(serializer.serviceDocument(metadata, "http://host/svc").getContent()));
+ }
+
+ @Test
+ public void writeServiceDocument() throws Exception {
+ CsdlEdmProvider provider = new MetadataDocumentXmlSerializerTest.LocalProvider();
+ ServiceMetadata serviceMetadata = new ServiceMetadataImpl(provider,
+ Collections.<EdmxReference> emptyList(), null);
+ InputStream metadataStream = serializer.serviceDocument(serviceMetadata, "http://host/svc").getContent();
+ String metadata = IOUtils.toString(metadataStream);
+ assertEquals("<?xml version='1.0' encoding='UTF-8'?>"
+ + "<app:service xmlns:atom=\"http://www.w3.org/2005/Atom\" "
+ + "xmlns:app=\"http://www.w3.org/2007/app\" "
+ + "xmlns:metadata=\"http://docs.oasis-open.org/odata/ns/metadata\" "
+ + "metadata:context=\"http://host/svc/$metadata\">"
+ + "<app:workspace>"
+ + "<atom:title>org.olingo.container</atom:title>"
+ + "<app:collection href=\"ESAllPrim\">"
+ + "<atom:title>ESAllPrim</atom:title>"
+ + "</app:collection>"
+ + "<metadata:function-import href=\"FINRTInt16\">"
+ + "<atom:title>FINRTInt16</atom:title>"
+ + "</metadata:function-import>"
+ + "<metadata:singleton href=\"SI\">"
+ + "<atom:title>SI</atom:title>"
+ + "</metadata:singleton>"
+ + "</app:workspace>"
+ + "</app:service>",
+ metadata);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
index 0b5922c..51a2c34 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
@@ -75,7 +75,7 @@ public class TechnicalServlet extends HttpServlet {
HttpSession session = request.getSession(true);
DataProvider dataProvider = (DataProvider) session.getAttribute(DataProvider.class.getName());
if (dataProvider == null) {
- dataProvider = new DataProvider();
+ dataProvider = new DataProvider(serviceMetadata.getEdm());
session.setAttribute(DataProvider.class.getName(), dataProvider);
LOG.info("Created new data provider.");
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
index 6d7a41f..65a56c7 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -36,7 +37,10 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
public class ActionData {
@@ -151,6 +155,9 @@ public class ActionData {
protected static EntityActionResult entityAction(final String name, final Map<String, Parameter> parameters)
throws DataProviderException {
+ final ServiceMetadata metadata = OData.newInstance().createServiceMetadata(new EdmTechProvider(),
+ Collections.<EdmxReference> emptyList(),null);
+
if ("UARTETTwoKeyTwoPrimParam".equals(name)) {
Parameter parameter = parameters.get("ParameterInt16");
Short number;
@@ -160,7 +167,7 @@ public class ActionData {
number = (short) 0;
}
- EntityCollection entityCollection = new DataCreator().getData().get("ESTwoKeyTwoPrim");
+ EntityCollection entityCollection = new DataCreator(metadata.getEdm()).getData().get("ESTwoKeyTwoPrim");
for (Entity entity : entityCollection.getEntities()) {
Object asPrimitive = entity.getProperty("PropertyInt16").asPrimitive();
if (number.equals(asPrimitive)) {
@@ -171,7 +178,7 @@ public class ActionData {
throw new DataProviderException("Entity not found with key: " + number, HttpStatusCode.NOT_FOUND);
} else if ("UARTETAllPrimParam".equals(name)) {
Parameter paramDate = parameters.get("ParameterDate");
- EntityCollection entityCollection = new DataCreator().getData().get("ESAllPrim");
+ EntityCollection entityCollection = new DataCreator(metadata.getEdm()).getData().get("ESAllPrim");
if (paramDate != null) {
Calendar date = (Calendar) paramDate.asPrimitive();
boolean freeKey;