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:41 UTC
[05/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/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
index df88d27..e75d74a 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
@@ -20,8 +20,10 @@ package org.apache.olingo.client.core.serialization;
import java.io.InputStream;
import java.net.URI;
+import java.sql.Timestamp;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -61,6 +63,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.geo.Geospatial;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import com.fasterxml.aalto.stax.InputFactoryImpl;
@@ -95,12 +98,17 @@ public class AtomDeserializer extends AbstractAtomDealer implements ODataDeseria
if (event.isCharacters() && !event.asCharacters().isWhiteSpace()
&& (typeInfo == null || !typeInfo.getPrimitiveTypeKind().isGeospatial())) {
-
final String stringValue = event.asCharacters().getData();
- value = typeInfo == null ? stringValue : // TODO: add facets
- ((EdmPrimitiveType) typeInfo.getType()).valueOfString(stringValue, true, null,
+ if (typeInfo == null) {
+ value = stringValue;
+ } else {
+ final EdmPrimitiveType primitiveType = (EdmPrimitiveType) typeInfo.getType();
+ final Class<?> returnType = primitiveType.getDefaultType().isAssignableFrom(Calendar.class)
+ ? Timestamp.class : primitiveType.getDefaultType();
+ value = ((EdmPrimitiveType) typeInfo.getType()).valueOfString(stringValue, true, null,
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, true,
- ((EdmPrimitiveType) typeInfo.getType()).getDefaultType());
+ returnType);
+ }
}
if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
@@ -634,11 +642,9 @@ public class AtomDeserializer extends AbstractAtomDealer implements ODataDeseria
entity.setMediaETag(mediaETag.getValue());
}
} else if (link.getRel().startsWith(Constants.NS_NAVIGATION_LINK_REL)) {
-
entity.getNavigationLinks().add(link);
inline(reader, event.asStartElement(), link);
} else if (link.getRel().startsWith(Constants.NS_ASSOCIATION_LINK_REL)) {
-
entity.getAssociationLinks().add(link);
} else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomSerializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomSerializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomSerializer.java
index bc56e48..3c12f5a 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomSerializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomSerializer.java
@@ -20,8 +20,11 @@ package org.apache.olingo.client.core.serialization;
import java.io.Writer;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLOutputFactory;
@@ -83,7 +86,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
private void value(final XMLStreamWriter writer,
final ValueType valueType, final EdmPrimitiveTypeKind kind, final Object value)
throws XMLStreamException, EdmPrimitiveTypeException {
- if (value == null) {
+ if (value == null || (valueType == ValueType.COMPLEX && ((ComplexValue)value).getValue().isEmpty())) {
writer.writeAttribute(Constants.PREFIX_METADATA, namespaceMetadata,
Constants.ATTR_NULL, Boolean.TRUE.toString());
return;
@@ -140,7 +143,11 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
property.getValue());
if (!property.isNull() && property.isComplex() && !property.isCollection()) {
links(writer, property.asComplex().getAssociationLinks());
- links(writer, property.asComplex().getNavigationLinks());
+ if (serverMode) {
+ links(writer, property.asComplex().getNavigationLinks());
+ } else {
+ writeNavigationLinks(writer, property.asComplex().getNavigationLinks());
+ }
}
writer.writeEndElement();
@@ -158,7 +165,6 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
private void startDocument(final XMLStreamWriter writer, final String rootElement) throws XMLStreamException {
writer.writeStartDocument();
writer.setDefaultNamespace(Constants.NS_ATOM);
-
writer.writeStartElement(rootElement);
namespaces(writer);
@@ -175,49 +181,147 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writer.writeEndDocument();
writer.flush();
}
-
- private void links(final XMLStreamWriter writer, final List<Link> links)
+
+ private boolean isEntitySetNavigation(final Link link) {
+ return Constants.ENTITY_SET_NAVIGATION_LINK_TYPE.equals(link.getType());
+ }
+
+ private void writeNavigationLinks(final XMLStreamWriter writer, final List<Link> links)
throws XMLStreamException, EdmPrimitiveTypeException {
- for (Link link : links) {
- writer.writeStartElement(Constants.ATOM_ELEM_LINK);
-
- if (StringUtils.isNotBlank(link.getRel())) {
- writer.writeAttribute(Constants.ATTR_REL, link.getRel());
- }
- if (StringUtils.isNotBlank(link.getTitle())) {
- writer.writeAttribute(Constants.ATTR_TITLE, link.getTitle());
- }
- if (StringUtils.isNotBlank(link.getHref())) {
- writer.writeAttribute(Constants.ATTR_HREF, link.getHref());
- }
- if (StringUtils.isNotBlank(link.getType())) {
- writer.writeAttribute(Constants.ATTR_TYPE, link.getType());
- }
+ final Map<String, List<String>> entitySetLinks = new HashMap<String, List<String>>();
+ for (Link link : links) {
+
if (link.getInlineEntity() != null || link.getInlineEntitySet() != null) {
- writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
-
- if (link.getInlineEntity() != null) {
- writer.writeStartElement(Constants.ATOM_ELEM_ENTRY);
- entity(writer, link.getInlineEntity());
- writer.writeEndElement();
- }
- if (link.getInlineEntitySet() != null) {
- writer.writeStartElement(Constants.ATOM_ELEM_FEED);
- entitySet(writer, link.getInlineEntitySet());
- writer.writeEndElement();
+ writeLink(writer, link, new ExtraContent() {
+ @Override
+ public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
+ writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
+ if (link.getInlineEntity() != null) {
+ writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_ENTRY);
+ entity(writer, link.getInlineEntity());
+ writer.writeEndElement();
+ }
+ if (link.getInlineEntitySet() != null) {
+ writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_FEED);
+ entitySet(writer, link.getInlineEntitySet());
+ writer.writeEndElement();
+ }
+ writer.writeEndElement(); // inline
+ }
+ });
+
+ } else if (link.getBindingLink() != null) {
+ writeLink(writer, link, new ExtraContent() {
+ @Override
+ public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
+ writer.writeAttribute(Constants.ATTR_HREF, link.getBindingLink());
+ }
+ });
+ } else if (link.getBindingLinks() != null && !link.getBindingLinks().isEmpty()) {
+ writeLink(writer, link, new ExtraContent() {
+ @Override
+ public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
+ writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
+ writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_FEED);
+ for (String binding:link.getBindingLinks()) {
+ Entity entity = new Entity();
+ entity.setId(URI.create(binding));
+ inlineEntityRef(writer, entity);
+ }
+ writer.writeEndElement(); //feed
+ writer.writeEndElement(); //inline
+ }
+ });
+ } else {
+ if (isEntitySetNavigation(link)) {
+ final List<String> uris;
+ if (entitySetLinks.containsKey(link.getTitle())) {
+ uris = entitySetLinks.get(link.getTitle());
+ } else {
+ uris = new ArrayList<String>();
+ entitySetLinks.put(link.getTitle(), uris);
+ }
+ if (StringUtils.isNotBlank(link.getHref())) {
+ uris.add(link.getHref());
+ }
+ } else {
+ writeLink(writer, link, new ExtraContent() {
+ @Override
+ public void write(XMLStreamWriter writer, Link link)
+ throws XMLStreamException, EdmPrimitiveTypeException {
+ }
+ });
}
-
- writer.writeEndElement();
}
-
- for (Annotation annotation : link.getAnnotations()) {
- annotation(writer, annotation, null);
+ }
+ for (String title : entitySetLinks.keySet()) {
+ final List<String>entitySetLink = entitySetLinks.get(title);
+ if (!entitySetLink.isEmpty()) {
+ Link link = new Link();
+ link.setTitle(title);
+ link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
+ link.setRel(Constants.NS_NAVIGATION_LINK_REL+title);
+
+ writeLink(writer, link, new ExtraContent() {
+ @Override
+ public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
+ writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
+ writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_FEED);
+ for (String binding:entitySetLink) {
+ Entity entity = new Entity();
+ entity.setId(URI.create(binding));
+ inlineEntityRef(writer, entity);
+ }
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ });
}
-
- writer.writeEndElement();
+ }
+ }
+
+ private void links(final XMLStreamWriter writer, final List<Link> links)
+ throws XMLStreamException, EdmPrimitiveTypeException {
+ for (Link link : links) {
+ writeLink(writer, link, new ExtraContent() {
+ @Override
+ public void write(XMLStreamWriter writer, Link link)
+ throws XMLStreamException, EdmPrimitiveTypeException {
+ }
+ });
}
}
+
+ interface ExtraContent {
+ void write(final XMLStreamWriter writer, final Link link)
+ throws XMLStreamException, EdmPrimitiveTypeException;
+ }
+
+ private void writeLink(final XMLStreamWriter writer, final Link link, final ExtraContent content)
+ throws XMLStreamException, EdmPrimitiveTypeException {
+ writer.writeStartElement(Constants.ATOM_ELEM_LINK);
+
+ if (StringUtils.isNotBlank(link.getRel())) {
+ writer.writeAttribute(Constants.ATTR_REL, link.getRel());
+ }
+ if (StringUtils.isNotBlank(link.getTitle())) {
+ writer.writeAttribute(Constants.ATTR_TITLE, link.getTitle());
+ }
+ if (StringUtils.isNotBlank(link.getHref())) {
+ writer.writeAttribute(Constants.ATTR_HREF, link.getHref());
+ }
+ if (StringUtils.isNotBlank(link.getType())) {
+ writer.writeAttribute(Constants.ATTR_TYPE, link.getType());
+ }
+
+ content.write(writer, link);
+
+ for (Annotation annotation : link.getAnnotations()) {
+ annotation(writer, annotation, null);
+ }
+ writer.writeEndElement();
+ }
private void common(final XMLStreamWriter writer, final AbstractODataObject object) throws XMLStreamException {
if (StringUtils.isNotBlank(object.getTitle())) {
@@ -298,7 +402,12 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
links(writer, entity.getAssociationLinks());
- links(writer, entity.getNavigationLinks());
+ if (serverMode) {
+ links(writer, entity.getNavigationLinks());
+ } else {
+ writeNavigationLinks(writer, entity.getNavigationLinks());
+ writeNavigationLinks(writer, entity.getNavigationBindings());
+ }
links(writer, entity.getMediaEditLinks());
if (serverMode) {
@@ -336,15 +445,22 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
}
+ private void inlineEntityRef(final XMLStreamWriter writer, final Entity entity) throws XMLStreamException {
+ writer.writeStartElement(namespaceMetadata, Constants.ATOM_ELEM_ENTRY_REF);
+ writer.writeAttribute(Constants.ATOM_ATTR_ID, entity.getId().toASCIIString());
+ writer.writeEndElement();
+ }
+
private void entityRef(final XMLStreamWriter writer, final Entity entity) throws XMLStreamException {
writer.writeStartElement(Constants.ATOM_ELEM_ENTRY_REF);
- writer.writeNamespace(StringUtils.EMPTY, namespaceMetadata);
+ writer.writeDefaultNamespace(namespaceMetadata);
writer.writeAttribute(Constants.ATOM_ATTR_ID, entity.getId().toASCIIString());
+ writer.writeEndElement();
}
private void entityRef(final XMLStreamWriter writer, final ResWrap<Entity> container) throws XMLStreamException {
writer.writeStartElement(Constants.ATOM_ELEM_ENTRY_REF);
- writer.writeNamespace(StringUtils.EMPTY, namespaceMetadata);
+ writer.writeDefaultNamespace(namespaceMetadata);
addContextInfo(writer, container);
writer.writeAttribute(Constants.ATOM_ATTR_ID, container.getPayload().getId().toASCIIString());
}
@@ -356,15 +472,11 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
if (entity.getType() == null && entity.getProperties().isEmpty()) {
writer.writeStartDocument();
writer.setDefaultNamespace(namespaceMetadata);
-
entityRef(writer, entity);
} else {
startDocument(writer, Constants.ATOM_ELEM_ENTRY);
-
entity(writer, entity);
}
-
- writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
}
@@ -416,7 +528,6 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
for (Entity entity : entitySet.getEntities()) {
if (entity.getType() == null && entity.getProperties().isEmpty()) {
entityRef(writer, entity);
- writer.writeEndElement();
} else {
writer.writeStartElement(Constants.ATOM_ELEM_ENTRY);
entity(writer, entity);
@@ -512,9 +623,10 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writer.writeStartDocument();
- writer.writeStartElement(Constants.ATTR_METADATA, Constants.ATTR_REF);
+ writer.writeStartElement(Constants.ATTR_METADATA, Constants.ATTR_REF, Constants.NS_METADATA);
writer.writeNamespace(Constants.ATTR_METADATA, Constants.NS_METADATA);
- writer.writeAttribute(Constants.ATTR_METADATA, Constants.CONTEXT, container.getContextURL().toASCIIString());
+ writer.writeAttribute(Constants.ATTR_METADATA, Constants.NS_METADATA, Constants.CONTEXT,
+ container.getContextURL().toASCIIString());
writer.writeAttribute(Constants.ATOM_ATTR_ID, container.getPayload().toASCIIString());
writer.writeEndElement();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
index 926f74c..1f42d9b 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
@@ -456,7 +456,7 @@ public class ODataBinderImpl implements ODataBinder {
odataLinked.addLink(createODataInlineEntity(inlineEntity,
URIUtils.getURI(base, href), title, metadataETag));
} else {
- odataLinked.addLink(createODataInlineEntitySet(inlineEntitySet,
+ odataLinked.addLink(createODataInlineEntitySet(inlineEntitySet, href == null?null:
URIUtils.getURI(base, href), title, metadataETag));
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java
index 87edec1..3577455 100644
--- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java
+++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java
@@ -146,7 +146,7 @@ public class JSONTest extends AbstractTest {
final StringWriter writer = new StringWriter();
getClient().getSerializer(contentType).write(writer, getClient().getDeserializer(contentType).toEntity(
getClass().getResourceAsStream(filename + "." + getSuffix(contentType))).getPayload());
-
+ System.out.println(writer.toString());
assertSimilar(filename + "." + getSuffix(contentType), writer.toString());
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Customers.xml
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Customers.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Customers.xml
index aa416d2..a0adedd 100644
--- a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Customers.xml
+++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Customers.xml
@@ -35,7 +35,9 @@
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Customer" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="edit" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Parent"/>
- <link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed" title="Orders" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Orders"/>
+ <link rel="http://docs.oasis-open.org/odata/ns/related/Orders"
+ type="application/atom+xml;type=feed" title="Orders">
+ <m:inline><feed><m:ref id="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Orders"/></feed></m:inline></link>
<link rel="http://docs.oasis-open.org/odata/ns/related/Company" type="application/atom+xml;type=entry" title="Company" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Company"/>
<title/>
<updated>2014-03-31T09:35:14Z</updated>
@@ -76,7 +78,10 @@
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Customer" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="edit" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=2)"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=2)/Parent"/>
- <link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed" title="Orders" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=2)/Orders"/>
+ <link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed"
+ title="Orders">
+ <m:inline><feed><m:ref id="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=2)/Orders"/></feed></m:inline>
+ </link>
<link rel="http://docs.oasis-open.org/odata/ns/related/Company" type="application/atom+xml;type=entry" title="Company" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=2)/Company"/>
<title/>
<updated>2014-03-31T09:35:14Z</updated>
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Products_5.xml
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Products_5.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Products_5.xml
index 9109f2d..409799e 100644
--- a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Products_5.xml
+++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/Products_5.xml
@@ -23,7 +23,7 @@
<id>http://odatae2etest.azurewebsites.net/javatest/DefaultService/Products(5)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Product" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Products(5)" />
- <link rel="http://docs.oasis-open.org/odata/ns/related/Details" type="application/atom+xml;type=feed" title="Details" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Products(5)/Details" />
+ <link rel="http://docs.oasis-open.org/odata/ns/related/Details" type="application/atom+xml;type=feed" title="Details"><m:inline><feed><ref xmlns="http://docs.oasis-open.org/odata/ns/metadata" id="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Products(5)/Details"/></feed></m:inline></link>
<title />
<updated>2014-03-28T11:24:49Z</updated>
<author>
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/VipCustomer.xml
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/VipCustomer.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/VipCustomer.xml
index d233ce9..cc5c04d 100644
--- a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/VipCustomer.xml
+++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/VipCustomer.xml
@@ -30,7 +30,7 @@
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Customer" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/VipCustomer" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/VipCustomer/Parent" />
- <link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed" title="Orders" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/VipCustomer/Orders" />
+ <link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed" title="Orders"><m:inline><feed><ref xmlns="http://docs.oasis-open.org/odata/ns/metadata" id="http://odatae2etest.azurewebsites.net/javatest/DefaultService/VipCustomer/Orders"/></feed></m:inline></link>
<link rel="http://docs.oasis-open.org/odata/ns/related/Company" type="application/atom+xml;type=entry" title="Company" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/VipCustomer/Company" />
<title />
<updated>2014-03-28T13:03:32Z</updated>
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/annotated.xml
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/annotated.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/annotated.xml
index 851f960..a3b06a9 100644
--- a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/annotated.xml
+++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/annotated.xml
@@ -24,7 +24,9 @@
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Customer" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="edit" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Parent"/>
- <link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed" title="Orders" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Orders">
+ <link rel="http://docs.oasis-open.org/odata/ns/related/Orders"
+ type="application/atom+xml;type=feed" title="Orders">
+ <m:inline><feed><m:ref id="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Customers(PersonID=1)/Orders"/></feed></m:inline>
<m:annotation term="com.contoso.display.style" m:type="#com.contoso.display.styleType">
<d:order m:type="Int32">2</d:order>
</m:annotation>
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/entity.withcomplexnavigation.xml
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/entity.withcomplexnavigation.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/entity.withcomplexnavigation.xml
index 1a4e0cc..94cb766 100644
--- a/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/entity.withcomplexnavigation.xml
+++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/v4/entity.withcomplexnavigation.xml
@@ -33,7 +33,8 @@ under the License.
<link rel="edit" title="Customer" href="Customers('ALFKI')"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/Orders"
type="application/atom+xml;type=feed"
- title="Orders" href="Customers('ALFKI')/Orders"/>
+ title="Orders">
+ <m:inline><feed><m:ref id="Customers('ALFKI')/Orders"/></feed></m:inline> </link>
<link rel="http://docs.oasis-open.org/odata/ns/related/Supplier"
type="application/atom+xml;type=entry"
title="Supplier" href="Customers('ALFKI')/Supplier"/>
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
index d81530f..0eab699 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
@@ -31,7 +31,8 @@ public class EntityCollectionSerializerOptions {
private ExpandOption expand;
private SelectOption select;
private boolean onlyReferences;
-
+ private String id;
+
/** Gets the {@link ContextURL}. */
public ContextURL getContextURL() {
return contextURL;
@@ -56,6 +57,11 @@ public class EntityCollectionSerializerOptions {
public boolean onlyReferences() {
return onlyReferences;
}
+
+ /** Gets the id of the entity collection */
+ public String getId() {
+ return id;
+ }
/** Initializes the options builder. */
public static Builder with() {
@@ -101,6 +107,12 @@ public class EntityCollectionSerializerOptions {
return this;
}
+ /** Sets id of the collection */
+ public Builder setId(final String id) {
+ options.id = id;
+ return this;
+ }
+
/** Builds the OData serializer options. */
public EntityCollectionSerializerOptions build() {
return options;
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
index 76e8d5f..7f3f234 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
@@ -152,7 +152,8 @@ public abstract class ServiceRequest {
return (T) EntityCollectionSerializerOptions.with()
.contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
.count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
- .select(uriInfo.getSelectOption()).setWriteOnlyReferences(references).build();
+ .select(uriInfo.getSelectOption()).setWriteOnlyReferences(references)
+ .setId(getODataRequest().getRawBaseUri()+getODataRequest().getRawODataPath()).build();
} else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) {
return (T) ComplexSerializerOptions.with().contextURL(contextUrl)
.expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption()).build();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
index f35c277..2eed18f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
@@ -53,7 +53,9 @@ public class ContentNegotiator {
return Arrays.asList(
ContentType.JSON,
ContentType.JSON_NO_METADATA,
- ContentType.APPLICATION_JSON);
+ ContentType.APPLICATION_JSON,
+ ContentType.APPLICATION_ATOM_XML,
+ ContentType.APPLICATION_XML);
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
index dac1642..2dbac81 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
@@ -44,11 +44,12 @@ import org.apache.olingo.server.api.uri.UriHelper;
import org.apache.olingo.server.core.debug.DebugResponseHelperImpl;
import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl;
import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer;
+import org.apache.olingo.server.core.deserializer.xml.ODataXmlDeserializer;
import org.apache.olingo.server.core.etag.ETagHelperImpl;
import org.apache.olingo.server.core.prefer.PreferencesImpl;
import org.apache.olingo.server.core.serializer.FixedFormatSerializerImpl;
import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
-import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializerImpl;
+import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializer;
import org.apache.olingo.server.core.uri.UriHelperImpl;
public class ODataImpl extends OData {
@@ -64,8 +65,9 @@ public class ODataImpl extends OData {
|| ContentType.VALUE_ODATA_METADATA_NONE.equals(metadata)) {
serializer = new ODataJsonSerializer(contentType);
}
- } else if (contentType.isCompatible(ContentType.APPLICATION_XML)) {
- serializer = new ODataXmlSerializerImpl();
+ } else if (contentType.isCompatible(ContentType.APPLICATION_XML)
+ || contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)) {
+ serializer = new ODataXmlSerializer();
}
if (serializer == null) {
@@ -114,15 +116,13 @@ public class ODataImpl extends OData {
if (contentType.isCompatible(ContentType.JSON)) {
deserializer = new ODataJsonDeserializer(contentType);
- // } else if(contentType.isCompatible(ContentType.APPLICATION_XML))
- // We do not support XML deserialization right now so this must lead
- // to an error.
- // {
+ } else if (contentType.isCompatible(ContentType.APPLICATION_XML)
+ || contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)) {
+ deserializer = new ODataXmlDeserializer();
} else {
throw new DeserializerException("Unsupported format: " + contentType.toContentTypeString(),
DeserializerException.MessageKeys.UNSUPPORTED_FORMAT, contentType.toContentTypeString());
}
-
return deserializer;
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5b99eb7b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
new file mode 100644
index 0000000..c130ebb
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
@@ -0,0 +1,702 @@
+/*
+ * 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.deserializer.xml;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.AbstractODataObject;
+import org.apache.olingo.commons.api.data.ComplexValue;
+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.Property;
+import org.apache.olingo.commons.api.data.Valuable;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.edm.EdmAction;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmEnumType;
+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.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.commons.core.edm.primitivetype.AbstractGeospatialType;
+import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.DeserializerResult;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
+import org.apache.olingo.server.core.deserializer.DeserializerResultImpl;
+
+import com.fasterxml.aalto.stax.InputFactoryImpl;
+
+public class ODataXmlDeserializer implements ODataDeserializer {
+
+ protected static final XMLInputFactory FACTORY = new InputFactoryImpl();
+ private static final String ATOM = "a";
+ private static final String NS_ATOM = "http://www.w3.org/2005/Atom";
+ protected QName REF_ELEMENT = new QName("http://docs.oasis-open.org/odata/ns/metadata", "ref");
+ protected QName FEED_ELEMENT = new QName("http://www.w3.org/2005/Atom", "feed");
+ protected QName ID_ATTR = new QName(NS_ATOM, ATOM);
+
+ protected final QName propertiesQName = new QName(Constants.NS_METADATA, Constants.PROPERTIES);
+ protected final QName propertyValueQName = new QName(Constants.NS_METADATA, Constants.VALUE);
+ protected final QName contextQName = new QName(Constants.NS_METADATA, Constants.CONTEXT);
+ protected final QName nullQName = new QName(Constants.NS_METADATA, Constants.ATTR_NULL);
+ protected final QName inlineQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_INLINE);
+ protected final QName entryRefQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_ENTRY_REF);
+ protected final QName etagQName = new QName(Constants.NS_METADATA, Constants.ATOM_ATTR_ETAG);
+ protected final QName countQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_COUNT);
+
+ protected void namespaces(final XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeNamespace(StringUtils.EMPTY, Constants.NS_ATOM);
+ writer.writeNamespace(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
+ writer.writeNamespace(Constants.PREFIX_METADATA, Constants.NS_METADATA);
+ writer.writeNamespace(Constants.PREFIX_DATASERVICES, Constants.NS_DATASERVICES);
+ writer.writeNamespace(Constants.PREFIX_GML, Constants.NS_GML);
+ writer.writeNamespace(Constants.PREFIX_GEORSS, Constants.NS_GEORSS);
+ }
+
+ protected XMLEventReader getReader(final InputStream input) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(input);
+ }
+
+ private Object primitive(final XMLEventReader reader, final StartElement start,
+ final EdmProperty edmProperty) throws XMLStreamException, EdmPrimitiveTypeException,
+ DeserializerException {
+
+ Object value = null;
+
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isCharacters() && !event.asCharacters().isWhiteSpace()) {
+ if (edmProperty.getType() instanceof AbstractGeospatialType<?>) {
+ throw new DeserializerException("geo types support not implemented",
+ DeserializerException.MessageKeys.NOT_IMPLEMENTED);
+ }
+ final String stringValue = event.asCharacters().getData();
+ value = ((EdmPrimitiveType)edmProperty.getType()).valueOfString(stringValue,
+ edmProperty.isNullable(),
+ edmProperty.getMaxLength(),
+ edmProperty.getPrecision(),
+ edmProperty.getScale(),
+ edmProperty.isUnicode(),
+ ((EdmPrimitiveType)edmProperty.getType()).getDefaultType());
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+ return value;
+ }
+
+ private Object complex(final XMLEventReader reader, final StartElement start, EdmComplexType edmComplex,
+ boolean validateType)
+ throws XMLStreamException, EdmPrimitiveTypeException, DeserializerException {
+
+ ComplexValue value = new ComplexValue();
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isStartElement()) {
+ StartElement se = event.asStartElement();
+ value.getValue().add(property(reader, se, (EdmProperty)edmComplex.getProperty(se.getName().getLocalPart())));
+ }
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+ return value;
+ }
+
+ private void collection(final Valuable valuable, final XMLEventReader reader, final StartElement start,
+ final EdmProperty edmProperty) throws XMLStreamException, EdmPrimitiveTypeException, DeserializerException {
+
+ List<Object> values = new ArrayList<Object>();
+ EdmType edmType = edmProperty.getType();
+
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ if (edmType instanceof SingletonPrimitiveType) {
+ values.add(primitive(reader, event.asStartElement(), edmProperty));
+ } else if (edmType instanceof EdmComplexType) {
+ values.add(complex(reader, event.asStartElement(), (EdmComplexType)edmType, false));
+ } else if (edmType instanceof EdmEnumType) {
+ values.add(readEnum(reader, event.asStartElement(), edmProperty));
+ } else {
+ // do not add null or empty values
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+ valuable.setValue(getValueType(edmType, true), values);
+ }
+
+ private Object readEnum(XMLEventReader reader, StartElement start, EdmProperty edmProperty)
+ throws XMLStreamException {
+ boolean foundEndProperty = false;
+ Object value = null;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isCharacters() && !event.asCharacters().isWhiteSpace()) {
+ value = event.asCharacters().getData();
+ }
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+ return value;
+ }
+
+ private Property property(final XMLEventReader reader, final StartElement start, final EdmProperty edmProperty)
+ throws XMLStreamException, EdmPrimitiveTypeException, DeserializerException {
+
+ final Property property = new Property();
+
+ if (propertyValueQName.equals(start.getName())) {
+ // retrieve name from context
+ final Attribute context = start.getAttributeByName(contextQName);
+ if (context != null) {
+ property.setName(StringUtils.substringAfterLast(context.getValue(), "/"));
+ }
+ } else {
+ property.setName(start.getName().getLocalPart());
+ }
+ valuable(property, reader, start, edmProperty);
+ return property;
+ }
+
+ private ValueType getValueType(EdmType edmType, boolean isCollection) {
+ if (edmType instanceof SingletonPrimitiveType) {
+ return isCollection? ValueType.COLLECTION_PRIMITIVE:ValueType.PRIMITIVE;
+ } else if (edmType instanceof EdmComplexType) {
+ return isCollection? ValueType.COLLECTION_COMPLEX:ValueType.COMPLEX;
+ } else if (edmType instanceof EdmEnumType) {
+ return isCollection?ValueType.COLLECTION_ENUM:ValueType.ENUM;
+ } else {
+ return ValueType.PRIMITIVE;
+ }
+ }
+
+ private void valuable(final Valuable valuable, final XMLEventReader reader, final StartElement start,
+ EdmProperty edmProperty) throws XMLStreamException, EdmPrimitiveTypeException,
+ DeserializerException {
+
+ final Attribute nullAttr = start.getAttributeByName(nullQName);
+ if (nullAttr != null) {
+ //found null
+ boolean foundEndProperty = false;
+ while (reader.hasNext() && !foundEndProperty) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperty = true;
+ }
+ }
+ valuable.setValue(getValueType(edmProperty.getType(), false), null);
+ return;
+ }
+
+ EdmType edmType = edmProperty.getType();
+ if (edmProperty.isCollection()) {
+ collection(valuable, reader, start, edmProperty);
+ valuable.setType("Collection("+edmType.getFullQualifiedName().getFullQualifiedNameAsString()+")");
+ } else if (edmType instanceof SingletonPrimitiveType) {
+ valuable.setType(edmType.getFullQualifiedName().getFullQualifiedNameAsString());
+ valuable.setValue(ValueType.PRIMITIVE, primitive(reader, start, edmProperty));
+ } else if (edmType instanceof EdmComplexType) {
+ valuable.setValue(ValueType.COMPLEX, complex(reader, start, (EdmComplexType)edmType, true));
+ valuable.setType(edmType.getFullQualifiedName().getFullQualifiedNameAsString());
+ } else if (edmType instanceof EdmEnumType) {
+ valuable.setValue(ValueType.ENUM, readEnum(reader, start, edmProperty));
+ valuable.setType(edmType.getFullQualifiedName().getFullQualifiedNameAsString());
+ } else {
+ // do not add null or empty values
+ }
+ }
+
+ @Override
+ public DeserializerResult property(InputStream input, EdmProperty edmProperty)
+ throws DeserializerException {
+ try {
+ final XMLEventReader reader = getReader(input);
+ final StartElement start = skipBeforeFirstStartElement(reader);
+ Property property = property(reader, start, edmProperty);
+ return DeserializerResultImpl.with().property(property)
+ .build();
+ } catch (XMLStreamException e) {
+ throw new DeserializerException(e.getMessage(), e, DeserializerException.MessageKeys.IO_EXCEPTION);
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new DeserializerException(e.getMessage(), e,
+ DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY);
+ }
+ }
+
+ private StartElement skipBeforeFirstStartElement(final XMLEventReader reader) throws XMLStreamException {
+ StartElement startEvent = null;
+ while (reader.hasNext() && startEvent == null) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isStartElement()) {
+ startEvent = event.asStartElement();
+ }
+ }
+ if (startEvent == null) {
+ throw new IllegalArgumentException("Cannot find any XML start element");
+ }
+
+ return startEvent;
+ }
+
+ private void common(final XMLEventReader reader, final StartElement start,
+ final AbstractODataObject object, final String key) throws XMLStreamException {
+
+ boolean foundEndElement = false;
+ while (reader.hasNext() && !foundEndElement) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isCharacters() && !event.asCharacters().isWhiteSpace()) {
+ try {
+ object.setCommonProperty(key, event.asCharacters().getData());
+ } catch (ParseException e) {
+ throw new XMLStreamException("While parsing Atom entry or feed common elements", e);
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndElement = true;
+ }
+ }
+ }
+
+ private void inline(final XMLEventReader reader, final StartElement start, final Link link,
+ final EdmEntityType edmEntityType) throws XMLStreamException, EdmPrimitiveTypeException,
+ DeserializerException {
+
+ boolean foundEndElement = false;
+ EdmNavigationProperty navigationProperty = edmEntityType.getNavigationProperty(link.getTitle());
+ while (reader.hasNext() && !foundEndElement) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ if (inlineQName.equals(event.asStartElement().getName())) {
+ StartElement inline = getStartElement(reader);
+ if (inline != null) {
+ if (Constants.QNAME_ATOM_ELEM_ENTRY.equals(inline.getName())) {
+ if (navigationProperty.isCollection()) {
+ throw new DeserializerException( "Navigation Property "+ link.getTitle() +
+ " must be collection entities",
+ DeserializerException.MessageKeys.INVALID_ANNOTATION_TYPE, link.getTitle());
+ }
+
+ link.setInlineEntity(entity(reader, inline, navigationProperty.getType()));
+ }
+ if (Constants.QNAME_ATOM_ELEM_FEED.equals(inline.getName())) {
+ if (!navigationProperty.isCollection()) {
+ throw new DeserializerException("Navigation Property " + link.getTitle() +
+ " must be single entity",
+ DeserializerException.MessageKeys.INVALID_ANNOTATION_TYPE, link.getTitle());
+ }
+ link.setInlineEntitySet(entitySet(reader, inline, navigationProperty.getType()));
+ }
+ }
+ } else if (REF_ELEMENT.equals(event.asStartElement().getName())) {
+ if (navigationProperty.isCollection()) {
+ throw new DeserializerException("Binding annotation: " + link.getTitle() +
+ " must be collection of entity refercences",
+ DeserializerException.MessageKeys.INVALID_ANNOTATION_TYPE, link.getTitle());
+ }
+ link.setBindingLink(entityRef(reader, event.asStartElement()));
+ link.setType(Constants.ENTITY_BINDING_LINK_TYPE);
+ } else if (Constants.QNAME_ATOM_ELEM_FEED.equals(event.asStartElement().getName())) {
+ if (navigationProperty.isCollection()) {
+ throw new DeserializerException("Binding annotation: " + link.getTitle() +
+ " must be single entity refercences",
+ DeserializerException.MessageKeys.INVALID_ANNOTATION_TYPE, link.getTitle());
+ }
+ link.setBindingLinks(entityRefCollection(reader, event.asStartElement()));
+ link.setType(Constants.ENTITY_COLLECTION_BINDING_LINK_TYPE);
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndElement = true;
+ }
+ }
+ }
+
+ private List<String> entityRefCollection(XMLEventReader reader, StartElement start)
+ throws XMLStreamException {
+ boolean foundEndElement = false;
+ ArrayList<String> references = new ArrayList<String>();
+ while (reader.hasNext() && !foundEndElement) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ if (REF_ELEMENT.equals(event.asStartElement().getName())) {
+ references.add(entityRef(reader, event.asStartElement()));
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndElement = true;
+ }
+ }
+ return references;
+ }
+
+ private String entityRef(XMLEventReader reader, StartElement start) throws XMLStreamException {
+ boolean foundEndElement = false;
+ final Attribute entityRefId = start.getAttributeByName(Constants.QNAME_ATOM_ATTR_ID);
+ while (reader.hasNext() && !foundEndElement) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndElement = true;
+ }
+ }
+ return entityRefId.getValue();
+ }
+
+ private StartElement getStartElement(final XMLEventReader reader) throws XMLStreamException {
+ while (reader.hasNext()) {
+ final XMLEvent innerEvent = reader.peek();
+ if (innerEvent.isCharacters() && innerEvent.asCharacters().isWhiteSpace()) {
+ reader.nextEvent();
+ } else if (innerEvent.isStartElement()) {
+ return innerEvent.asStartElement();
+ } else if (innerEvent.isEndElement() && inlineQName.equals(innerEvent.asEndElement().getName())) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ private void properties(final XMLEventReader reader, final StartElement start, final Entity entity,
+ final EdmEntityType edmEntityType)
+ throws XMLStreamException, EdmPrimitiveTypeException, DeserializerException {
+
+ boolean foundEndProperties = false;
+ while (reader.hasNext() && !foundEndProperties) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ EdmProperty edmProperty = (EdmProperty)edmEntityType
+ .getProperty(event.asStartElement().getName().getLocalPart());
+ entity.getProperties().add(property(reader, event.asStartElement(), edmProperty));
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndProperties = true;
+ }
+ }
+ }
+
+ private Entity entityRef(final StartElement start) throws XMLStreamException {
+ final Entity entity = new Entity();
+
+ final Attribute entityRefId = start.getAttributeByName(Constants.QNAME_ATOM_ATTR_ID);
+ if (entityRefId != null) {
+ entity.setId(URI.create(entityRefId.getValue()));
+ }
+
+ return entity;
+ }
+
+ private Entity entity(final XMLEventReader reader, final StartElement start, final EdmEntityType edmEntityType)
+ throws XMLStreamException, EdmPrimitiveTypeException, DeserializerException {
+ Entity entity = null;
+ if (entryRefQName.equals(start.getName())) {
+ entity = entityRef(start);
+ } else if (Constants.QNAME_ATOM_ELEM_ENTRY.equals(start.getName())) {
+ entity = new Entity();
+ final Attribute xmlBase = start.getAttributeByName(Constants.QNAME_ATTR_XML_BASE);
+ if (xmlBase != null) {
+ entity.setBaseURI(URI.create(xmlBase.getValue()));
+ }
+
+ final Attribute etag = start.getAttributeByName(etagQName);
+ if (etag != null) {
+ entity.setETag(etag.getValue());
+ }
+
+ boolean foundEndEntry = false;
+ while (reader.hasNext() && !foundEndEntry) {
+ final XMLEvent event = reader.nextEvent();
+
+ if (event.isStartElement()) {
+ if (Constants.QNAME_ATOM_ELEM_ID.equals(event.asStartElement().getName())) {
+ common(reader, event.asStartElement(), entity, "id");
+ } else if (Constants.QNAME_ATOM_ELEM_CATEGORY.equals(event.asStartElement().getName())) {
+ final Attribute term = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATOM_ATTR_TERM));
+ if (term != null) {
+ entity.setType(new EdmTypeInfo.Builder().setTypeExpression(term.getValue()).build().internal());
+ }
+ } else if (Constants.QNAME_ATOM_ELEM_LINK.equals(event.asStartElement().getName())) {
+ final Link link = new Link();
+ final Attribute rel = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_REL));
+ if (rel != null) {
+ link.setRel(rel.getValue());
+ }
+ final Attribute title = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TITLE));
+ if (title != null) {
+ link.setTitle(title.getValue());
+ }
+ final Attribute href = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_HREF));
+ if (href != null) {
+ link.setBindingLink(href.getValue());
+ }
+ final Attribute linktype = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TYPE));
+ if (linktype != null) {
+ link.setType(linktype.getValue());
+ }
+ if (Constants.SELF_LINK_REL.equals(link.getRel())) {
+ entity.setSelfLink(link);
+ } else if (Constants.EDIT_LINK_REL.equals(link.getRel())) {
+ entity.setEditLink(link);
+ } else if (Constants.EDITMEDIA_LINK_REL.equals(link.getRel())) {
+ final Attribute mediaETag = event.asStartElement().getAttributeByName(etagQName);
+ if (mediaETag != null) {
+ entity.setMediaETag(mediaETag.getValue());
+ }
+ } else if (link.getRel().startsWith(Constants.NS_NAVIGATION_LINK_REL)) {
+ inline(reader, event.asStartElement(), link, edmEntityType);
+ if (link.getInlineEntity() == null && link.getInlineEntitySet() == null) {
+ entity.getNavigationBindings().add(link);
+ } else {
+ if (link.getInlineEntitySet() != null) {
+ List<String> bindings = new ArrayList<String>();
+ List<Entity> enities = link.getInlineEntitySet().getEntities();
+
+ for (Entity inlineEntity:enities) {
+ // check if this is reference
+ if (inlineEntity.getId() != null && inlineEntity.getProperties().isEmpty()) {
+ bindings.add(inlineEntity.getId().toASCIIString());
+ }
+ }
+ if (!bindings.isEmpty()) {
+ link.setInlineEntitySet(null);
+ link.setBindingLinks(bindings);
+ entity.getNavigationBindings().add(link);
+ } else {
+ entity.getNavigationLinks().add(link);
+ }
+ } else {
+ // add link
+ entity.getNavigationLinks().add(link);
+ }
+ }
+ } else if (link.getRel().startsWith(Constants.NS_ASSOCIATION_LINK_REL)) {
+ entity.getAssociationLinks().add(link);
+ } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) {
+ final Attribute metag = event.asStartElement().getAttributeByName(etagQName);
+ if (metag != null) {
+ link.setMediaETag(metag.getValue());
+ }
+ entity.getMediaEditLinks().add(link);
+ }
+ } else if (Constants.QNAME_ATOM_ELEM_CONTENT.equals(event.asStartElement().getName())) {
+ final Attribute contenttype = event.asStartElement()
+ .getAttributeByName(QName.valueOf(Constants.ATTR_TYPE));
+ if (contenttype == null || ContentType.APPLICATION_XML.toContentTypeString()
+ .equals(contenttype.getValue())) {
+ properties(reader, skipBeforeFirstStartElement(reader), entity, edmEntityType);
+ } else {
+ entity.setMediaContentType(contenttype.getValue());
+ final Attribute src = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATOM_ATTR_SRC));
+ if (src != null) {
+ entity.setMediaContentSource(URI.create(src.getValue()));
+ }
+ }
+ } else if (propertiesQName.equals(event.asStartElement().getName())) {
+ properties(reader, event.asStartElement(), entity, edmEntityType);
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndEntry = true;
+ }
+ }
+ }
+ return entity;
+ }
+
+ @Override
+ public DeserializerResult entity(InputStream input, EdmEntityType edmEntityType)
+ throws DeserializerException {
+ try {
+ final XMLEventReader reader = getReader(input);
+ final StartElement start = skipBeforeFirstStartElement(reader);
+ final Entity entity = entity(reader, start, edmEntityType);
+ if (entity == null) {
+ throw new DeserializerException("No entity found!", DeserializerException.MessageKeys.INVALID_ENTITY);
+ }
+ return DeserializerResultImpl.with().entity(entity)
+ .build();
+ } catch (XMLStreamException e) {
+ throw new DeserializerException(e.getMessage(), e,
+ DeserializerException.MessageKeys.IO_EXCEPTION);
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new DeserializerException(e.getMessage(), e,
+ DeserializerException.MessageKeys.INVALID_ENTITY);
+ }
+ }
+
+ private void count(final XMLEventReader reader, final StartElement start, final EntityCollection entitySet)
+ throws XMLStreamException {
+
+ boolean foundEndElement = false;
+ while (reader.hasNext() && !foundEndElement) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isCharacters() && !event.asCharacters().isWhiteSpace()) {
+ entitySet.setCount(Integer.valueOf(event.asCharacters().getData()));
+ }
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndElement = true;
+ }
+ }
+ }
+
+ private EntityCollection entitySet(final XMLEventReader reader, final StartElement start,
+ final EdmEntityType edmEntityType) throws XMLStreamException, EdmPrimitiveTypeException,
+ DeserializerException {
+ if (!Constants.QNAME_ATOM_ELEM_FEED.equals(start.getName())) {
+ return null;
+ }
+ final EntityCollection entitySet = new EntityCollection();
+ final Attribute xmlBase = start.getAttributeByName(Constants.QNAME_ATTR_XML_BASE);
+ if (xmlBase != null) {
+ entitySet.setBaseURI(URI.create(xmlBase.getValue()));
+ }
+
+ boolean foundEndFeed = false;
+ while (reader.hasNext() && !foundEndFeed) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isStartElement()) {
+ if (countQName.equals(event.asStartElement().getName())) {
+ count(reader, event.asStartElement(), entitySet);
+ } else if (Constants.QNAME_ATOM_ELEM_ID.equals(event.asStartElement().getName())) {
+ common(reader, event.asStartElement(), entitySet, "id");
+ } else if (Constants.QNAME_ATOM_ELEM_LINK.equals(event.asStartElement().getName())) {
+ final Attribute rel = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_REL));
+ if (rel != null) {
+ if (Constants.NEXT_LINK_REL.equals(rel.getValue())) {
+ final Attribute href = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_HREF));
+ if (href != null) {
+ entitySet.setNext(URI.create(href.getValue()));
+ }
+ }
+ if (Constants.NS_DELTA_LINK_REL.equals(rel.getValue())) {
+ final Attribute href = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_HREF));
+ if (href != null) {
+ entitySet.setDeltaLink(URI.create(href.getValue()));
+ }
+ }
+ }
+ } else if (Constants.QNAME_ATOM_ELEM_ENTRY.equals(event.asStartElement().getName())) {
+ entitySet.getEntities().add(entity(reader, event.asStartElement(), edmEntityType));
+ } else if (entryRefQName.equals(event.asStartElement().getName())) {
+ entitySet.getEntities().add(entityRef(event.asStartElement()));
+ }
+ }
+
+ if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
+ foundEndFeed = true;
+ }
+ }
+ return entitySet;
+ }
+
+ @Override
+ public DeserializerResult entityCollection(InputStream input, EdmEntityType edmEntityType)
+ throws DeserializerException {
+ try {
+ final XMLEventReader reader = getReader(input);
+ final StartElement start = skipBeforeFirstStartElement(reader);
+ EntityCollection entityCollection = entitySet(reader, start, edmEntityType);
+ for (Entity entity:entityCollection.getEntities()) {
+ entity.setType(edmEntityType.getFullQualifiedName().getFullQualifiedNameAsString());
+ }
+ return DeserializerResultImpl.with().entityCollection(entityCollection)
+ .build();
+ } catch (XMLStreamException e) {
+ throw new DeserializerException(e.getMessage(), e, DeserializerException.MessageKeys.IO_EXCEPTION);
+ } catch (final EdmPrimitiveTypeException e) {
+ throw new DeserializerException(e.getMessage(), e,
+ DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY);
+ }
+ }
+
+ @Override
+ public DeserializerResult entityReferences(InputStream stream) throws DeserializerException {
+ try {
+ XMLEventReader reader = getReader(stream);
+ ArrayList<URI> references = new ArrayList<URI>();
+
+ while (reader.hasNext()) {
+ final XMLEvent event = reader.nextEvent();
+ if (event.isStartElement()) {
+ StartElement start = event.asStartElement();
+ if (REF_ELEMENT.equals(start.getName())) {
+ Attribute context = start.getAttributeByName(ID_ATTR);
+ if (context == null) {
+ context = start.getAttributeByName(new QName("id"));
+ }
+ URI uri = URI.create(context.getValue());
+ references.add(uri);
+ }
+ }
+ }
+ return DeserializerResultImpl.with().entityReferences(references).build();
+ } catch (XMLStreamException e) {
+ throw new DeserializerException("An IOException occurred", e.getCause(),
+ DeserializerException.MessageKeys.IO_EXCEPTION);
+ }
+ }
+
+ @Override
+ public DeserializerResult actionParameters(InputStream stream, EdmAction edmAction)
+ throws DeserializerException {
+ throw new DeserializerException("Not implemented", DeserializerException.MessageKeys.NOT_IMPLEMENTED);
+ }
+}