You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ar...@apache.org on 2018/04/02 11:31:59 UTC
[18/24] olingo-odata2 git commit: [OLINGO-1253]Client Module for
Olingo v2
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java
new file mode 100644
index 0000000..53370bc
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.deserializer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.DeserializerProperties;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityTypeMapping;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * XML property consumer.
+ */
+public class XmlPropertyDeserializer {
+
+ protected static final String TRUE = "true";
+ protected static final String FALSE = "false";
+
+ /**
+ * Read property of every entry in a payload
+ * @param reader
+ * @param property
+ * @param readProperties
+ * @return Map<String, Object>
+ * @throws EntityProviderException
+ */
+ public Map<String, Object> readProperty(final XMLStreamReader reader, final EdmProperty property,
+ final DeserializerProperties readProperties) throws EntityProviderException {
+ return readProperty(reader, EntityInfoAggregator.create(property), readProperties);
+ }
+
+ /**
+ * Read property of every entry in a payload
+ * @param reader
+ * @param propertyInfo
+ * @param readProperties
+ * @return Map<String, Object>
+ * @throws EntityProviderException
+ */
+ public Map<String, Object> readProperty(final XMLStreamReader reader, final EntityPropertyInfo propertyInfo,
+ final DeserializerProperties readProperties) throws EntityProviderException {
+ final EntityTypeMapping typeMappings =
+ EntityTypeMapping.create(readProperties == null ? Collections.<String, Object> emptyMap() :
+ readProperties.getTypeMappings());
+ try {
+ reader.next();
+
+ Object value = readStartedElement(reader, propertyInfo.getName(), propertyInfo, typeMappings, readProperties);
+
+ Map<String, Object> result = new HashMap<String, Object>();
+ result.put(propertyInfo.getName(), value);
+ return result;
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ } catch (EdmException e) {
+ throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ }
+ }
+
+
+ /**
+ * Deserializes a collection of entities
+ * @param reader
+ * @param info
+ * @param properties
+ * @return List<Object>
+ * @throws EntityProviderException
+ */
+ public List<Object> readCollection(XMLStreamReader reader, final EntityPropertyInfo info,
+ final DeserializerProperties properties) throws EntityProviderException {
+ final String collectionName = info.getName();
+ final EntityTypeMapping typeMappings = EntityTypeMapping.create(
+ properties == null || !properties.getTypeMappings().containsKey(collectionName) ?
+ Collections.<String, Object> emptyMap() :
+ Collections.<String, Object> singletonMap(FormatXml.D_ELEMENT,
+ properties.getTypeMappings().get(collectionName)));
+ List<Object> result = new ArrayList<Object>();
+ try {
+ reader.nextTag();
+ reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, collectionName);
+ reader.nextTag();
+ while (reader.isStartElement()) {
+ result.add(readStartedElement(reader, FormatXml.D_ELEMENT, info, typeMappings, properties));
+ reader.nextTag();
+ }
+ reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, collectionName);
+ reader.next();
+ reader.require(XMLStreamConstants.END_DOCUMENT, null, null);
+ return result;
+ } catch (final XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED
+ .addContent(e.getClass().getSimpleName()), e);
+ } catch (final EdmException e) {
+ throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED
+ .addContent(e.getClass().getSimpleName()), e);
+ }
+ }
+
+ protected Object readStartedElement(XMLStreamReader reader, final String name, //NOSONAR
+ final EntityPropertyInfo propertyInfo,
+ final EntityTypeMapping typeMappings, final DeserializerProperties readProperties)
+ throws EntityProviderException, EdmException {
+ Object result = null;
+
+ try {
+ reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, name);
+ final String nullAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_NULL);
+
+ if (!(nullAttribute == null || TRUE.equals(nullAttribute) || FALSE.equals(nullAttribute))) {
+ throw new EntityProviderException(EntityProviderException.COMMON);
+ }
+
+ if (TRUE.equals(nullAttribute)) {
+ if ((readProperties == null || readProperties.isValidatingFacets()) && propertyInfo.isMandatory()) {
+ throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY_VALUE.addContent(name));
+ }
+ reader.nextTag();
+ } else if (propertyInfo.isComplex()) {
+ final String typeAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_TYPE);
+ if (typeAttribute != null) {
+ final String expectedTypeAttributeValue =
+ propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+ if (!expectedTypeAttributeValue.equals(typeAttribute)) { //NOSONAR
+ throw new EntityProviderException(EntityProviderException.INVALID_COMPLEX_TYPE.addContent(
+ expectedTypeAttributeValue).addContent(typeAttribute));
+ }
+ }
+
+ reader.nextTag();
+ Map<String, Object> name2Value = new HashMap<String, Object>();
+ while (reader.hasNext() && !reader.isEndElement()) {
+ final String childName = reader.getLocalName();
+ final EntityPropertyInfo childProperty =
+ ((EntityComplexPropertyInfo) propertyInfo).getPropertyInfo(childName);
+ if (childProperty == null) { //NOSONAR
+ throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(childName));
+ }
+ final Object value = readStartedElement(reader, childName, childProperty,
+ typeMappings.getEntityTypeMapping(name), readProperties);
+ name2Value.put(childName, value);
+ reader.nextTag();
+ }
+ result = name2Value;
+ } else {
+ result = convert(propertyInfo, reader.getElementText(), typeMappings.getMappingClass(name), readProperties);
+ }
+ reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, name);
+
+ return result;
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ }
+ }
+
+ private Object convert(final EntityPropertyInfo property, final String value, final Class<?> typeMapping,
+ final DeserializerProperties readProperties) throws EdmSimpleTypeException {
+ final EdmSimpleType type = (EdmSimpleType) property.getType();
+ return type.valueOfString(value, EdmLiteralKind.DEFAULT,
+ readProperties == null || readProperties.isValidatingFacets() ? property.getFacets() : null,
+ typeMapping == null ? type.getDefaultType() : typeMapping);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java
new file mode 100644
index 0000000..5881813
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java
@@ -0,0 +1,669 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.Map.Entry;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmCustomizableFeedMappings;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmTargetPath;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.commons.ContentType;
+import org.apache.olingo.odata2.core.commons.Encoder;
+import org.apache.olingo.odata2.core.edm.EdmDateTimeOffset;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Serializes an ATOM entry.
+ *
+ */
+public class AtomEntryEntitySerializer {
+ private final EntitySerializerProperties properties;
+ private static final String VALUE = "/$value";
+
+ /**
+ *
+ * @param properties
+ */
+ public AtomEntryEntitySerializer(final EntitySerializerProperties properties) {
+ this.properties = properties == null ? EntitySerializerProperties.serviceRoot(null).build() : properties;
+ }
+
+ /**
+ * This serializes the xml payload entry
+ * @param writer
+ * @param eia
+ * @param data
+ * @param isRootElement
+ * @param isFeedPart
+ * @throws EntityProviderException
+ */
+ public void append(final XMLStreamWriter writer, final EntityInfoAggregator eia, final Entity data,
+ final boolean isRootElement, final boolean isFeedPart) throws EntityProviderException {
+
+ try {
+ if (properties.getServiceRoot() == null) {
+ throw new EntityProviderProducerException(EntityProviderException.MANDATORY_WRITE_PROPERTY);
+ }
+ writer.writeStartElement(FormatXml.ATOM_ENTRY);
+
+ if (isRootElement) {
+ writer.writeDefaultNamespace(Edm.NAMESPACE_ATOM_2005);
+ writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+ writer.writeNamespace(Edm.PREFIX_D, Edm.NAMESPACE_D_2007_08);
+ }
+ if (!isFeedPart) {
+ writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_BASE, properties.getServiceRoot()
+ .toASCIIString());
+ }
+
+ String selfLink = null;
+ if (properties.isIncludeMetadata()) {
+ // write all atom infos (mandatory and optional)
+ selfLink = createSelfLink(eia, data.getProperties(), null, properties.isKeyAutoGenerated(), false);
+ appendAtomMandatoryParts(writer, eia, data.getProperties());
+ appendAtomOptionalParts(writer, eia, data.getProperties());
+ appendAtomEditLink(writer, eia, selfLink);
+ if (eia.getEntityType().hasStream()) {
+ appendAtomContentLink(writer, eia, data.getProperties(), selfLink);
+ }
+ }
+
+ appendNavigationLinks(writer, eia, data);
+ appendCustomProperties(writer, eia, data.getProperties());
+
+ if (eia.getEntityType().hasStream()) {
+ if (properties.isIncludeMetadata()) {
+ appendAtomContentPart(writer, eia, data.getProperties(), selfLink);
+ }
+ appendProperties(writer, eia, data.getProperties());
+ } else {
+ writer.writeStartElement(FormatXml.ATOM_CONTENT);
+ writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_XML.toString());
+ appendProperties(writer, eia, data.getProperties());
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+ writer.flush();
+
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ } catch (URISyntaxException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void appendNavigationLinks(final XMLStreamWriter writer, //NOSONAR
+ final EntityInfoAggregator eia,
+ final Entity data)
+ throws EntityProviderException, EdmException, URISyntaxException, XMLStreamException {
+
+ for (Entry<String, Object> entry : data.getNavigations().entrySet()) {
+ final EntityInfoAggregator targetEntityInfo = EntityInfoAggregator.create(
+ eia.getEntitySet().getRelatedEntitySet(
+ (EdmNavigationProperty) eia.getEntityType().getProperty(entry.getKey())));
+ final boolean isFeed =
+ (eia.getNavigationPropertyInfo(entry.getKey()).getMultiplicity() == EdmMultiplicity.MANY);
+ if (entry.getValue() == null) {
+ throw new EntityProviderProducerException(EntityProviderProducerException.NULL_VALUE);
+ } else if (entry.getValue() instanceof Map) {
+ Map<String, Object> navigationKeyMap = (Map<String, Object>) entry.getValue();
+ if (navigationKeyMap != null && !navigationKeyMap.isEmpty()) {
+ appendAtomNavigationLink(writer, createSelfLink(targetEntityInfo, navigationKeyMap, null,
+ properties.isKeyAutoGenerated(), false), entry.getKey(), isFeed);
+ writer.writeEndElement();
+ }
+ } else if (entry.getValue() instanceof Entity) {
+ Entity navigationEntity = (Entity) entry.getValue();
+ Map<String, Object> navigationKeyMap = navigationEntity.getProperties();
+ if (navigationKeyMap != null && !navigationKeyMap.isEmpty()) {
+ String navigationPropertyName = entry.getKey();
+ String selfLink = createSelfLink(eia, data.getProperties(), navigationPropertyName,
+ properties.isKeyAutoGenerated(), false);
+ appendNavigationLink(writer, selfLink, navigationPropertyName);
+
+ writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_ENTRY.toString());
+ appendInlineEntry(writer, navigationPropertyName, eia, data);
+ writer.writeEndElement();
+
+ }
+ } else if (entry.getValue() instanceof EntityCollection) {
+ String navigationPropertyName = entry.getKey();
+ String selfLink = createSelfLink(eia, data.getProperties(), navigationPropertyName,
+ properties.isKeyAutoGenerated(), false);
+ if (!((EntityCollection) entry.getValue()).getEntities().isEmpty()) {
+ appendNavigationLink(writer, selfLink, navigationPropertyName);
+
+ writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_FEED.toString());
+ appendInlineFeed(writer, navigationPropertyName, eia, data);
+ writer.writeEndElement();
+ }
+
+ } else{
+ throw new EntityProviderProducerException(EntityProviderProducerException.INCORRECT_NAVIGATION_TYPE);
+
+ }
+ }
+ }
+
+ private void appendNavigationLink(XMLStreamWriter writer, String selfLink, String navigationPropertyName)
+ throws XMLStreamException {
+
+ writer.writeStartElement(FormatXml.ATOM_LINK);
+ writer.writeAttribute(FormatXml.ATOM_HREF, selfLink);
+ writer.writeAttribute(FormatXml.ATOM_REL, Edm.NAMESPACE_REL_2007_08 + navigationPropertyName);
+ writer.writeAttribute(FormatXml.ATOM_TITLE, navigationPropertyName);
+ }
+
+ private void appendCustomProperties(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data) throws EntityProviderException {
+ List<String> noneSyndicationTargetPaths = eia.getNoneSyndicationTargetPathNames();
+ for (String tpName : noneSyndicationTargetPaths) {
+ EntityPropertyInfo info = eia.getTargetPathInfo(tpName);
+ final String name = info.getName();
+ XmlPropertyEntitySerializer aps = new XmlPropertyEntitySerializer(properties);
+ aps.appendCustomProperty(writer, name, info, data.get(name));
+ }
+ }
+
+ private void appendAtomNavigationLink(final XMLStreamWriter writer, final String target,
+ final String navigationPropertyName, final boolean isFeed)
+ throws EntityProviderException, EdmException, URISyntaxException { //NOSONAR
+ try {
+ writer.writeStartElement(FormatXml.ATOM_LINK);
+ writer.writeAttribute(FormatXml.ATOM_HREF, target);
+ writer.writeAttribute(FormatXml.ATOM_REL, Edm.NAMESPACE_REL_2007_08 + navigationPropertyName);
+ writer.writeAttribute(FormatXml.ATOM_TITLE, navigationPropertyName);
+ if (isFeed) {
+ writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_FEED.toString());
+ } else {
+ writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_ENTRY.toString());
+ }
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ private void appendInlineFeed(final XMLStreamWriter writer, final String navigationPropertyName,
+ final EntityInfoAggregator eia, final Entity data)
+ throws EntityProviderException, XMLStreamException, EdmException {
+
+ if (eia.getNavigationPropertyNames().contains(navigationPropertyName) &&
+ data != null && data.getNavigations().containsKey(navigationPropertyName)) {
+
+ EdmNavigationProperty navProp = (EdmNavigationProperty) eia.getEntityType().getProperty(navigationPropertyName);
+
+ if (navProp == null) {
+ throw new EntityProviderProducerException(EntityProviderException.EXPANDNOTSUPPORTED);
+ }
+ EntityCollection inlineData;
+ inlineData = (EntityCollection) data.getNavigation(navigationPropertyName);
+ if (inlineData == null) {
+ inlineData = new EntityCollection();
+ }
+
+ if (inlineData.getEntities().isEmpty()) {
+ return;
+ }
+ writer.writeStartElement(Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+
+ EntityCollectionSerializerProperties inlineProperties = inlineData.getCollectionProperties() == null
+ ? EntityCollectionSerializerProperties.serviceRoot(data.getWriteProperties().getServiceRoot()).build()
+ : inlineData.getCollectionProperties();
+ EdmEntitySet inlineEntitySet = eia.getEntitySet().getRelatedEntitySet(navProp);
+ AtomFeedSerializer inlineFeedProducer = new AtomFeedSerializer(inlineProperties);
+ inlineData.setCollectionProperties(inlineProperties);
+ EntityInfoAggregator inlineEia =
+ EntityInfoAggregator.create(inlineEntitySet, null);
+ inlineFeedProducer.append(writer, inlineEia, inlineData, true);
+
+ writer.writeEndElement();
+
+ }
+ }
+
+ private void appendInlineEntry(final XMLStreamWriter writer, final String navigationPropertyName,
+ final EntityInfoAggregator eia, final Entity data) throws EntityProviderException,
+ XMLStreamException, EdmException {
+
+ if (data.getNavigations() != null && data.getNavigations().containsKey(navigationPropertyName)) {
+
+ EdmNavigationProperty navProp = (EdmNavigationProperty) eia.getEntityType().getProperty(navigationPropertyName);
+
+ Entity inlineData = (Entity) data.getNavigation(navigationPropertyName);
+
+ if ((inlineData == null) || inlineData.getProperties().size() == 0) {
+ return;
+ }
+
+ writer.writeStartElement(Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+ if (inlineData != null && !(inlineData.getProperties().isEmpty())) {
+ inlineData.setWriteProperties(inlineData.getWriteProperties() == null ? data.getWriteProperties() : inlineData
+ .getWriteProperties());
+ EdmEntitySet inlineEntitySet = eia.getEntitySet().getRelatedEntitySet(navProp);
+ AtomEntryEntitySerializer inlineProducer = new AtomEntryEntitySerializer(inlineData.getWriteProperties());
+ EntityInfoAggregator inlineEia =
+ EntityInfoAggregator.create(inlineEntitySet, null);
+ inlineProducer.append(writer, inlineEia, inlineData, false, false);
+ }
+
+ writer.writeEndElement();
+ }
+ }
+
+
+ private void appendAtomEditLink(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final String selfLink) throws EntityProviderException {
+ try {
+ writer.writeStartElement(FormatXml.ATOM_LINK);
+ writer.writeAttribute(FormatXml.ATOM_HREF, selfLink);
+ writer.writeAttribute(FormatXml.ATOM_REL, Edm.LINK_REL_EDIT);
+ writer.writeAttribute(FormatXml.ATOM_TITLE, eia.getEntityType().getName());
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ private void appendAtomContentLink(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data, final String selfLink) throws EntityProviderException, EdmException {
+ try {
+ String mediaResourceMimeType = null;
+ EdmMapping entityTypeMapping = eia.getEntityType().getMapping();
+ if (entityTypeMapping != null) {
+ String mediaResourceMimeTypeKey = entityTypeMapping.getMediaResourceMimeTypeKey();
+ if (mediaResourceMimeTypeKey != null) {
+ mediaResourceMimeType = (String) data.get(mediaResourceMimeTypeKey);
+ }
+ }
+ if (mediaResourceMimeType == null) {
+ mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+ }
+
+ writer.writeStartElement(FormatXml.ATOM_LINK);
+ writer.writeAttribute(FormatXml.ATOM_HREF, selfLink + VALUE);
+ writer.writeAttribute(FormatXml.ATOM_REL, Edm.LINK_REL_EDIT_MEDIA);
+ writer.writeAttribute(FormatXml.ATOM_TYPE, mediaResourceMimeType);
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ private void appendAtomContentPart(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data, final String selfLink) throws EntityProviderException, EdmException {
+ try {
+
+ EdmMapping entityTypeMapping = eia.getEntityType().getMapping();
+ String self = null;
+ String mediaResourceMimeType = null;
+
+ if (entityTypeMapping != null) {
+ String mediaResourceSourceKey = entityTypeMapping.getMediaResourceSourceKey();
+ if (mediaResourceSourceKey != null) {
+ self = (String) data.get(mediaResourceSourceKey);
+ }
+ if (self == null) {
+ self = selfLink + VALUE;
+ }
+ String mediaResourceMimeTypeKey = entityTypeMapping.getMediaResourceMimeTypeKey();
+ if (mediaResourceMimeTypeKey != null) {
+ mediaResourceMimeType = (String) data.get(mediaResourceMimeTypeKey);
+ }
+ if (mediaResourceMimeType == null) {
+ mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+ }
+ } else {
+ self = selfLink + VALUE;
+ mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+ }
+
+ writer.writeStartElement(FormatXml.ATOM_CONTENT);
+ writer.writeAttribute(FormatXml.ATOM_TYPE, mediaResourceMimeType);
+ writer.writeAttribute(FormatXml.ATOM_SRC, self);
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ private void appendAtomMandatoryParts(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data) throws EntityProviderException {
+ try {
+ writer.writeStartElement(FormatXml.ATOM_ID);
+ String idlocation = properties.getServiceRoot().toASCIIString() + createSelfLink(
+ eia, data, null, properties.isKeyAutoGenerated(), true);;
+ writer.writeCharacters(idlocation);
+ writer.writeEndElement();
+
+ writer.writeStartElement(FormatXml.ATOM_TITLE);
+ writer.writeAttribute(FormatXml.ATOM_TYPE, FormatXml.ATOM_TEXT);
+ EntityPropertyInfo titleInfo = eia.getTargetPathInfo(EdmTargetPath.SYNDICATION_TITLE);
+ if (titleInfo != null) {
+ EdmSimpleType st = (EdmSimpleType) titleInfo.getType();
+ Object object = data.get(titleInfo.getName());
+ String title = null;
+ try { //NOSONAR
+ title = st.valueToString(object, EdmLiteralKind.DEFAULT, titleInfo.getFacets());
+ } catch (EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(EdmSimpleTypeException.getMessageReference(
+ e.getMessageReference()).updateContent(e.getMessageReference().getContent(), titleInfo.getName()), e);
+ }
+ if (title != null) {
+ writer.writeCharacters(title);
+ }
+ } else {
+ writer.writeCharacters(eia.getEntitySetName());
+ }
+ writer.writeEndElement();
+
+ writer.writeStartElement(FormatXml.ATOM_UPDATED);
+
+ writer.writeCharacters(getUpdatedString(eia, data));
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ String getUpdatedString(final EntityInfoAggregator eia, final Map<String, Object> data)
+ throws EdmSimpleTypeException, EntityProviderProducerException {
+ Object updateDate = null;
+ EdmFacets updateFacets = null;
+ EntityPropertyInfo updatedInfo = eia.getTargetPathInfo(EdmTargetPath.SYNDICATION_UPDATED);
+ if (updatedInfo != null) {
+ updateDate = data.get(updatedInfo.getName());
+ if (updateDate != null) {
+ updateFacets = updatedInfo.getFacets();
+ }
+ }
+ if (updateDate == null) {
+ updateDate = new Date();
+ }
+ try {
+ return EdmDateTimeOffset.getInstance().valueToString(updateDate, EdmLiteralKind.DEFAULT, updateFacets);
+ } catch (final EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(
+ EdmSimpleTypeException.getMessageReference(e.getMessageReference()).
+ updateContent(e.getMessageReference().getContent(),
+ updatedInfo == null ? null : updatedInfo.getName()), e);
+ }
+ }
+
+ private String getTargetPathValue(final EntityInfoAggregator eia, final String targetPath,
+ final Map<String, Object> data) throws EntityProviderException {
+ EntityPropertyInfo info = null;
+ try {
+ info = eia.getTargetPathInfo(targetPath);
+ if (info != null) {
+ EdmSimpleType type = (EdmSimpleType) info.getType();
+ Object value = data.get(info.getName());
+ return type.valueToString(value, EdmLiteralKind.DEFAULT, info.getFacets());
+ }
+ return null;
+ } catch (final EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(
+ EdmSimpleTypeException.getMessageReference(e.getMessageReference()).
+ updateContent(e.getMessageReference().getContent(), info.getName()), e);
+ }
+ }
+
+ private void appendAtomOptionalParts(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data) throws EntityProviderException {
+ try {
+ String authorEmail = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_AUTHOREMAIL, data);
+ String authorName = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_AUTHORNAME, data);
+ String authorUri = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_AUTHORURI, data);
+ if (authorEmail != null || authorName != null || authorUri != null) {
+ writer.writeStartElement(FormatXml.ATOM_AUTHOR);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_AUTHOR_NAME, authorName, false);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_AUTHOR_EMAIL, authorEmail, false);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_AUTHOR_URI, authorUri, false);
+ writer.writeEndElement();
+ }
+
+ String summary = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_SUMMARY, data);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_SUMMARY, summary, true);
+
+ String contributorName = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_CONTRIBUTORNAME, data);
+ String contributorEmail = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_CONTRIBUTOREMAIL, data);
+ String contributorUri = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_CONTRIBUTORURI, data);
+ if (contributorEmail != null || contributorName != null || contributorUri != null) {
+ writer.writeStartElement(FormatXml.ATOM_CONTRIBUTOR);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_CONTRIBUTOR_NAME, contributorName, false);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_CONTRIBUTOR_EMAIL, contributorEmail, false);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_CONTRIBUTOR_URI, contributorUri, false);
+ writer.writeEndElement();
+ }
+
+ String rights = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_RIGHTS, data);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_RIGHTS, rights, true);
+ String published = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_PUBLISHED, data);
+ appendAtomOptionalPart(writer, FormatXml.ATOM_PUBLISHED, published, false);
+
+ String term = eia.getEntityType().getNamespace() + Edm.DELIMITER + eia.getEntityType().getName();
+ writer.writeStartElement(FormatXml.ATOM_CATEGORY);
+ writer.writeAttribute(FormatXml.ATOM_CATEGORY_TERM, term);
+ writer.writeAttribute(FormatXml.ATOM_CATEGORY_SCHEME, Edm.NAMESPACE_SCHEME_2007_08);
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ private void appendAtomOptionalPart(final XMLStreamWriter writer, final String name, final String value,
+ final boolean writeType) throws EntityProviderException {
+ try {
+ if (value != null) {
+ writer.writeStartElement(name);
+ if (writeType) {
+ writer.writeAttribute(FormatXml.ATOM_TYPE, FormatXml.ATOM_TEXT);
+ }
+ writer.writeCharacters(value);
+ writer.writeEndElement();
+ }
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ static String createSelfLink(final EntityInfoAggregator eia, final Map<String, Object> data, final String extension,
+ boolean isKeyAutoGenerated, boolean isIdTag)
+ throws EntityProviderException {
+ StringBuilder sb = new StringBuilder();
+ if (!eia.isDefaultEntityContainer()) {
+ sb.append(Encoder.encode(eia.getEntityContainerName())).append(Edm.DELIMITER);
+ }
+ sb.append(Encoder.encode(eia.getEntitySetName()));
+
+ String keyValue = createEntryKey(eia, data, isKeyAutoGenerated, isIdTag);
+ if (isIdTag && isKeyAutoGenerated && "".equals(keyValue) && keyValue.length() == 0) {
+ sb.append(extension == null ? "" : ("/" + extension));
+ } else {
+ sb.append("(").append(keyValue).append(")").
+ append(extension == null ? "" : ("/" + extension));
+ }
+ return sb.toString();
+ }
+
+ private static String createEntryKey(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+ boolean isKeyAutoGenerated, boolean isIdTag)
+ throws EntityProviderException {
+ final List<EntityPropertyInfo> keyPropertyInfos = entityInfo.getKeyPropertyInfos();
+
+ StringBuilder keys = new StringBuilder();
+ for (final EntityPropertyInfo keyPropertyInfo : keyPropertyInfos) {
+ if (keys.length() > 0) {
+ keys.append(',');
+ }
+
+ final String name = keyPropertyInfo.getName();
+ if (keyPropertyInfos.size() > 1) {
+ keys.append(Encoder.encode(name)).append('=');
+ }
+
+ final EdmSimpleType type = (EdmSimpleType) keyPropertyInfo.getType();
+ try {
+ String keyValue = null;
+ if (isKeyAutoGenerated && data.get(name) == null) {
+ if (isIdTag) {
+ keyValue = "";
+ } else {
+ Object value = fetchDefaultValue(type.getDefaultType());
+ keyValue = Encoder.encode(type.valueToString(value, EdmLiteralKind.URI,
+ keyPropertyInfo.getFacets()));
+ }
+ } else {
+ keyValue = Encoder.encode(type.valueToString(data.get(name), EdmLiteralKind.URI,
+ keyPropertyInfo.getFacets()));
+ }
+ keys.append(keyValue);
+ } catch (final EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(
+ EdmSimpleTypeException.getMessageReference(e.getMessageReference()).
+ updateContent(e.getMessageReference().getContent(), name), e);
+ }
+ }
+
+ return keys.toString();
+ }
+
+ private static Object fetchDefaultValue(Class<?> edmType) throws EntityProviderProducerException {
+ if (edmType == boolean.class || edmType == Boolean.class) {
+ return false;
+ } else if (edmType == String.class) {
+ return "A";
+ } else if (edmType == byte.class || edmType == Byte.class) {
+ return new Byte(Byte.parseByte("0"));
+ } else if (edmType == char.class) {
+ return new Character('A');
+ } else if (edmType == short.class || edmType == Short.class) {
+ return new Short(Short.parseShort("0"));
+ } else if (edmType == int.class || edmType == Integer.class) {
+ return new Integer(0);
+ } else if (edmType == long.class || edmType == Long.class) {
+ return new Long(0L);
+ } else if (edmType == float.class || edmType == Float.class) {
+ return new Float(0.0f);
+ } else if (edmType == double.class || edmType == Double.class) {
+ return new Double(0.0d);
+ } else if (edmType == BigDecimal.class) {
+ return BigDecimal.valueOf(0.0);
+ } else if (edmType == UUID.class) {
+ return UUID.fromString("0");
+ } else if (edmType == Timestamp.class) {
+ return new Timestamp(Calendar.getInstance().getTimeInMillis());
+ } else if (edmType == Calendar.class) {
+ return Calendar.getInstance();
+ } else if (edmType == byte[].class || edmType == Byte[].class) {
+ return new byte[0];
+ } else if (edmType == Date.class) {
+ return new Date();
+ } else if (edmType == BigInteger.class) {
+ return new BigInteger("0");
+ } else if (edmType == Time.class) {
+ return new Time(0L);
+ } else {
+ throw new EntityProviderProducerException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED);
+ }
+ }
+
+ private void appendProperties(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data) throws EntityProviderException {
+ try {
+ {
+ if (!data.isEmpty() && data.size() > 0) {
+ writer.writeStartElement(Edm.NAMESPACE_M_2007_08, FormatXml.M_PROPERTIES);
+ for (String propertyName : eia.getPropertyNames()) {
+ if (data.containsKey(propertyName)) {
+ appendPropertyNameValue(writer, eia, data, propertyName);
+ }
+ }
+ writer.writeEndElement();
+ }
+ }
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ /**
+ * @param writer
+ * @param eia
+ * @param data
+ * @param propertyName
+ * @throws EntityProviderException
+ */
+ private void appendPropertyNameValue(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final Map<String, Object> data, String propertyName) throws EntityProviderException {
+ EntityPropertyInfo propertyInfo = eia.getPropertyInfo(propertyName);
+ if (isNotMappedViaCustomMapping(propertyInfo)) {
+ Object value = data.get(propertyName);
+ XmlPropertyEntitySerializer aps = new XmlPropertyEntitySerializer(properties);
+ aps.append(writer, propertyInfo.getName(), propertyInfo, value);
+ }
+ }
+
+ private boolean isNotMappedViaCustomMapping(final EntityPropertyInfo propertyInfo) {
+ EdmCustomizableFeedMappings customMapping = propertyInfo.getCustomMapping();
+ if (customMapping != null && customMapping.isFcKeepInContent() != null) {
+ return customMapping.isFcKeepInContent();
+ }
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java
new file mode 100644
index 0000000..8e4e615
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.commons.Encoder;
+import org.apache.olingo.odata2.core.edm.EdmDateTimeOffset;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Serializes an ATOM feed.
+ *
+ */
+public class AtomFeedSerializer {
+
+ private final EntityCollectionSerializerProperties properties;
+
+ /**
+ *
+ * @param properties
+ */
+ public AtomFeedSerializer(final EntityCollectionSerializerProperties properties) {
+ this.properties = properties == null ?
+ EntityCollectionSerializerProperties.serviceRoot(null).build() :
+ properties;
+ }
+
+ /**
+ * This serializes the xml payload feed
+ * @param writer
+ * @param eia
+ * @param data
+ * @param isInline
+ * @throws EntityProviderException
+ */
+ public void append(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final EntityCollection data, final boolean isInline) throws EntityProviderException {
+ try {
+ if (properties.getServiceRoot() == null) {
+ throw new EntityProviderProducerException(EntityProviderException.MANDATORY_WRITE_PROPERTY);
+ }
+
+ writer.writeStartElement(FormatXml.ATOM_FEED);
+ if (!isInline) {
+ writer.writeDefaultNamespace(Edm.NAMESPACE_ATOM_2005);
+ writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+ writer.writeNamespace(Edm.PREFIX_D, Edm.NAMESPACE_D_2007_08);
+
+ }
+ writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_BASE, properties.getServiceRoot()
+ .toASCIIString());
+
+ // write all atom infos (mandatory and optional)
+ appendAtomMandatoryParts(writer, eia);
+ appendAtomSelfLink(writer, eia);
+
+
+ appendEntries(writer, eia, data);
+
+
+
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ private void appendEntries(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+ final EntityCollection data) throws EntityProviderException {
+ AtomEntryEntitySerializer entryProvider;
+ for (Entity singleEntryData : data.getEntities()) {
+ entryProvider = singleEntryData.getWriteProperties() == null? data.getGlobalEntityProperties() == null ?
+ new AtomEntryEntitySerializer
+ (EntitySerializerProperties.serviceRoot(data.getCollectionProperties().getServiceRoot()).build()) :
+ new AtomEntryEntitySerializer(data.getGlobalEntityProperties()):
+ new AtomEntryEntitySerializer(singleEntryData.getWriteProperties());
+ entryProvider.append(writer, eia, singleEntryData, false, true);
+ }
+ }
+
+
+ private void appendAtomSelfLink(final XMLStreamWriter writer, final EntityInfoAggregator eia)
+ throws EntityProviderException {
+
+ URI self = properties.getSelfLink();
+ String selfLink = "";
+ if (self == null) {
+ selfLink = createSelfLink(eia);
+ } else {
+ selfLink = self.toASCIIString();
+ }
+ try {
+ writer.writeStartElement(FormatXml.ATOM_LINK);
+ writer.writeAttribute(FormatXml.ATOM_HREF, selfLink);
+ writer.writeAttribute(FormatXml.ATOM_REL, Edm.LINK_REL_SELF);
+ writer.writeAttribute(FormatXml.ATOM_TITLE, eia.getEntitySetName());
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ private String createSelfLink(final EntityInfoAggregator eia) {
+ StringBuilder sb = new StringBuilder();
+ if (!eia.isDefaultEntityContainer()) {
+ final String entityContainerName = Encoder.encode(eia.getEntityContainerName());
+ sb.append(entityContainerName).append(Edm.DELIMITER);
+ }
+ final String entitySetName = Encoder.encode(eia.getEntitySetName());
+ sb.append(entitySetName);
+ return sb.toString();
+ }
+
+ private void appendAtomMandatoryParts(final XMLStreamWriter writer, final EntityInfoAggregator eia)
+ throws EntityProviderException {
+ try {
+ writer.writeStartElement(FormatXml.ATOM_ID);
+ writer.writeCharacters(createAtomId(eia));
+ writer.writeEndElement();
+
+ writer.writeStartElement(FormatXml.ATOM_TITLE);
+ writer.writeAttribute(FormatXml.M_TYPE, FormatXml.ATOM_TEXT);
+ writer.writeCharacters(eia.getEntitySetName());
+ writer.writeEndElement();
+
+ writer.writeStartElement(FormatXml.ATOM_UPDATED);
+
+ Object updateDate = null;
+ EdmFacets updateFacets = null;
+ updateDate = new Date();
+ writer.writeCharacters(EdmDateTimeOffset.getInstance().valueToString(updateDate, EdmLiteralKind.DEFAULT,
+ updateFacets));
+ writer.writeEndElement();
+
+ writer.writeStartElement(FormatXml.ATOM_AUTHOR);
+ writer.writeStartElement(FormatXml.ATOM_AUTHOR_NAME);
+ writer.writeEndElement();
+ writer.writeEndElement();
+
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ private String createAtomId(final EntityInfoAggregator eia) throws EntityProviderException {
+ return properties.getServiceRoot() + createSelfLink(eia);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java
new file mode 100644
index 0000000..b727538
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.commons.ContentType;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing an entity in JSON, also usable for function imports
+ * returning a single instance of an entity type.
+ *
+ */
+public class JsonEntryEntitySerializer {
+
+ private final EntitySerializerProperties properties;
+ private String location;
+ private String idlocation;
+ private JsonStreamWriter jsonStreamWriter;
+ private static final String VALUE = "/$value";
+
+ /**
+ *
+ * @param properties
+ * @throws EntityProviderException
+ */
+ public JsonEntryEntitySerializer(final EntitySerializerProperties properties) {
+ this.properties = properties == null ? EntitySerializerProperties.serviceRoot(null).build() : properties;
+ }
+
+ /**
+ * This serializes the json payload entry
+ * @param writer
+ * @param entityInfo
+ * @param data
+ * @param isRootElement
+ * @throws EntityProviderException
+ */
+ public void append(final Writer writer, final EntityInfoAggregator entityInfo, final Entity data)
+ throws EntityProviderException {
+ if (data == null) {
+ throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+ }
+ final EdmEntityType type = entityInfo.getEntityType();
+
+ try {
+ jsonStreamWriter = new JsonStreamWriter(writer);
+
+ jsonStreamWriter.beginObject();
+
+ boolean containsMetadata = false;
+ if (properties.isIncludeMetadata()) {
+ writeMetadata(entityInfo, data.getProperties(), type);
+ containsMetadata = true;
+ }
+ writeProperties(entityInfo, data.getProperties(), type, containsMetadata);
+
+ writeNavigationProperties(writer, entityInfo, data.getNavigations(), type);
+ jsonStreamWriter.endObject();
+
+ writer.flush();
+
+ } catch (final IOException e) {
+ throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ } catch (final EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ private void writeNavigationProperties(final Writer writer, final EntityInfoAggregator entityInfo,
+ final Map<String, Object> data,
+ final EdmEntityType type) throws EdmException, EntityProviderException, IOException {
+ for (final String navigationPropertyName : type.getNavigationPropertyNames()) {
+ if (data.containsKey(navigationPropertyName)) {
+ if (data.get(navigationPropertyName) == null) {
+ throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+ }
+ if (data.get(navigationPropertyName) instanceof Entity ||
+ data.get(navigationPropertyName) instanceof EntityCollection) {
+ jsonStreamWriter.separator();
+ jsonStreamWriter.name(navigationPropertyName);
+ writeExpandedNavigationProperty(writer, entityInfo, data, type, navigationPropertyName);
+ } else if (data.get(navigationPropertyName) instanceof Map<?,?>){
+ writeNavigationLinks(entityInfo, data);
+ } else {
+ throw new EntityProviderException(EntityProviderException.INCORRECT_NAVIGATION_TYPE);
+ }
+ }
+ }
+ }
+
+ private void writeExpandedNavigationProperty(final Writer writer, final EntityInfoAggregator entityInfo,
+ final Map<String, Object> data,
+ final EdmEntityType type, final String navigationPropertyName) throws EdmException, EntityProviderException,
+ IOException {
+
+ final EdmNavigationProperty navigationProperty = (EdmNavigationProperty) type.getProperty(navigationPropertyName);
+ final boolean isFeed = navigationProperty.getMultiplicity() == EdmMultiplicity.MANY;
+ final EdmEntitySet entitySet = entityInfo.getEntitySet();
+ final EdmEntitySet inlineEntitySet = entitySet.getRelatedEntitySet(navigationProperty);
+
+ if (isFeed) {
+ EntityCollection inlineData = (EntityCollection) data.get(navigationProperty.getName());
+
+ if(inlineData == null){
+ throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+ }
+ final EntityCollectionSerializerProperties inlineProperties = inlineData.getCollectionProperties() == null ?
+ EntityCollectionSerializerProperties.
+ serviceRoot(properties.getServiceRoot()).build() :
+ inlineData.getCollectionProperties();
+ JsonFeedEntitySerializer jsonFeedEntityProducer = new JsonFeedEntitySerializer(inlineProperties);
+ final EntityInfoAggregator inlineEntityInfo =
+ EntityInfoAggregator.create(inlineEntitySet, null);
+ jsonFeedEntityProducer.appendAsArray(writer, inlineEntityInfo, inlineData);
+ } else {
+ Entity inlineData = (Entity) data.get(navigationProperty.getName());
+ //This statement is used for the client use case. Flag should never be set on server side
+ if(inlineData == null){
+ throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+ }
+ if (inlineData != null && inlineData.getProperties() != null &&
+ !inlineData.getProperties().isEmpty()) {
+ final EntitySerializerProperties inlineProperties = inlineData.getWriteProperties() == null ?
+ EntitySerializerProperties.
+ serviceRoot(properties.getServiceRoot()).build() : inlineData.getWriteProperties();
+ final EntityInfoAggregator inlineEntityInfo =
+ EntityInfoAggregator.create(inlineEntitySet, null);
+ new JsonEntryEntitySerializer(inlineProperties).append(writer, inlineEntityInfo, inlineData);
+ } else {
+ jsonStreamWriter.beginObject();
+ jsonStreamWriter.endObject();
+ }
+ }
+ }
+
+ private void writeProperties(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+ final EdmEntityType type, boolean containsMetadata) throws EdmException, EntityProviderException, IOException {
+ // if the payload contains metadata we must not omit the first comm as it separates the _metadata object form the
+ // properties
+ boolean omitComma = !containsMetadata;
+
+ List<String> propertyNames = type.getPropertyNames();
+ for (final String propertyName : propertyNames) {
+ if (data.containsKey(propertyName)) {
+ omitComma = appendPropertyNameValue(entityInfo, data, omitComma, propertyName);
+ }
+ }
+ }
+
+ /**
+ * @param entityInfo
+ * @param data
+ * @param omitComma
+ * @param propertyName
+ * @return
+ * @throws IOException
+ * @throws EdmException
+ * @throws EntityProviderException
+ */
+ private boolean appendPropertyNameValue(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+ boolean omitComma, String propertyName) throws IOException, EdmException, EntityProviderException {
+ if (omitComma) {
+ omitComma = false; //NOSONAR
+ } else {
+ jsonStreamWriter.separator();
+ }
+ jsonStreamWriter.name(propertyName);
+
+ JsonPropertyEntitySerializer.appendPropertyValue(jsonStreamWriter,
+ entityInfo.getPropertyInfo(propertyName),
+ data.get(propertyName),
+ properties.isValidatingFacets());
+ return omitComma;
+ }
+
+ private void writeMetadata(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+ final EdmEntityType type) throws IOException, EntityProviderException, EdmException {
+ if (properties.getServiceRoot() == null) {
+ location = "";
+ idlocation = "";
+ } else {
+ location = properties.getServiceRoot().toASCIIString() +
+ AtomEntryEntitySerializer.createSelfLink(entityInfo, data, null, properties.isKeyAutoGenerated(), false);
+ idlocation = properties.getServiceRoot().toASCIIString() +
+ AtomEntryEntitySerializer.createSelfLink(entityInfo, data, null, properties.isKeyAutoGenerated(), true);
+ }
+
+ jsonStreamWriter.name(FormatJson.METADATA);
+ jsonStreamWriter.beginObject();
+ jsonStreamWriter.namedStringValue(FormatJson.ID, idlocation);
+ jsonStreamWriter.separator();
+ jsonStreamWriter.namedStringValue(FormatJson.URI, location);
+ jsonStreamWriter.separator();
+ jsonStreamWriter.namedStringValueRaw(FormatJson.TYPE, type.getNamespace() + Edm.DELIMITER + type.getName());
+
+ if (type.hasStream()) {
+ jsonStreamWriter.separator();
+
+ EdmMapping entityTypeMapping = entityInfo.getEntityType().getMapping();
+ String mediaResourceMimeType = null;
+ String mediaSrc = null;
+
+ if (entityTypeMapping != null) {
+ String mediaResourceSourceKey = entityTypeMapping.getMediaResourceSourceKey();
+ if (mediaResourceSourceKey != null) {
+ mediaSrc = (String) data.get(mediaResourceSourceKey);
+ }
+ if (mediaSrc == null) {
+ mediaSrc = location + VALUE;
+ }
+ String mediaResourceMimeTypeKey = entityTypeMapping.getMediaResourceMimeTypeKey();
+ if (mediaResourceMimeTypeKey != null) {
+ mediaResourceMimeType = (String) data.get(mediaResourceMimeTypeKey);
+ }
+ if (mediaResourceMimeType == null) {
+ mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+ }
+ } else {
+ mediaSrc = location + VALUE;
+ mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+ }
+
+ jsonStreamWriter.namedStringValueRaw(FormatJson.CONTENT_TYPE, mediaResourceMimeType);
+ jsonStreamWriter.separator();
+
+ jsonStreamWriter.namedStringValue(FormatJson.MEDIA_SRC, mediaSrc);
+ jsonStreamWriter.separator();
+ jsonStreamWriter.namedStringValue(FormatJson.EDIT_MEDIA, location + VALUE);
+ }
+ jsonStreamWriter.endObject();
+ }
+
+ private String createCustomTargetLink(final EntityInfoAggregator entityInfo, final String navigationPropertyName,
+ final Map<String, Object> key) throws EntityProviderException, EdmException {
+ String target;
+ final EntityInfoAggregator targetEntityInfo = EntityInfoAggregator.create(
+ entityInfo.getEntitySet().getRelatedEntitySet(
+ (EdmNavigationProperty) entityInfo.getEntityType().getProperty(navigationPropertyName)));
+ target = (properties.getServiceRoot() == null ? "" : properties.getServiceRoot().toASCIIString())
+ + AtomEntryEntitySerializer.createSelfLink(targetEntityInfo, key, null, properties.isKeyAutoGenerated(), false);
+ return target;
+ }
+
+ private void writeNavigationLinks(final EntityInfoAggregator entityInfo,
+ Map<String, Object> navigationLinks) throws IOException,
+ EntityProviderException, EdmException {
+ if (navigationLinks != null && !navigationLinks.isEmpty()) {
+ for (Entry<String, Object> entry : navigationLinks.entrySet()) {
+ String target = null;
+ if (entry.getValue() instanceof HashMap<?, ?>) {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> navigationKeyMap = (Map<String, Object>) entry.getValue();
+ if (navigationKeyMap != null && !navigationKeyMap.isEmpty()) { //NOSONAR
+ target = createCustomTargetLink(entityInfo, entry.getKey(), navigationKeyMap);
+ jsonStreamWriter.separator();
+ jsonStreamWriter.name(entry.getKey());
+ jsonStreamWriter.beginObject()
+ .name(FormatJson.DEFERRED);
+ JsonLinkEntitySerializer.appendUri(jsonStreamWriter, target);
+ jsonStreamWriter.endObject();
+ }
+ }
+ }
+ }
+ }
+
+ public String getLocation() {
+ return location;
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java
new file mode 100644
index 0000000..e86b6c4
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing an entity collection (a feed) in JSON.
+ *
+ */
+public class JsonFeedEntitySerializer {
+
+ private final EntityCollectionSerializerProperties properties;
+
+ /**
+ *
+ * @param properties
+ * @throws EntityProviderException
+ */
+ public JsonFeedEntitySerializer(final EntityCollectionSerializerProperties properties) {
+ this.properties = properties == null ? EntityCollectionSerializerProperties.
+ serviceRoot(null).build() : properties;
+ }
+
+ /**
+ * This serializes the json payload feed
+ * @param writer
+ * @param entityInfo
+ * @param data
+ * @throws EntityProviderException
+ */
+ public void appendAsArray(final Writer writer, final EntityInfoAggregator entityInfo,
+ final EntityCollection data) throws EntityProviderException {
+
+ JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+ try {
+ jsonStreamWriter.beginArray();
+ appendEntries(writer, entityInfo, data, jsonStreamWriter);
+ jsonStreamWriter.endArray();
+ } catch (final IOException e) {
+ throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ }
+ }
+
+ /**
+ * This serializes the json payload feed
+ * @param writer
+ * @param entityInfo
+ * @param data
+ * @param isRootElement
+ * @throws EntityProviderException
+ */
+ public void appendAsObject(final Writer writer, final EntityInfoAggregator entityInfo,
+ final EntityCollection data) throws EntityProviderException {
+ if (data == null) {
+ throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+ }
+ JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+
+ try {
+ jsonStreamWriter.beginObject();
+
+ jsonStreamWriter.name(FormatJson.RESULTS)
+ .beginArray();
+
+ appendEntries(writer, entityInfo, data, jsonStreamWriter);
+
+ jsonStreamWriter.endArray();
+
+ jsonStreamWriter.endObject();
+ } catch (final IOException e) {
+ throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ }
+ }
+
+ private void appendEntries(final Writer writer, final EntityInfoAggregator entityInfo,
+ final EntityCollection data, JsonStreamWriter jsonStreamWriter) throws EntityProviderException,
+ IOException {
+ boolean first = true;
+ for (Entity entryData : data.getEntities()) {
+ if (first) {
+ first = false;
+ } else {
+ jsonStreamWriter.separator();
+ }
+ EntitySerializerProperties entryProperties = entryData == null ||
+ entryData.getWriteProperties() == null ? data.getGlobalEntityProperties() != null?
+ data.getGlobalEntityProperties(): EntitySerializerProperties.
+ serviceRoot(properties.getServiceRoot()).
+ build() : entryData.getWriteProperties();
+
+ JsonEntryEntitySerializer entryProducer = new JsonEntryEntitySerializer(entryProperties);
+ entryProducer.append(writer, entityInfo, entryData);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java
new file mode 100644
index 0000000..cd756ce
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+
+import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing a link in JSON.
+ *
+ */
+public class JsonLinkEntitySerializer {
+
+ private final EntityProviderWriteProperties properties; //NOSONAR
+
+ /**
+ *
+ * @param properties
+ * @throws EntityProviderException
+ */
+ public JsonLinkEntitySerializer(final EntityProviderWriteProperties properties) {
+ this.properties = properties == null ? EntityProviderWriteProperties.serviceRoot(null).build() : properties;
+ }
+
+ protected static void appendUri(final JsonStreamWriter jsonStreamWriter, final String uri) throws IOException {
+ jsonStreamWriter.beginObject()
+ .namedStringValue(FormatJson.URI, uri)
+ .endObject();
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java
new file mode 100644
index 0000000..f759389
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing a single simple or complex property in JSON, also usable
+ * for function imports returning a single instance of a simple or complex type.
+ *
+ */
+public class JsonPropertyEntitySerializer {
+
+ /**
+ * Serializes a property of every entry in json payload
+ * @param writer
+ * @param propertyInfo
+ * @param value
+ * @throws EntityProviderException
+ */
+ public void append(final Writer writer, final EntityPropertyInfo propertyInfo, final Object value)
+ throws EntityProviderException {
+ JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+
+ try {
+ jsonStreamWriter.beginObject()
+ .name(FormatJson.D)
+ .beginObject();
+
+ jsonStreamWriter.name(propertyInfo.getName());
+ appendPropertyValue(jsonStreamWriter, propertyInfo.isComplex() ? (EntityComplexPropertyInfo) propertyInfo
+ : propertyInfo, value, true);
+
+ jsonStreamWriter.endObject()
+ .endObject();
+ } catch (final IOException e) {
+ throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+ .getSimpleName()), e);
+ } catch (final EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ protected static void appendPropertyValue(final JsonStreamWriter jsonStreamWriter,
+ final EntityPropertyInfo propertyInfo, final Object value,
+ boolean validatingFacets) throws IOException, EdmException,
+ EntityProviderException { //NOSONAR
+ if (propertyInfo.isComplex()) {
+ if (value == null || value instanceof Map<?,?>) {
+ jsonStreamWriter.beginObject();
+ appendPropertyMetadata(jsonStreamWriter, propertyInfo.getType());
+ if (value == null) {
+ jsonStreamWriter.endObject();
+ return;
+ }
+ for (final EntityPropertyInfo childPropertyInfo : ((EntityComplexPropertyInfo) propertyInfo)
+ .getPropertyInfos()) {
+ final String name = childPropertyInfo.getName();
+ if ( !((Map<?,?>)value).containsKey(name)) { //NOSONAR
+ continue;
+ }
+ jsonStreamWriter.separator();
+ jsonStreamWriter.name(name);
+ appendPropertyValue(jsonStreamWriter, childPropertyInfo,
+ value == null ? null : ((Map<?,?>) value).get(name), validatingFacets); //NOSONAR
+ }
+ jsonStreamWriter.endObject();
+ } else {
+ throw new EntityProviderProducerException(EntityProviderException.ILLEGAL_ARGUMENT
+ .addContent("A complex property must have a Map as data"));
+ }
+ } else {
+ final EdmSimpleType type = (EdmSimpleType) propertyInfo.getType();
+ final Object contentValue = value instanceof Entity ? ((Entity) value).
+ getProperties().get(propertyInfo.getName()) : value;
+ final EdmFacets facets = validatingFacets ? propertyInfo.getFacets(): null;
+ String valueAsString = null;
+ try {
+ valueAsString = type.valueToString(contentValue, EdmLiteralKind.JSON, facets);
+ } catch (EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(EdmSimpleTypeException.getMessageReference(
+ e.getMessageReference()).updateContent(e.getMessageReference().getContent(),
+ propertyInfo.getName()), e);
+ }
+ switch (EdmSimpleTypeKind.valueOf(type.getName())) {
+ case String:
+ jsonStreamWriter.stringValue(valueAsString);
+ break;
+ case Boolean:
+ case Byte:
+ case SByte:
+ case Int16:
+ case Int32:
+ jsonStreamWriter.unquotedValue(valueAsString);
+ break;
+ case DateTime:
+ case DateTimeOffset:
+ // Although JSON escaping is (and should be) done in the JSON
+ // serializer, we backslash-escape the forward slash here explicitly
+ // because it is not required to escape it in JSON but in OData.
+ jsonStreamWriter.stringValueRaw(valueAsString == null ? null : valueAsString.replace("/", "\\/"));
+ break;
+ default:
+ jsonStreamWriter.stringValueRaw(valueAsString);
+ break;
+ }
+ }
+ }
+
+ protected static void appendPropertyMetadata(final JsonStreamWriter jsonStreamWriter, final EdmType type)
+ throws IOException, EdmException {
+ jsonStreamWriter.name(FormatJson.METADATA)
+ .beginObject()
+ .namedStringValueRaw(FormatJson.TYPE, type.getNamespace() + Edm.DELIMITER + type.getName())
+ .endObject();
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java
new file mode 100644
index 0000000..24bfc17
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.serializer;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmCustomizableFeedMappings;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Internal EntityProvider for simple and complex EDM properties which are pre-analyzed as {@link EntityPropertyInfo}.
+ *
+ */
+public class XmlPropertyEntitySerializer {
+
+ private final boolean validateFacets;
+
+ /**
+ *
+ * @param writeProperties
+ */
+ public XmlPropertyEntitySerializer(final EntitySerializerProperties writeProperties) {
+ this(writeProperties.isValidatingFacets());
+ }
+
+ /**
+ *
+ * @param validateFacets
+ */
+ public XmlPropertyEntitySerializer( final boolean validateFacets) {
+ this.validateFacets = validateFacets;
+ }
+
+ /**
+ * Append {@link Object} <code>value</code> based on {@link EntityPropertyInfo} to {@link XMLStreamWriter} in an
+ * already existing XML structure inside the d namespace.
+ *
+ * @param writer
+ * @param name Name of the outer XML tag
+ * @param propertyInfo
+ * @param value
+ * @throws EntityProviderException
+ */
+ public void append(final XMLStreamWriter writer, final String name, final EntityPropertyInfo propertyInfo,
+ final Object value) throws EntityProviderException {
+ try {
+ writer.writeStartElement(Edm.NAMESPACE_D_2007_08, name);
+
+ if (propertyInfo.isComplex()) {
+ appendProperty(writer, (EntityComplexPropertyInfo) propertyInfo, value);
+ } else {
+ appendProperty(writer, propertyInfo, value);
+ }
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+ /**
+ * Serializes custom properties
+ * @param writer
+ * @param name
+ * @param propertyInfo
+ * @param value
+ * @throws EntityProviderException
+ */
+ public void appendCustomProperty(final XMLStreamWriter writer, final String name,
+ final EntityPropertyInfo propertyInfo, final Object value) throws EntityProviderException {
+ try {
+ if (!propertyInfo.isComplex()) {
+ writeStartElementWithCustomNamespace(writer, propertyInfo, name);
+ appendProperty(writer, propertyInfo, value);
+ writer.writeEndElement();
+ }
+ } catch (XMLStreamException e) {
+ throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderProducerException(e.getMessageReference(), e);
+ }
+ }
+
+
+ /**
+ *
+ * @param writer
+ * @param propertyInfo
+ * @param value
+ * @throws XMLStreamException
+ * @throws EdmException
+ * @throws EntityProviderException
+ */
+ private void appendProperty(final XMLStreamWriter writer, final EntityComplexPropertyInfo propertyInfo,
+ final Object value) throws XMLStreamException, EdmException, EntityProviderException {
+
+ if (value == null) {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_NULL, FormatXml.ATOM_VALUE_TRUE);
+ } else {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_TYPE, getFqnTypeName(propertyInfo));
+ List<EntityPropertyInfo> propertyInfos = propertyInfo.getPropertyInfos();
+ for (EntityPropertyInfo childPropertyInfo : propertyInfos) {
+ if ( value instanceof Map && !((Map<?,?>)value).containsKey(childPropertyInfo.getName())||
+ (value instanceof Entity && (((Entity)value).getProperty(childPropertyInfo.getName()))==null)) {
+ continue;
+ }
+ Object childValue = extractChildValue(value, childPropertyInfo.getName());
+ append(writer, childPropertyInfo.getName(), childPropertyInfo, childValue);
+ }
+ }
+ }
+
+ /**
+ * Returns full qualified name of a type of a given PropertyInfo.
+ * @return Full qualified name
+ */
+ private String getFqnTypeName(final EntityComplexPropertyInfo propertyInfo) throws EdmException {
+ return propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+ }
+
+ /**
+ * If <code>value</code> is a {@link Map} the element with given <code>name</code> as key is returned.
+ * If <code>value</code> is NOT a {@link Map} its {@link String#valueOf(Object)} result is returned.
+ *
+ * @param value
+ * @param name
+ * @return name or result (see above)
+ */
+ private Object extractChildValue(final Object value, final String name) {
+ if (value instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ return map.get(name);
+ }else if (value instanceof Entity) {
+ Map<?, ?> map = ((Entity) value).getProperties();
+ return map.get(name);
+ }
+ return String.valueOf(value);
+ }
+
+ /**
+ * Appends a simple-property value to the XML stream.
+ * @param writer the XML stream writer
+ * @param prop property informations
+ * @param value the value of the property
+ * @throws XMLStreamException
+ * @throws EdmException
+ * @throws EntityProviderProducerException
+ */
+ private void appendProperty(final XMLStreamWriter writer, final EntityPropertyInfo prop, final Object value)
+ throws XMLStreamException, EdmException, EntityProviderProducerException {
+ Object contentValue = value;
+ String mimeType = null;
+ if (prop.getMimeType() != null) {
+ mimeType = prop.getMimeType();
+ } else if (prop.getMapping() != null && prop.getMapping().getMediaResourceMimeTypeKey() != null) {
+ mimeType = (String) extractChildValue(value, prop.getMapping().getMediaResourceMimeTypeKey());
+ contentValue = extractChildValue(value, prop.getName());
+ }
+
+ if (mimeType != null) {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.M_MIME_TYPE, mimeType);
+ }
+
+ final EdmSimpleType type = (EdmSimpleType) prop.getType();
+ final EdmFacets facets = validateFacets ? prop.getFacets() : null;
+ String valueAsString = null;
+ try {
+ valueAsString = type.valueToString(contentValue, EdmLiteralKind.DEFAULT, facets);
+ } catch (EdmSimpleTypeException e) {
+ throw new EntityProviderProducerException(EdmSimpleTypeException.getMessageReference(
+ e.getMessageReference()).updateContent(
+ e.getMessageReference().getContent(), prop.getName()), e);
+ }
+ if (valueAsString == null) {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_NULL, FormatXml.ATOM_VALUE_TRUE);
+ } else {
+ writer.writeCharacters(valueAsString);
+ }
+ }
+
+ /**
+ *
+ * @param writer
+ * @param prop
+ * @param name
+ * @throws XMLStreamException
+ * @throws EntityProviderException
+ */
+ private void writeStartElementWithCustomNamespace(final XMLStreamWriter writer, final EntityPropertyInfo prop,
+ final String name) throws XMLStreamException, EntityProviderException {
+ EdmCustomizableFeedMappings mapping = prop.getCustomMapping();
+ String nsPrefix = mapping.getFcNsPrefix();
+ String nsUri = mapping.getFcNsUri();
+ if (nsUri == null || nsPrefix == null) {
+ throw new EntityProviderProducerException(EntityProviderException.INVALID_NAMESPACE.addContent(name));
+ }
+ writer.writeStartElement(nsPrefix, name, nsUri);
+ writer.writeNamespace(nsPrefix, nsUri);
+ }
+}