[OLINGO-205] refactoring in order to add context url and metadata etag management

This commit is contained in:
fmartelli 2014-03-27 15:41:09 +01:00
parent cde94fc09b
commit e4bf21325d
31 changed files with 344 additions and 128 deletions

View File

@ -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.
* <br />
* Request payloads generally do not require context URLs as the type of the payload can generally be determined from
* the request URL.
* <br />
* 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.

View File

@ -170,7 +170,7 @@ public class ODataEntitySetIterator implements Iterator<ODataEntity> {
Entry jsonEntry = null;
try {
int c = 0;
int c;
boolean foundNewOne = false;
@ -203,7 +203,7 @@ public class ODataEntitySetIterator implements Iterator<ODataEntity> {
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<ODataEntity> {
if (consume(input, "</entry>", entry, true) >= 0) {
atomEntry = odataClient.getDeserializer().
toEntry(new ByteArrayInputStream(entry.toByteArray()), ODataPubFormat.ATOM);
toEntry(new ByteArrayInputStream(entry.toByteArray()), ODataPubFormat.ATOM).getObject();
}
}
} catch (Exception e) {

View File

@ -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 <tt>ServiceDocument</tt> object.
*/
ServiceDocument toServiceDocument(InputStream input, ODataFormat format);
Container<ServiceDocument> toServiceDocument(InputStream input, ODataFormat format);
}

View File

@ -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> T read(InputStream src, String format, Class<T> reference);
<T> Container<T> read(InputStream src, String format, Class<T> reference);
}

View File

@ -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<LinkCollection> toLinkCollection(InputStream input, ODataFormat format);
}

View File

