From e4bf21325df8f96927096fa875ff1db5fda49662 Mon Sep 17 00:00:00 2001 From: fmartelli Date: Thu, 27 Mar 2014 15:41:09 +0100 Subject: [PATCH] [OLINGO-205] refactoring in order to add context url and metadata etag management --- .../communication/response/ODataResponse.java | 25 ++++++ .../api/domain/ODataEntitySetIterator.java | 6 +- .../api/op/ClientODataDeserializer.java | 3 +- .../client/api/op/CommonODataReader.java | 3 +- .../client/api/op/v3/ODataDeserializer.java | 3 +- .../retrieve/ODataEntityRequestImpl.java | 8 +- .../retrieve/ODataEntitySetRequestImpl.java | 14 ++-- .../request/retrieve/ODataRawRequestImpl.java | 10 ++- .../response/AbstractODataResponse.java | 40 ++++++++++ .../client/core/op/AbstractODataReader.java | 63 ++++++++++----- .../op/impl/v3/ODataDeserializerImpl.java | 14 ++-- .../core/op/impl/v3/ODataReaderImpl.java | 21 +++-- .../op/impl/v4/ODataDeserializerImpl.java | 7 +- .../core/op/impl/v4/ODataReaderImpl.java | 1 - .../client/core/AbstractPrimitiveTest.java | 4 +- .../olingo/client/core/AbstractTest.java | 2 - .../core/it/v3/QueryOptionsTestITCase.java | 2 +- .../core/it/v4/EntitySetTestITCase.java | 4 +- .../olingo/client/core/v3/AtomTest.java | 8 +- .../olingo/client/core/v3/EntitySetTest.java | 2 +- .../olingo/client/core/v3/EntityTest.java | 10 +-- .../apache/olingo/commons/api/Constants.java | 4 + .../olingo/commons/api/data/Container.java | 76 +++++++++++++++++++ .../api/op/CommonODataDeserializer.java | 8 +- .../commons/core/data/AbstractAtomDealer.java | 4 + .../commons/core/data/AbstractEntry.java | 2 +- ...omObject.java => AbstractODataObject.java} | 2 +- .../commons/core/data/AtomDeserializer.java | 61 ++++++++------- .../commons/core/data/AtomFeedImpl.java | 2 +- .../commons/core/data/AtomSerializer.java | 10 +-- .../core/op/AbstractODataDeserializer.java | 53 +++++++++---- 31 files changed, 344 insertions(+), 128 deletions(-) create mode 100644 lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Container.java rename lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/{AbstractAtomObject.java => AbstractODataObject.java} (97%) diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataResponse.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataResponse.java index 65434eccc..5498d1b57 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataResponse.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataResponse.java @@ -19,6 +19,7 @@ package org.apache.olingo.client.api.communication.response; import java.io.InputStream; +import java.net.URI; import java.util.Collection; import java.util.Map; import org.apache.olingo.client.api.communication.header.HeaderName; @@ -58,6 +59,30 @@ public interface ODataResponse { * @return ETag header value, if provided */ String getEtag(); + + /** + * The context URL describes the content of the payload. It consists of the canonical metadata document URL and a + * fragment identifying the relevant portion of the metadata document. + *
+ * Request payloads generally do not require context URLs as the type of the payload can generally be determined from + * the request URL. + *
+ * For details on how the context URL is used to describe a payload, see the relevant sections in the particular + * format. + * + * @return context URL. + */ + URI getContextURL(); + + /** + * An ETag header MAY also be returned on a metadata document request or service document request to allow the client + * subsequently to make a conditional request for the metadata or service document. Clients can also compare the value + * of the ETag header returned from a metadata document request to the metadata ETag returned in a response in order + * to verify the version of the metadata used to generate that response. + * + * @return metadata ETag. + */ + String getMetadataETag(); /** * Gets the content type. diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ODataEntitySetIterator.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ODataEntitySetIterator.java index 9d720bf42..e5eeeed73 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ODataEntitySetIterator.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ODataEntitySetIterator.java @@ -170,7 +170,7 @@ public class ODataEntitySetIterator implements Iterator { Entry jsonEntry = null; try { - int c = 0; + int c; boolean foundNewOne = false; @@ -203,7 +203,7 @@ public class ODataEntitySetIterator implements Iterator { if (c >= 0) { jsonEntry = odataClient.getDeserializer().toEntry( - new ByteArrayInputStream(entry.toByteArray()), ODataPubFormat.JSON); + new ByteArrayInputStream(entry.toByteArray()), ODataPubFormat.JSON).getObject(); } } else { while ((c = input.read()) >= 0) { @@ -237,7 +237,7 @@ public class ODataEntitySetIterator implements Iterator { if (consume(input, "", entry, true) >= 0) { atomEntry = odataClient.getDeserializer(). - toEntry(new ByteArrayInputStream(entry.toByteArray()), ODataPubFormat.ATOM); + toEntry(new ByteArrayInputStream(entry.toByteArray()), ODataPubFormat.ATOM).getObject(); } } } catch (Exception e) { diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/ClientODataDeserializer.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/ClientODataDeserializer.java index ad482fb33..24b6e60ff 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/ClientODataDeserializer.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/ClientODataDeserializer.java @@ -21,6 +21,7 @@ package org.apache.olingo.client.api.op; import java.io.InputStream; import org.apache.olingo.client.api.data.ServiceDocument; import org.apache.olingo.client.api.edm.xml.XMLMetadata; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.op.CommonODataDeserializer; @@ -35,5 +36,5 @@ public interface ClientODataDeserializer extends CommonODataDeserializer { * @param format OData service document format. * @return ServiceDocument object. */ - ServiceDocument toServiceDocument(InputStream input, ODataFormat format); + Container toServiceDocument(InputStream input, ODataFormat format); } diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataReader.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataReader.java index 9164918b1..f13e0ac0a 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataReader.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataReader.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.io.Serializable; import java.util.List; import org.apache.olingo.client.api.edm.xml.Schema; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.domain.ODataError; import org.apache.olingo.commons.api.domain.ODataEntity; import org.apache.olingo.commons.api.domain.ODataEntitySet; @@ -111,5 +112,5 @@ public interface CommonODataReader extends Serializable { * @param reference reference. * @return read object. */ - T read(InputStream src, String format, Class reference); + Container read(InputStream src, String format, Class reference); } diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/v3/ODataDeserializer.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/v3/ODataDeserializer.java index b12b104d4..bc16b74c4 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/v3/ODataDeserializer.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/v3/ODataDeserializer.java @@ -20,6 +20,7 @@ package org.apache.olingo.client.api.op.v3; import java.io.InputStream; import org.apache.olingo.client.api.op.ClientODataDeserializer; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.data.v3.LinkCollection; import org.apache.olingo.commons.api.format.ODataFormat; @@ -32,6 +33,6 @@ public interface ODataDeserializer extends ClientODataDeserializer { * @param format OData format. * @return de-serialized links. */ - LinkCollection toLinkCollection(InputStream input, ODataFormat format); + Container toLinkCollection(InputStream input, ODataFormat format); } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntityRequestImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntityRequestImpl.java index 447f54346..481d41e65 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntityRequestImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntityRequestImpl.java @@ -24,6 +24,8 @@ import org.apache.http.client.HttpClient; import org.apache.olingo.client.api.CommonODataClient; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.commons.api.data.Container; +import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.domain.ODataEntity; import org.apache.olingo.commons.api.format.ODataPubFormat; @@ -83,8 +85,10 @@ public class ODataEntityRequestImpl extends AbstractODataRetrieveRequest entry = + odataClient.getDeserializer().toEntry(getRawResponse(), ODataPubFormat.fromString(getContentType())); + + entity = odataClient.getBinder().getODataEntity(extractFromContainer(entry)); } finally { this.close(); } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntitySetRequestImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntitySetRequestImpl.java index ef191bad2..bb46ce8c2 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntitySetRequestImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataEntitySetRequestImpl.java @@ -24,6 +24,8 @@ import org.apache.http.client.HttpClient; import org.apache.olingo.client.api.CommonODataClient; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.commons.api.data.Container; +import org.apache.olingo.commons.api.data.Feed; import org.apache.olingo.commons.api.domain.ODataEntitySet; import org.apache.olingo.commons.api.format.ODataPubFormat; @@ -33,7 +35,7 @@ import org.apache.olingo.commons.api.format.ODataPubFormat; public class ODataEntitySetRequestImpl extends AbstractODataRetrieveRequest implements ODataEntitySetRequest { - private ODataEntitySet feed = null; + private ODataEntitySet entitySet = null; /** * Private constructor. @@ -83,15 +85,17 @@ public class ODataEntitySetRequestImpl extends AbstractODataRetrieveRequest feed = + odataClient.getDeserializer().toFeed(getRawResponse(), ODataPubFormat.fromString(getContentType())); + + entitySet = odataClient.getBinder().getODataEntitySet(extractFromContainer(feed)); } finally { this.close(); } } - return feed; + return entitySet; } } } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataRawRequestImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataRawRequestImpl.java index 0212048c2..09f4c1485 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataRawRequestImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/retrieve/ODataRawRequestImpl.java @@ -31,6 +31,7 @@ import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.client.api.http.HttpMethod; import org.apache.olingo.client.core.communication.request.ODataRequestImpl; import org.apache.olingo.client.core.communication.response.AbstractODataResponse; +import org.apache.olingo.commons.api.data.Container; /** * This class implements a generic OData request. @@ -92,10 +93,11 @@ public class ODataRawRequestImpl extends ODataRequestImpl this.close(); } } - - return odataClient.getReader().read(new ByteArrayInputStream(obj), getContentType(), reference); + + final Container container = + odataClient.getReader().read(new ByteArrayInputStream(obj), getContentType(), reference); + + return extractFromContainer(container); } - } - } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/response/AbstractODataResponse.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/response/AbstractODataResponse.java index 7b2790613..c571cd60f 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/response/AbstractODataResponse.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/response/AbstractODataResponse.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; +import java.net.URI; import java.util.Collection; import java.util.HashSet; import java.util.Map; @@ -37,6 +38,7 @@ import org.apache.olingo.client.api.communication.response.ODataResponse; import org.apache.olingo.client.api.http.NoContentException; import org.apache.olingo.client.core.communication.request.batch.ODataBatchController; import org.apache.olingo.client.core.communication.request.batch.ODataBatchUtilities; +import org.apache.olingo.commons.api.data.Container; import org.slf4j.LoggerFactory; /** @@ -49,6 +51,16 @@ public abstract class AbstractODataResponse implements ODataResponse { */ protected static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ODataResponse.class); + /** + * Context URL. + */ + private URI contextURL; + + /** + * Metadata ETag. + */ + private String metadataETag; + /** * HTTP client. */ @@ -133,6 +145,24 @@ public abstract class AbstractODataResponse implements ODataResponse { statusMessage = res.getStatusLine().getReasonPhrase(); } + @Override + public URI getContextURL() { + return contextURL; + } + + protected void setContextURL(final URI contextURL) { + this.contextURL = contextURL; + } + + @Override + public String getMetadataETag() { + return metadataETag; + } + + protected void setMetadataETag(final String metadataETag) { + this.metadataETag = metadataETag; + } + /** * {@inheritDoc} */ @@ -273,4 +303,14 @@ public abstract class AbstractODataResponse implements ODataResponse { return payload; } + + protected T extractFromContainer(final Container container) { + if (container == null) { + return null; + } + + setContextURL(container.getContextURL()); + setMetadataETag(container.getMetadataETag()); + return container.getObject(); + } } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataReader.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataReader.java index bd3695d76..ffc58e1ad 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataReader.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataReader.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.olingo.client.api.CommonODataClient; +import org.apache.olingo.client.api.data.ServiceDocument; import org.apache.olingo.commons.api.domain.ODataError; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.domain.ODataEntity; @@ -32,12 +33,15 @@ import org.apache.olingo.commons.api.domain.ODataProperty; import org.apache.olingo.commons.api.domain.ODataServiceDocument; import org.apache.olingo.commons.api.domain.ODataValue; import org.apache.olingo.client.api.edm.xml.XMLMetadata; +import org.apache.olingo.client.api.op.CommonODataReader; +import org.apache.olingo.client.core.edm.EdmClientImpl; +import org.apache.olingo.commons.api.data.Container; +import org.apache.olingo.commons.api.data.Entry; +import org.apache.olingo.commons.api.data.Feed; +import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.commons.api.format.ODataValueFormat; -import org.apache.olingo.client.api.op.CommonODataReader; -import org.apache.olingo.client.core.edm.EdmClientImpl; -import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,22 +73,23 @@ public abstract class AbstractODataReader implements CommonODataReader { @Override public ODataServiceDocument readServiceDocument(final InputStream input, final ODataFormat format) { - return client.getBinder().getODataServiceDocument(client.getDeserializer().toServiceDocument(input, format)); + return client.getBinder().getODataServiceDocument( + client.getDeserializer().toServiceDocument(input, format).getObject()); } @Override public ODataEntitySet readEntitySet(final InputStream input, final ODataPubFormat format) { - return client.getBinder().getODataEntitySet(client.getDeserializer().toFeed(input, format)); + return client.getBinder().getODataEntitySet(client.getDeserializer().toFeed(input, format).getObject()); } @Override public ODataEntity readEntity(final InputStream input, final ODataPubFormat format) { - return client.getBinder().getODataEntity(client.getDeserializer().toEntry(input, format)); + return client.getBinder().getODataEntity(client.getDeserializer().toEntry(input, format).getObject()); } @Override public ODataProperty readProperty(final InputStream input, final ODataFormat format) { - final Property property = client.getDeserializer().toProperty(input, format); + final Property property = client.getDeserializer().toProperty(input, format).getObject(); return client.getBinder().getODataProperty(property); } @@ -95,30 +100,48 @@ public abstract class AbstractODataReader implements CommonODataReader { @Override @SuppressWarnings("unchecked") - public T read(final InputStream src, final String format, final Class reference) { - Object res; + public Container read(final InputStream src, final String format, final Class reference) { + Container res; try { if (ODataEntitySetIterator.class.isAssignableFrom(reference)) { - res = new ODataEntitySetIterator(client, src, ODataPubFormat.fromString(format)); + res = new Container( + null, null, (T) new ODataEntitySetIterator(client, src, ODataPubFormat.fromString(format))); } else if (ODataEntitySet.class.isAssignableFrom(reference)) { - res = readEntitySet(src, ODataPubFormat.fromString(format)); + final Container container = client.getDeserializer().toFeed(src, ODataPubFormat.fromString(format)); + res = new Container( + container.getContextURL(), + container.getMetadataETag(), + (T) client.getBinder().getODataEntitySet(container.getObject())); } else if (ODataEntity.class.isAssignableFrom(reference)) { - res = readEntity(src, ODataPubFormat.fromString(format)); + final Container container = client.getDeserializer().toEntry(src, ODataPubFormat.fromString(format)); + res = new Container( + container.getContextURL(), + container.getMetadataETag(), + (T) client.getBinder().getODataEntity(container.getObject())); } else if (ODataProperty.class.isAssignableFrom(reference)) { - res = readProperty(src, ODataFormat.fromString(format)); + final Container container = client.getDeserializer().toProperty(src, ODataFormat.fromString(format)); + res = new Container( + container.getContextURL(), + container.getMetadataETag(), + (T) client.getBinder().getODataProperty(container.getObject())); } else if (ODataValue.class.isAssignableFrom(reference)) { - res = client.getPrimitiveValueBuilder(). + res = new Container(null, null, (T) client.getPrimitiveValueBuilder(). setType(ODataValueFormat.fromString(format) == ODataValueFormat.TEXT - ? EdmPrimitiveTypeKind.String : EdmPrimitiveTypeKind.Stream). + ? EdmPrimitiveTypeKind.String : EdmPrimitiveTypeKind.Stream). setText(IOUtils.toString(src)). - build(); + build()); } else if (XMLMetadata.class.isAssignableFrom(reference)) { - res = readMetadata(src); + res = new Container(null, null, (T) readMetadata(src)); } else if (ODataServiceDocument.class.isAssignableFrom(reference)) { - res = readServiceDocument(src, ODataFormat.fromString(format)); + final Container container = + client.getDeserializer().toServiceDocument(src, ODataFormat.fromString(format)); + res = new Container( + container.getContextURL(), + container.getMetadataETag(), + (T) client.getBinder().getODataServiceDocument(container.getObject())); } else if (ODataError.class.isAssignableFrom(reference)) { - res = readError(src, !format.toString().contains("json")); + res = new Container(null, null, (T) readError(src, !format.toString().contains("json"))); } else { throw new IllegalArgumentException("Invalid reference type " + reference); } @@ -131,6 +154,6 @@ public abstract class AbstractODataReader implements CommonODataReader { } } - return (T) res; + return res; } } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataDeserializerImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataDeserializerImpl.java index f88ae96e9..01bacbe01 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataDeserializerImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataDeserializerImpl.java @@ -31,6 +31,7 @@ import org.apache.olingo.client.core.data.v3.JSONServiceDocumentImpl; import org.apache.olingo.client.core.data.v4.XMLServiceDocumentImpl; import org.apache.olingo.client.core.edm.xml.v3.EdmxImpl; import org.apache.olingo.client.core.edm.xml.v3.XMLMetadataImpl; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.core.op.AbstractODataDeserializer; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; @@ -52,17 +53,16 @@ public class ODataDeserializerImpl extends AbstractODataDeserializer implements } @Override - public ServiceDocument toServiceDocument(final InputStream input, final ODataFormat format) { + public Container toServiceDocument(final InputStream input, final ODataFormat format) { return format == ODataFormat.XML - ? xml(input, XMLServiceDocumentImpl.class) - : json(input, JSONServiceDocumentImpl.class); + ? this.xml(input, XMLServiceDocumentImpl.class) + : this.json(input, JSONServiceDocumentImpl.class); } @Override - public LinkCollection toLinkCollection(final InputStream input, final ODataFormat format) { + public Container toLinkCollection(final InputStream input, final ODataFormat format) { return format == ODataFormat.XML - ? atom(input, XMLLinkCollectionImpl.class) - : json(input, JSONLinkCollectionImpl.class); + ? this.atom(input, XMLLinkCollectionImpl.class) + : this.json(input, JSONLinkCollectionImpl.class); } - } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataReaderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataReaderImpl.java index beb69b95f..b9cf6deda 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataReaderImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataReaderImpl.java @@ -25,6 +25,8 @@ import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.client.api.op.v3.ODataReader; import org.apache.olingo.client.api.v3.ODataClient; import org.apache.olingo.client.core.op.AbstractODataReader; +import org.apache.olingo.commons.api.data.Container; +import org.apache.olingo.commons.api.data.v3.LinkCollection; public class ODataReaderImpl extends AbstractODataReader implements ODataReader { @@ -37,15 +39,22 @@ public class ODataReaderImpl extends AbstractODataReader implements ODataReader @Override public ODataLinkCollection readLinks(final InputStream input, final ODataFormat format) { return ((ODataClient) client).getBinder().getLinkCollection( - ((ODataClient) client).getDeserializer().toLinkCollection(input, format)); + ((ODataClient) client).getDeserializer().toLinkCollection(input, format).getObject()); } @Override @SuppressWarnings("unchecked") - public T read(final InputStream src, final String format, final Class reference) { - return (ODataLinkCollection.class.isAssignableFrom(reference) - ? (T) readLinks(src, ODataFormat.fromString(format)) - : super.read(src, format, reference)); - } + public Container read(final InputStream src, final String format, final Class reference) { + if (ODataLinkCollection.class.isAssignableFrom(reference)) { + final Container container = + ((ODataClient) client).getDeserializer().toLinkCollection(src, ODataFormat.fromString(format)); + return new Container( + container.getContextURL(), + container.getMetadataETag(), + (T) ((ODataClient) client).getBinder().getLinkCollection(container.getObject())); + } else { + return super.read(src, format, reference); + } + } } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataDeserializerImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataDeserializerImpl.java index f9368537a..08d35568b 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataDeserializerImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataDeserializerImpl.java @@ -28,6 +28,7 @@ import org.apache.olingo.client.core.data.v4.JSONServiceDocumentImpl; import org.apache.olingo.client.core.data.v4.XMLServiceDocumentImpl; import org.apache.olingo.client.core.edm.xml.v4.EdmxImpl; import org.apache.olingo.client.core.edm.xml.v4.XMLMetadataImpl; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.core.op.AbstractODataDeserializer; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; @@ -49,10 +50,10 @@ public class ODataDeserializerImpl extends AbstractODataDeserializer implements } @Override - public ServiceDocument toServiceDocument(final InputStream input, final ODataFormat format) { + public Container toServiceDocument(final InputStream input, final ODataFormat format) { return format == ODataFormat.XML - ? xml(input, XMLServiceDocumentImpl.class) - : json(input, JSONServiceDocumentImpl.class); + ? this.xml(input, XMLServiceDocumentImpl.class) + : this.json(input, JSONServiceDocumentImpl.class); } } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataReaderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataReaderImpl.java index cb8958b68..93409630d 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataReaderImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataReaderImpl.java @@ -29,5 +29,4 @@ public class ODataReaderImpl extends AbstractODataReader implements ODataReader public ODataReaderImpl(final ODataClient client) { super(client); } - } diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractPrimitiveTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractPrimitiveTest.java index 04eb893fd..9a42d868a 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractPrimitiveTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractPrimitiveTest.java @@ -75,7 +75,9 @@ public abstract class AbstractPrimitiveTest extends AbstractTest { } protected ODataPrimitiveValue readPrimitiveValue(final InputStream input) { - final ODataProperty property = getClient().getReader().readProperty(input, getFormat()); + final ODataProperty property = getClient().getBinder().getODataProperty( + getClient().getDeserializer().toProperty(input, getFormat()).getObject()); + assertNotNull(property); assertTrue(property.hasPrimitiveValue()); assertNotNull(property.getPrimitiveValue()); diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractTest.java index 473b25e8c..04a5c9673 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/AbstractTest.java @@ -18,8 +18,6 @@ */ package org.apache.olingo.client.core; -import java.util.Locale; - import org.apache.olingo.client.api.CommonODataClient; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.format.ODataPubFormat; diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/QueryOptionsTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/QueryOptionsTestITCase.java index a3fe55e07..9f9c2c3f2 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/QueryOptionsTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/QueryOptionsTestITCase.java @@ -192,7 +192,7 @@ public class QueryOptionsTestITCase extends AbstractTestITCase { req.setFormat(ODataPubFormat.ATOM); final Entry atomEntry = - client.getDeserializer().toEntry(req.execute().getRawResponse(), ODataPubFormat.ATOM); + client.getDeserializer().toEntry(req.execute().getRawResponse(), ODataPubFormat.ATOM).getObject(); assertEquals("remotingdestructorprinterswitcheschannelssatellitelanguageresolve", ((AtomEntryImpl) atomEntry).getSummary()); } diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntitySetTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntitySetTestITCase.java index 473e7211a..2d78a6d8a 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntitySetTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntitySetTestITCase.java @@ -104,7 +104,7 @@ public class EntitySetTestITCase extends AbstractTestITCase { assertNotNull(feed); - assertTrue(feed.getContextURL().toASCIIString().endsWith("$metadata#People")); + assertTrue(res.getContextURL().toASCIIString().endsWith("$metadata#People")); debugFeed(client.getBinder().getFeed(feed, ResourceFactory.feedClassForFormat( ODataPubFormat.ATOM == format)), "Just retrieved feed"); @@ -153,6 +153,6 @@ public class EntitySetTestITCase extends AbstractTestITCase { final ODataEntitySet entitySet = res.getBodyAs(ODataEntitySet.class); assertNotNull(entitySet); - assertTrue(entitySet.getContextURL().toASCIIString().endsWith("$metadata#People")); + assertTrue(res.getContextURL().toASCIIString().endsWith("$metadata#People")); } } diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/AtomTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/AtomTest.java index 755b44b59..1be265bdd 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/AtomTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/AtomTest.java @@ -70,8 +70,7 @@ public class AtomTest extends AbstractTest { protected void feed(final String filename, final ODataPubFormat format) throws Exception { final StringWriter writer = new StringWriter(); getClient().getSerializer().feed(getClient().getDeserializer().toFeed( - getClass().getResourceAsStream("Customer." + getSuffix(format)), format), - writer); + getClass().getResourceAsStream("Customer." + getSuffix(format)), format).getObject(), writer); assertSimilar("Customer." + getSuffix(format), writer.toString()); } @@ -84,7 +83,7 @@ public class AtomTest extends AbstractTest { protected void entry(final String filename, final ODataPubFormat format) throws Exception { final StringWriter writer = new StringWriter(); getClient().getSerializer().entry(getClient().getDeserializer().toEntry( - getClass().getResourceAsStream(filename + "." + getSuffix(format)), format), writer); + getClass().getResourceAsStream(filename + "." + getSuffix(format)), format).getObject(), writer); assertSimilar(filename + "." + getSuffix(format), writer.toString()); } @@ -104,7 +103,7 @@ public class AtomTest extends AbstractTest { protected void property(final String filename, final ODataFormat format) throws Exception { final StringWriter writer = new StringWriter(); getClient().getSerializer().property(getClient().getDeserializer(). - toProperty(getClass().getResourceAsStream(filename + "." + getSuffix(format)), format), writer); + toProperty(getClass().getResourceAsStream(filename + "." + getSuffix(format)), format).getObject(), writer); assertSimilar(filename + "." + getSuffix(format), writer.toString()); } @@ -128,5 +127,4 @@ public class AtomTest extends AbstractTest { property("Product_-10_ComplexConcurrency_QueriedDateTime", getODataFormat()); property("Product_-10_Dimensions_Width", getODataFormat()); } - } diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntitySetTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntitySetTest.java index c6fd0d8df..0812c6d33 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntitySetTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntitySetTest.java @@ -40,7 +40,7 @@ public class EntitySetTest extends AbstractTest { private void read(final ODataPubFormat format) throws IOException { final InputStream input = getClass().getResourceAsStream("Customer." + getSuffix(format)); final ODataEntitySet entitySet = getClient().getBinder().getODataEntitySet( - getClient().getDeserializer().toFeed(input, format)); + getClient().getDeserializer().toFeed(input, format).getObject()); assertNotNull(entitySet); assertEquals(2, entitySet.getEntities().size()); diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntityTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntityTest.java index 151478ab9..80c56c2c6 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntityTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/EntityTest.java @@ -46,7 +46,7 @@ public class EntityTest extends AbstractTest { private void readAndWrite(final ODataPubFormat format) { final InputStream input = getClass().getResourceAsStream("Customer_-10." + getSuffix(format)); final ODataEntity entity = getClient().getBinder().getODataEntity( - getClient().getDeserializer().toEntry(input, format)); + getClient().getDeserializer().toEntry(input, format).getObject()); assertNotNull(entity); assertEquals("Microsoft.Test.OData.Services.AstoriaDefaultService.Customer", entity.getName()); @@ -82,7 +82,7 @@ public class EntityTest extends AbstractTest { private void readGeospatial(final ODataPubFormat format) { final InputStream input = getClass().getResourceAsStream("AllGeoTypesSet_-8." + getSuffix(format)); final ODataEntity entity = getClient().getBinder().getODataEntity( - getClient().getDeserializer().toEntry(input, format)); + getClient().getDeserializer().toEntry(input, format).getObject()); assertNotNull(entity); boolean found = false; @@ -114,7 +114,7 @@ public class EntityTest extends AbstractTest { private void withActions(final ODataPubFormat format) { final InputStream input = getClass().getResourceAsStream("ComputerDetail_-10." + getSuffix(format)); final ODataEntity entity = getClient().getBinder().getODataEntity( - getClient().getDeserializer().toEntry(input, format)); + getClient().getDeserializer().toEntry(input, format).getObject()); assertNotNull(entity); assertEquals(1, entity.getOperations().size()); @@ -140,7 +140,7 @@ public class EntityTest extends AbstractTest { private void mediaEntity(final ODataPubFormat format) { final InputStream input = getClass().getResourceAsStream("Car_16." + getSuffix(format)); final ODataEntity entity = getClient().getBinder().getODataEntity( - getClient().getDeserializer().toEntry(input, format)); + getClient().getDeserializer().toEntry(input, format).getObject()); assertNotNull(entity); assertTrue(entity.isMediaEntity()); assertNotNull(entity.getMediaContentSource()); @@ -164,7 +164,7 @@ public class EntityTest extends AbstractTest { private void issue128(final ODataPubFormat format) throws EdmPrimitiveTypeException { final InputStream input = getClass().getResourceAsStream("AllGeoTypesSet_-5." + getSuffix(format)); final ODataEntity entity = getClient().getBinder().getODataEntity( - getClient().getDeserializer().toEntry(input, format)); + getClient().getDeserializer().toEntry(input, format).getObject()); assertNotNull(entity); final ODataProperty geogCollection = entity.getProperty("GeogCollection"); diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java index 3b5b9cc36..39d961432 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java @@ -141,6 +141,8 @@ public interface Constants { public final static String JSON_METADATA = "odata.metadata"; + public final static String JSON_METADATA_ETAG = "@odata.metadataEtag"; + public final static String JSON_TYPE = "odata.type"; public final static String JSON_TYPE_SUFFIX = "@" + JSON_TYPE; @@ -248,4 +250,6 @@ public interface Constants { public static final String ATOM_ATTR_ETAG = "etag"; + public static final String ATOM_ATTR_METADATAETAG = "metadata-etag"; + } diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Container.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Container.java new file mode 100644 index 000000000..be3476b64 --- /dev/null +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Container.java @@ -0,0 +1,76 @@ +/* + * 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.commons.api.data; + +import java.net.URI; + +/** + * Outermost response object container. + */ +public class Container { + + private final URI contextURL; + + private final String metadataETag; + + private final T object; + + public Container(final URI contextURL, final String metadataETag, final T object) { + this.contextURL = contextURL; + this.metadataETag = metadataETag; + this.object = object; + } + + /** + * The context URL describes the content of the payload. It consists of the canonical metadata document URL and a + * fragment identifying the relevant portion of the metadata document. + *
+ * Request payloads generally do not require context URLs as the type of the payload can generally be determined from + * the request URL. + *
+ * For details on how the context URL is used to describe a payload, see the relevant sections in the particular + * format. + * + * @return context URL. + */ + public URI getContextURL() { + return contextURL; + } + + /** + * An ETag header MAY also be returned on a metadata document request or service document request to allow the client + * subsequently to make a conditional request for the metadata or service document. Clients can also compare the value + * of the ETag header returned from a metadata document request to the metadata ETag returned in a response in order + * to verify the version of the metadata used to generate that response. + * + * @return metadata ETag. + */ + public String getMetadataETag() { + return metadataETag; + } + + /** + * Gets contained object. + * + * @return contained object. + */ + public T getObject() { + return object; + } +} diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/op/CommonODataDeserializer.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/op/CommonODataDeserializer.java index dfefb7890..4b30ddd0c 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/op/CommonODataDeserializer.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/op/CommonODataDeserializer.java @@ -20,6 +20,7 @@ package org.apache.olingo.commons.api.op; import java.io.InputStream; import java.io.Serializable; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.domain.ODataError; import org.apache.olingo.commons.api.data.Feed; @@ -39,7 +40,7 @@ public interface CommonODataDeserializer extends Serializable { * @param format Atom or JSON * @return Feed instance. */ - Feed toFeed(InputStream input, ODataPubFormat format); + Container toFeed(InputStream input, ODataPubFormat format); /** * Gets an entry object from the given InputStream. @@ -48,7 +49,7 @@ public interface CommonODataDeserializer extends Serializable { * @param format Atom or JSON * @return Entry instance. */ - Entry toEntry(InputStream input, ODataPubFormat format); + Container toEntry(InputStream input, ODataPubFormat format); /** * Gets a property object from the given InputStream. @@ -57,7 +58,7 @@ public interface CommonODataDeserializer extends Serializable { * @param format XML or JSON * @return Property instance. */ - Property toProperty(InputStream input, ODataFormat format); + Container toProperty(InputStream input, ODataFormat format); /** * Gets the ODataError object represented by the given InputStream. @@ -67,5 +68,4 @@ public interface CommonODataDeserializer extends Serializable { * @return */ ODataError toError(InputStream input, boolean isXML); - } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomDealer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomDealer.java index d4cf40a85..e258219cd 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomDealer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomDealer.java @@ -34,6 +34,8 @@ abstract class AbstractAtomDealer { protected final QName etagQName; + protected final QName metadataEtagQName; + protected final QName inlineQName; protected final QName actionQName; @@ -63,6 +65,8 @@ abstract class AbstractAtomDealer { this.etagQName = new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.ATOM_ATTR_ETAG); + this.metadataEtagQName = + new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.ATOM_ATTR_METADATAETAG); this.inlineQName = new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.ATOM_ELEM_INLINE); this.actionQName = diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntry.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntry.java index 29a4a75f7..85d677511 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntry.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntry.java @@ -29,7 +29,7 @@ import org.apache.olingo.commons.api.domain.ODataOperation; /** * Abstract base for classes implementing an OData entry in Atom and JSON. */ -public abstract class AbstractEntry extends AbstractAtomObject implements Entry { +public abstract class AbstractEntry extends AbstractODataObject implements Entry { private static final long serialVersionUID = 2127764552600969783L; diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomObject.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataObject.java similarity index 97% rename from lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomObject.java rename to lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataObject.java index 2436e3e68..3bcef747e 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractAtomObject.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataObject.java @@ -23,7 +23,7 @@ import java.net.URI; import java.text.ParseException; import java.util.Date; -abstract class AbstractAtomObject extends AbstractPayloadObject { +abstract class AbstractODataObject extends AbstractPayloadObject { private static final long serialVersionUID = -4391162864875546927L; diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java index 9a4eac1ab..d863eb6f5 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java @@ -18,6 +18,7 @@ */ package org.apache.olingo.commons.core.data; +import org.apache.olingo.commons.api.data.Container; import java.io.InputStream; import java.net.URI; import java.text.ParseException; @@ -40,7 +41,7 @@ public class AtomDeserializer extends AbstractAtomDealer { private static final Logger LOG = LoggerFactory.getLogger(AtomDeserializer.class); - private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance(); + public static final XMLInputFactory FACTORY = XMLInputFactory.newInstance(); private final AtomPropertyDeserializer propDeserializer; @@ -49,12 +50,13 @@ public class AtomDeserializer extends AbstractAtomDealer { this.propDeserializer = new AtomPropertyDeserializer(version); } - private AtomPropertyImpl property(final InputStream input) throws XMLStreamException { + private Container property(final InputStream input) throws XMLStreamException { final XMLEventReader reader = FACTORY.createXMLEventReader(input); - return propDeserializer.deserialize(reader, skipBeforeFirstStartElement(reader)); + final StartElement start = skipBeforeFirstStartElement(reader); + return getContainer(start, propDeserializer.deserialize(reader, start)); } - private StartElement skipBeforeFirstStartElement(final XMLEventReader reader) throws XMLStreamException { + public StartElement skipBeforeFirstStartElement(final XMLEventReader reader) throws XMLStreamException { StartElement startEvent = null; while (reader.hasNext() && startEvent == null) { final XMLEvent event = reader.nextEvent(); @@ -70,7 +72,7 @@ public class AtomDeserializer extends AbstractAtomDealer { } private void common(final XMLEventReader reader, final StartElement start, - final AbstractAtomObject object, final String key) throws XMLStreamException { + final AbstractODataObject object, final String key) throws XMLStreamException { boolean foundEndElement = false; while (reader.hasNext() && !foundEndElement) { @@ -123,8 +125,14 @@ public class AtomDeserializer extends AbstractAtomDealer { } } - private XMLLinkCollectionImpl linkCollection(final InputStream input) throws XMLStreamException { + private Container linkCollection(final InputStream input) throws XMLStreamException { final XMLEventReader reader = FACTORY.createXMLEventReader(input); + final StartElement start = skipBeforeFirstStartElement(reader); + return getContainer(start, linkCollection(reader, start)); + } + + private XMLLinkCollectionImpl linkCollection(final XMLEventReader reader, final StartElement start) + throws XMLStreamException { final XMLLinkCollectionImpl linkCollection = new XMLLinkCollectionImpl(); @@ -178,8 +186,6 @@ public class AtomDeserializer extends AbstractAtomDealer { entry.setBaseURI(xmlBase.getValue()); } - entry.setContextURL(retrieveContextURL(start, entry.getBaseURI())); - final Attribute etag = start.getAttributeByName(etagQName); if (etag != null) { entry.setETag(etag.getValue()); @@ -291,7 +297,6 @@ public class AtomDeserializer extends AbstractAtomDealer { private AtomEntryImpl entryRef(final StartElement start) throws XMLStreamException { final AtomEntryImpl entry = new AtomEntryImpl(); - entry.setContextURL(retrieveContextURL(start, null)); final Attribute entryRefId = start.getAttributeByName(Constants.QNAME_ATOM_ELEM_ENTRY_REF_ID); @@ -302,9 +307,10 @@ public class AtomDeserializer extends AbstractAtomDealer { return entry; } - private AtomEntryImpl entry(final InputStream input) throws XMLStreamException { + private Container entry(final InputStream input) throws XMLStreamException { final XMLEventReader reader = FACTORY.createXMLEventReader(input); - return entry(reader, skipBeforeFirstStartElement(reader)); + final StartElement start = skipBeforeFirstStartElement(reader); + return getContainer(start, entry(reader, start)); } private void count(final XMLEventReader reader, final StartElement start, final AtomFeedImpl feed) @@ -328,15 +334,12 @@ public class AtomDeserializer extends AbstractAtomDealer { if (!Constants.QNAME_ATOM_ELEM_FEED.equals(start.getName())) { return null; } - final AtomFeedImpl feed = new AtomFeedImpl(); final Attribute xmlBase = start.getAttributeByName(Constants.QNAME_ATTR_XML_BASE); if (xmlBase != null) { feed.setBaseURI(xmlBase.getValue()); } - feed.setContextURL(retrieveContextURL(start, feed.getBaseURI())); - boolean foundEndFeed = false; while (reader.hasNext() && !foundEndFeed) { final XMLEvent event = reader.nextEvent(); @@ -372,34 +375,34 @@ public class AtomDeserializer extends AbstractAtomDealer { return feed; } - private AtomFeedImpl feed(final InputStream input) throws XMLStreamException { + private Container feed(final InputStream input) throws XMLStreamException { final XMLEventReader reader = FACTORY.createXMLEventReader(input); - return feed(reader, skipBeforeFirstStartElement(reader)); + final StartElement start = skipBeforeFirstStartElement(reader); + return getContainer(start, feed(reader, start)); } @SuppressWarnings("unchecked") - public T read(final InputStream input, final Class reference) throws XMLStreamException { + public Container read(final InputStream input, final Class reference) + throws XMLStreamException { if (AtomFeedImpl.class.equals(reference)) { - return (T) feed(input); + return (Container) feed(input); } else if (AtomEntryImpl.class.equals(reference)) { - return (T) entry(input); + return (Container) entry(input); } else if (AtomPropertyImpl.class.equals(reference)) { - return (T) property(input); + return (Container) property(input); } else if (XMLLinkCollectionImpl.class.equals(reference)) { - return (T) linkCollection(input); + return (Container) linkCollection(input); } return null; } - private URI retrieveContextURL(final StartElement start, final URI base) { + public Container getContainer(final StartElement start, final T object) { final Attribute context = start.getAttributeByName(contextQName); + final Attribute metadataETag = start.getAttributeByName(metadataEtagQName); - if (context == null) { - return base == null - ? null - : URI.create(base.toASCIIString() + "/" + Constants.METADATA); - } else { - return URI.create(context.getValue()); - } + return new Container( + context == null ? null : URI.create(context.getValue()), + metadataETag == null ? null : metadataETag.getValue(), + object); } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomFeedImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomFeedImpl.java index d40f94529..09dfdcfe1 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomFeedImpl.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomFeedImpl.java @@ -29,7 +29,7 @@ import org.apache.olingo.commons.api.data.Feed; * * @see AtomEntry */ -public class AtomFeedImpl extends AbstractAtomObject implements Feed { +public class AtomFeedImpl extends AbstractODataObject implements Feed { private static final long serialVersionUID = 5466590540021319153L; diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java index 8bab108ff..4bcd3bff7 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java @@ -104,7 +104,7 @@ public class AtomSerializer extends AbstractAtomDealer { } } - private void common(final XMLStreamWriter writer, final AbstractAtomObject object) throws XMLStreamException { + private void common(final XMLStreamWriter writer, final AbstractODataObject object) throws XMLStreamException { if (StringUtils.isNotBlank(object.getTitle())) { writer.writeStartElement(Constants.ATOM_ELEM_TITLE); writer.writeAttribute(Constants.ATTR_TYPE, TYPE_TEXT); @@ -149,8 +149,8 @@ public class AtomSerializer extends AbstractAtomDealer { writer.writeAttribute(Constants.ATOM_ATTR_TERM, entry.getType()); writer.writeEndElement(); - if (entry instanceof AbstractAtomObject) { - common(writer, (AbstractAtomObject) entry); + if (entry instanceof AbstractODataObject) { + common(writer, (AbstractODataObject) entry); } links(writer, entry.getAssociationLinks()); @@ -215,8 +215,8 @@ public class AtomSerializer extends AbstractAtomDealer { writer.writeEndElement(); } - if (feed instanceof AbstractAtomObject) { - common(writer, (AbstractAtomObject) feed); + if (feed instanceof AbstractODataObject) { + common(writer, (AbstractODataObject) feed); } for (Entry entry : feed.getEntries()) { diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/op/AbstractODataDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/op/AbstractODataDeserializer.java index 991e72329..99d4c5c6f 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/op/AbstractODataDeserializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/op/AbstractODataDeserializer.java @@ -18,7 +18,13 @@ */ package org.apache.olingo.commons.core.op; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.InputStream; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.events.StartElement; import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.domain.ODataError; import org.apache.olingo.commons.api.data.Feed; @@ -28,6 +34,7 @@ import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.apache.olingo.commons.api.op.CommonODataDeserializer; import org.apache.olingo.commons.core.data.AtomDeserializer; +import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.core.data.AtomEntryImpl; import org.apache.olingo.commons.core.data.AtomFeedImpl; import org.apache.olingo.commons.core.data.AtomPropertyImpl; @@ -50,45 +57,59 @@ public abstract class AbstractODataDeserializer extends AbstractJacksonTool impl } @Override - public Feed toFeed(final InputStream input, final ODataPubFormat format) { + public Container toFeed(final InputStream input, final ODataPubFormat format) { return format == ODataPubFormat.ATOM - ? atom(input, AtomFeedImpl.class) - : json(input, JSONFeedImpl.class); + ? this.atom(input, AtomFeedImpl.class) + : this.json(input, JSONFeedImpl.class); } @Override - public Entry toEntry(final InputStream input, final ODataPubFormat format) { + public Container toEntry(final InputStream input, final ODataPubFormat format) { return format == ODataPubFormat.ATOM - ? atom(input, AtomEntryImpl.class) - : json(input, JSONEntryImpl.class); + ? this.atom(input, AtomEntryImpl.class) + : this.json(input, JSONEntryImpl.class); } @Override - public Property toProperty(final InputStream input, final ODataFormat format) { + public Container toProperty(final InputStream input, final ODataFormat format) { return format == ODataFormat.XML - ? atom(input, AtomPropertyImpl.class) - : json(input, JSONPropertyImpl.class); + ? this.atom(input, AtomPropertyImpl.class) + : this.json(input, JSONPropertyImpl.class); } @Override public ODataError toError(final InputStream input, final boolean isXML) { return isXML - ? xml(input, XMLErrorImpl.class) - : json(input, JSONErrorBundle.class).getError(); + ? this.xml(input, XMLErrorImpl.class).getObject() + : this.json(input, JSONErrorBundle.class).getObject().getError(); } /* * ------------------ Protected methods ------------------ */ - protected T xml(final InputStream input, final Class reference) { + @SuppressWarnings("unchecked") + protected Container xml(final InputStream input, final Class reference) { try { - return getXmlMapper().readValue(input, reference); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + final XMLEventReader reader = AtomDeserializer.FACTORY.createXMLEventReader(input); + final StartElement start = atomDeserializer.skipBeforeFirstStartElement(reader); + + final XMLEventWriter writer = XMLOutputFactory.newFactory().createXMLEventWriter(bos); + writer.add(start); + writer.add(reader); + writer.flush(); + writer.close(); + + return (Container) atomDeserializer.getContainer( + start, getXmlMapper().readValue(new ByteArrayInputStream(bos.toByteArray()), reference)); + } catch (Exception e) { throw new IllegalArgumentException("While deserializing " + reference.getName(), e); } } - protected T atom(final InputStream input, final Class reference) { + protected Container atom(final InputStream input, final Class reference) { try { return atomDeserializer.read(input, reference); } catch (Exception e) { @@ -96,9 +117,9 @@ public abstract class AbstractODataDeserializer extends AbstractJacksonTool impl } } - protected T json(final InputStream input, final Class reference) { + protected Container json(final InputStream input, final Class reference) { try { - return getObjectMapper().readValue(input, reference); + return new Container(null, null, getObjectMapper().readValue(input, reference)); } catch (Exception e) { throw new IllegalArgumentException("While deserializing " + reference.getName(), e); }