@ -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<ODataEn
public ODataEntity getBody() {
if (entity == null) {
try {
entity = odataClient.getReader().
readEntity(getRawResponse(), ODataPubFormat.fromString(getContentType()));
final Container<Entry> entry =
odataClient.getDeserializer().toEntry(getRawResponse(), ODataPubFormat.fromString(getContentType()));
entity = odataClient.getBinder().getODataEntity(extractFromContainer(entry));
} finally {
this.close();
}

View File

@ -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<ODataEntitySet, ODataPubFormat>
implements ODataEntitySetRequest {
private ODataEntitySet feed = null;
private ODataEntitySet entitySet = null;
/**
* Private constructor.
@ -83,15 +85,17 @@ public class ODataEntitySetRequestImpl extends AbstractODataRetrieveRequest<ODat
@Override
@SuppressWarnings("unchecked")
public ODataEntitySet getBody() {
if (feed == null) {
if (entitySet == null) {
try {
feed = odataClient.getReader().
readEntitySet(getRawResponse(), ODataPubFormat.fromString(getContentType()));
final Container<Feed> feed =
odataClient.getDeserializer().toFeed(getRawResponse(), ODataPubFormat.fromString(getContentType()));
entitySet = odataClient.getBinder().getODataEntitySet(extractFromContainer(feed));
} finally {
this.close();
}
}
return feed;
return entitySet;
}
}
}

View File

@ -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<ODataPubFormat>
this.close();
}
}
return odataClient.getReader().read(new ByteArrayInputStream(obj), getContentType(), reference);
final Container<T> container =
odataClient.getReader().read(new ByteArrayInputStream(obj), getContentType(), reference);
return extractFromContainer(container);
}
}
}

View File

@ -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> T extractFromContainer(final Container<T> container) {
if (container == null) {
return null;
}
setContextURL(container.getContextURL());
setMetadataETag(container.getMetadataETag());
return container.getObject();
}
}

View File

@ -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> T read(final InputStream src, final String format, final Class<T> reference) {
Object res;
public <T> Container<T> read(final InputStream src, final String format, final Class<T> reference) {
Container<T> res;
try {
if (ODataEntitySetIterator.class.isAssignableFrom(reference)) {
res = new ODataEntitySetIterator(client, src, ODataPubFormat.fromString(format));
res = new Container<T>(
null, null, (T) new ODataEntitySetIterator(client, src, ODataPubFormat.fromString(format)));
} else if (ODataEntitySet.class.isAssignableFrom(reference)) {
res = readEntitySet(src, ODataPubFormat.fromString(format));
final Container<Feed> container = client.getDeserializer().toFeed(src, ODataPubFormat.fromString(format));
res = new Container<T>(
container.getContextURL(),
container.getMetadataETag(),
(T) client.getBinder().getODataEntitySet(container.getObject()));
} else if (ODataEntity.class.isAssignableFrom(reference)) {
res = readEntity(src, ODataPubFormat.fromString(format));
final Container<Entry> container = client.getDeserializer().toEntry(src, ODataPubFormat.fromString(format));
res = new Container<T>(
container.getContextURL(),
container.getMetadataETag(),
(T) client.getBinder().getODataEntity(container.getObject()));
} else if (ODataProperty.class.isAssignableFrom(reference)) {
res = readProperty(src, ODataFormat.fromString(format));
final Container<Property> container = client.getDeserializer().toProperty(src, ODataFormat.fromString(format));
res = new Container<T>(
container.getContextURL(),
container.getMetadataETag(),
(T) client.getBinder().getODataProperty(container.getObject()));
} else if (ODataValue.class.isAssignableFrom(reference)) {
res = client.getPrimitiveValueBuilder().
res = new Container<T>(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<T>(null, null, (T) readMetadata(src));
} else if (ODataServiceDocument.class.isAssignableFrom(reference)) {
res = readServiceDocument(src, ODataFormat.fromString(format));
final Container<ServiceDocument> container =
client.getDeserializer().toServiceDocument(src, ODataFormat.fromString(format));
res = new Container<T>(
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<T>(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;
}
}

View File

@ -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<ServiceDocument> toServiceDocument(final InputStream input, final ODataFormat format) {
return format == ODataFormat.XML
? xml(input, XMLServiceDocumentImpl.class)
: json(input, JSONServiceDocumentImpl.class);
? this.<ServiceDocument, XMLServiceDocumentImpl>xml(input, XMLServiceDocumentImpl.class)
: this.<ServiceDocument, JSONServiceDocumentImpl>json(input, JSONServiceDocumentImpl.class);
}
@Override
public LinkCollection toLinkCollection(final InputStream input, final ODataFormat format) {
public Container<LinkCollection> toLinkCollection(final InputStream input, final ODataFormat format) {
return format == ODataFormat.XML
? atom(input, XMLLinkCollectionImpl.class)
: json(input, JSONLinkCollectionImpl.class);
? this.<LinkCollection, XMLLinkCollectionImpl>atom(input, XMLLinkCollectionImpl.class)
: this.<LinkCollection, JSONLinkCollectionImpl>json(input, JSONLinkCollectionImpl.class);
}
}

View File

@ -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> T read(final InputStream src, final String format, final Class<T> reference) {
return (ODataLinkCollection.class.isAssignableFrom(reference)
? (T) readLinks(src, ODataFormat.fromString(format))
: super.read(src, format, reference));
}
public <T> Container<T> read(final InputStream src, final String format, final Class<T> reference) {
if (ODataLinkCollection.class.isAssignableFrom(reference)) {
final Container<LinkCollection> container =
((ODataClient) client).getDeserializer().toLinkCollection(src, ODataFormat.fromString(format));
return new Container<T>(
container.getContextURL(),
container.getMetadataETag(),
(T) ((ODataClient) client).getBinder().getLinkCollection(container.getObject()));
} else {
return super.read(src, format, reference);
}
}
}

View File

@ -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<ServiceDocument> toServiceDocument(final InputStream input, final ODataFormat format) {
return format == ODataFormat.XML
? xml(input, XMLServiceDocumentImpl.class)
: json(input, JSONServiceDocumentImpl.class);
? this.<ServiceDocument, XMLServiceDocumentImpl>xml(input, XMLServiceDocumentImpl.class)
: this.<ServiceDocument, JSONServiceDocumentImpl>json(input, JSONServiceDocumentImpl.class);
}
}

View File

@ -29,5 +29,4 @@ public class ODataReaderImpl extends AbstractODataReader implements ODataReader
public ODataReaderImpl(final ODataClient client) {
super(client);
}
}

View File

@ -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());

View File

@ -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;

View File

@ -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());
}

View File

@ -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"));
}
}

View File

@ -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());
}
}

View File

@ -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());

View File

@ -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");

View File

@ -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";
}

View File

@ -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<T> {
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.
* <br />
* Request payloads generally do not require context URLs as the type of the payload can generally be determined from
* the request URL.
* <br />
* 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;
}
}

View File

@ -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<Feed> 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<Entry> 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<Property> 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);
}

View File

@ -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 =

View File

@ -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;

View File

@ -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;

View File

@ -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<AtomPropertyImpl> 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<XMLLinkCollectionImpl> 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<AtomEntryImpl> 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<AtomFeedImpl> 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> T read(final InputStream input, final Class<T> reference) throws XMLStreamException {
public <T, V extends T> Container<T> read(final InputStream input, final Class<V> reference)
throws XMLStreamException {
if (AtomFeedImpl.class.equals(reference)) {
return (T) feed(input);
return (Container<T>) feed(input);
} else if (AtomEntryImpl.class.equals(reference)) {
return (T) entry(input);
return (Container<T>) entry(input);
} else if (AtomPropertyImpl.class.equals(reference)) {
return (T) property(input);
return (Container<T>) property(input);
} else if (XMLLinkCollectionImpl.class.equals(reference)) {
return (T) linkCollection(input);
return (Container<T>) linkCollection(input);
}
return null;
}
private URI retrieveContextURL(final StartElement start, final URI base) {
public <T> Container<T> 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<T>(
context == null ? null : URI.create(context.getValue()),
metadataETag == null ? null : metadataETag.getValue(),
object);
}
}

View File

@ -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;

View File

@ -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()) {

View File

@ -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<Feed> toFeed(final InputStream input, final ODataPubFormat format) {
return format == ODataPubFormat.ATOM
? atom(input, AtomFeedImpl.class)
: json(input, JSONFeedImpl.class);
? this.<Feed, AtomFeedImpl>atom(input, AtomFeedImpl.class)
: this.<Feed, JSONFeedImpl>json(input, JSONFeedImpl.class);
}
@Override
public Entry toEntry(final InputStream input, final ODataPubFormat format) {
public Container<Entry> toEntry(final InputStream input, final ODataPubFormat format) {
return format == ODataPubFormat.ATOM
? atom(input, AtomEntryImpl.class)
: json(input, JSONEntryImpl.class);
? this.<Entry, AtomEntryImpl>atom(input, AtomEntryImpl.class)
: this.<Entry, JSONEntryImpl>json(input, JSONEntryImpl.class);
}
@Override
public Property toProperty(final InputStream input, final ODataFormat format) {
public Container<Property> toProperty(final InputStream input, final ODataFormat format) {
return format == ODataFormat.XML
? atom(input, AtomPropertyImpl.class)
: json(input, JSONPropertyImpl.class);
? this.<Property, AtomPropertyImpl>atom(input, AtomPropertyImpl.class)
: this.<Property, JSONPropertyImpl>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.<ODataError, XMLErrorImpl>xml(input, XMLErrorImpl.class).getObject()
: this.<JSONErrorBundle, JSONErrorBundle>json(input, JSONErrorBundle.class).getObject().getError();
}
/*
* ------------------ Protected methods ------------------
*/
protected <T> T xml(final InputStream input, final Class<T> reference) {
@SuppressWarnings("unchecked")
protected <T, V extends T> Container<T> xml(final InputStream input, final Class<V> 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<T>) atomDeserializer.getContainer(
start, getXmlMapper().readValue(new ByteArrayInputStream(bos.toByteArray()), reference));
} catch (Exception e) {
throw new IllegalArgumentException("While deserializing " + reference.getName(), e);
}
}
protected <T> T atom(final InputStream input, final Class<T> reference) {
protected <T, V extends T> Container<T> atom(final InputStream input, final Class<V> reference) {
try {
return atomDeserializer.read(input, reference);
} catch (Exception e) {
@ -96,9 +117,9 @@ public abstract class AbstractODataDeserializer extends AbstractJacksonTool impl
}
}
protected <T> T json(final InputStream input, final Class<T> reference) {
protected <T, V extends T> Container<T> json(final InputStream input, final Class<V> reference) {
try {
return getObjectMapper().readValue(input, reference);
return new Container<T>(null, null, getObjectMapper().readValue(input, reference));
} catch (Exception e) {
throw new IllegalArgumentException("While deserializing " + reference.getName(), e);
}