[OLINGO-663] metadata ETag

Change-Id: I93bcf78b9be2a34e46c4f2f4d8ec739faf197951

Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
Klaus Straubinger 2015-06-05 15:44:05 +02:00 committed by Christian Amend
parent 4cd8752e15
commit a604fa78f2
23 changed files with 526 additions and 332 deletions

View File

@ -170,7 +170,7 @@ public class BatchClientITCase extends AbstractTestITCase {
assertEquals(1, oDataResonse.getHeader("OData-Version").size());
assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
assertEquals(1, oDataResonse.getHeader("Content-Length").size());
assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("582", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
}
@ -202,7 +202,7 @@ public class BatchClientITCase extends AbstractTestITCase {
assertEquals(1, oDataResonse.getHeader("OData-Version").size());
assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
assertEquals(1, oDataResonse.getHeader("Content-Length").size());
assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("582", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
}
@ -234,7 +234,7 @@ public class BatchClientITCase extends AbstractTestITCase {
assertEquals(1, oDataResonse.getHeader("OData-Version").size());
assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
assertEquals(1, oDataResonse.getHeader("Content-Length").size());
assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("582", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
// Check second get request
@ -334,7 +334,7 @@ public class BatchClientITCase extends AbstractTestITCase {
assertEquals(1, oDataResonse.getHeader("OData-Version").size());
assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
assertEquals(1, oDataResonse.getHeader("Content-Length").size());
assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("582", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
// Check second get request
@ -357,7 +357,7 @@ public class BatchClientITCase extends AbstractTestITCase {
assertEquals(1, oDataResonse.getHeader("OData-Version").size());
assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
assertEquals(1, oDataResonse.getHeader("Content-Length").size());
assertEquals("446", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("490", oDataResonse.getHeader("Content-Length").toArray()[0]);
assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
}

View File

@ -35,16 +35,20 @@ import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest
import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataPropertyUpdateRequest;
import org.apache.olingo.client.api.communication.request.cud.UpdateType;
import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataServiceDocumentRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataValueRequest;
import org.apache.olingo.client.api.communication.request.streamed.ODataMediaEntityUpdateRequest;
import org.apache.olingo.client.api.communication.response.ODataDeleteResponse;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.domain.ClientEntity;
import org.apache.olingo.client.api.domain.ClientProperty;
import org.apache.olingo.client.api.domain.ClientServiceDocument;
import org.apache.olingo.client.api.http.HttpClientException;
import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
@ -64,6 +68,37 @@ public final class ConditionalITCase extends AbstractBaseTestITCase {
private final URI uriMedia = client.newURIBuilder(TecSvcConst.BASE_URI)
.appendEntitySetSegment("ESMedia").appendKeySegment(1).appendValueSegment().build();
@Test
public void readServiceDocument() throws Exception {
ODataServiceDocumentRequest request = client.getRetrieveRequestFactory()
.getServiceDocumentRequest(TecSvcConst.BASE_URI);
ODataRetrieveResponse<ClientServiceDocument> response = request.execute();
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
request = client.getRetrieveRequestFactory().getServiceDocumentRequest(TecSvcConst.BASE_URI);
request.setIfNoneMatch(response.getETag());
assertEquals(HttpStatusCode.NOT_MODIFIED.getStatusCode(), request.execute().getStatusCode());
request = client.getRetrieveRequestFactory().getServiceDocumentRequest(TecSvcConst.BASE_URI);
request.setIfMatch("W/\"0\"");
executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED);
}
@Test
public void readMetadataDocument() throws Exception {
EdmMetadataRequest request = client.getRetrieveRequestFactory().getMetadataRequest(TecSvcConst.BASE_URI);
ODataRetrieveResponse<Edm> response = request.execute();
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
request = client.getRetrieveRequestFactory().getMetadataRequest(TecSvcConst.BASE_URI);
request.setIfNoneMatch(response.getETag());
assertEquals(HttpStatusCode.NOT_MODIFIED.getStatusCode(), request.execute().getStatusCode());
request = client.getRetrieveRequestFactory().getMetadataRequest(TecSvcConst.BASE_URI);
request.setIfMatch("W/\"0\"");
executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED);
}
@Test
public void readWithWrongIfMatch() throws Exception {
ODataEntityRequest<ClientEntity> request = client.getRetrieveRequestFactory().getEntityRequest(uriEntity);

View File

@ -87,10 +87,9 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase {
.appendPropertySegment("PropertyString")
.build());
ODataRetrieveResponse<ClientProperty> response = request.execute();
String expectedResult =
"{\"@odata.context\":\"$metadata#ESTwoPrim(32766)/PropertyString\"," +
"\"value\":\"Test String1\"}";
assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8"));
String actualResult = IOUtils.toString(response.getRawResponse(), "UTF-8");
assertTrue(actualResult.startsWith("{\"@odata.context\":\"$metadata#ESTwoPrim(32766)/PropertyString\","));
assertTrue(actualResult.endsWith("\"value\":\"Test String1\"}"));
}
@Test
@ -167,10 +166,9 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase {
.appendPropertySegment("PropertyComp")
.build());
ODataRetrieveResponse<ClientProperty> response = request.execute();
String expectedResult =
"{\"@odata.context\":\"$metadata#ESMixPrimCollComp(7)/PropertyComp\"," +
"\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"}";
assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8"));
String actualResult = IOUtils.toString(response.getRawResponse(), "UTF-8");
assertTrue(actualResult.startsWith("{\"@odata.context\":\"$metadata#ESMixPrimCollComp(7)/PropertyComp\","));
assertTrue(actualResult.endsWith("\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"}"));
}
@Test

View File

@ -60,7 +60,7 @@ public class BasicBatchITCase extends AbstractBaseTestITCase {
assertEquals("HTTP/1.1 200 OK", reader.readLine());
assertEquals("OData-Version: 4.0", reader.readLine());
assertEquals("Content-Type: application/json;odata.metadata=minimal", reader.readLine());
assertEquals("Content-Length: 538", reader.readLine());
assertEquals("Content-Length: 582", reader.readLine());
blankLine(reader);
reader.close();

View File

@ -19,10 +19,13 @@
package org.apache.olingo.client.core.communication.request.retrieve;
import java.net.URI;
import java.util.Collection;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest;
import org.apache.olingo.client.api.communication.request.retrieve.XMLMetadataRequest;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
import org.apache.olingo.commons.api.edm.Edm;
@ -43,8 +46,17 @@ class EdmMetadataRequestImpl extends AbstractMetadataRequestImpl<Edm> implements
private EdmMetadataResponseImpl getPrivateResponse() {
if (privateResponse == null) {
final ODataRetrieveResponse<XMLMetadata> xmlMetadataResponse =
odataClient.getRetrieveRequestFactory().getXMLMetadataRequest(serviceRoot).execute();
XMLMetadataRequest request = odataClient.getRetrieveRequestFactory().getXMLMetadataRequest(serviceRoot);
if (getPrefer() != null) {
request.setPrefer(getPrefer());
}
if (getIfMatch() != null) {
request.setIfMatch(getIfMatch());
}
if (getIfNoneMatch() != null) {
request.setIfNoneMatch(getIfNoneMatch());
}
final ODataRetrieveResponse<XMLMetadata> xmlMetadataResponse = request.execute();
privateResponse = new EdmMetadataResponseImpl(odataClient, httpClient, xmlMetadataResponse);
}
@ -90,6 +102,21 @@ class EdmMetadataRequestImpl extends AbstractMetadataRequestImpl<Edm> implements
return xmlMetadataResponse.getStatusMessage();
}
@Override
public Collection<String> getHeaderNames() {
return xmlMetadataResponse.getHeaderNames();
}
@Override
public Collection<String> getHeader(final String name) {
return xmlMetadataResponse.getHeader(name);
}
@Override
public Collection<String> getHeader(final HeaderName name) {
return xmlMetadataResponse.getHeader(name);
}
public XMLMetadata getXMLMetadata() {
if (metadata == null) {
try {

View File

@ -35,6 +35,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation;
import org.apache.olingo.commons.api.edm.provider.CsdlAnnotations;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.http.HttpStatusCode;
public class XMLMetadataRequestImpl
extends AbstractMetadataRequestImpl<XMLMetadata>
@ -46,9 +47,21 @@ public class XMLMetadataRequestImpl
@Override
public ODataRetrieveResponse<XMLMetadata> execute() {
final SingleXMLMetadatRequestImpl rootReq = new SingleXMLMetadatRequestImpl(odataClient, uri, null);
SingleXMLMetadatRequestImpl rootReq = new SingleXMLMetadatRequestImpl(odataClient, uri, null);
if (getPrefer() != null) {
rootReq.setPrefer(getPrefer());
}
if (getIfMatch() != null) {
rootReq.setIfMatch(getIfMatch());
}
if (getIfNoneMatch() != null) {
rootReq.setIfNoneMatch(getIfNoneMatch());
}
final ODataRetrieveResponse<XMLMetadata> rootRes = rootReq.execute();
if (rootRes.getStatusCode() != HttpStatusCode.OK.getStatusCode()) {
return rootRes;
}
final XMLMetadataResponseImpl response =
new XMLMetadataResponseImpl(odataClient, httpClient, rootReq.getHttpResponse(), rootRes.getBody());
@ -176,12 +189,8 @@ public class XMLMetadataRequestImpl
final HttpResponse res, final XMLMetadata metadata) {
super(odataClient, httpClient, null);
initFromHttpResponse(res);
this.metadata = metadata;
statusCode = res.getStatusLine().getStatusCode();
statusMessage = res.getStatusLine().getReasonPhrase();
hasBeenInitialized = true;
}
@Override

View File

@ -47,6 +47,8 @@ public interface ServiceMetadata {
*/
List<EdmxReference> getReferences();
/**
* @return metadata ETag support
*/
ServiceMetadataETagSupport getServiceMetadataETagSupport();
}

View File

@ -73,7 +73,7 @@ public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProce
response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode());
} else {
ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
response.setContent(serializer.serviceDocument(serviceMetadata.getEdm(), null).getContent());
response.setContent(serializer.serviceDocument(serviceMetadata, null).getContent());
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
}

View File

@ -22,7 +22,6 @@ import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -38,10 +37,10 @@ public interface ODataSerializer {
/**
* Writes the service document into an InputStream.
* @param edm the Entity Data Model
* @param serviceMetadata the metadata information for the service
* @param serviceRoot the service-root URI of this OData service
*/
SerializerResult serviceDocument(Edm edm, String serviceRoot) throws SerializerException;
SerializerResult serviceDocument(ServiceMetadata serviceMetadata, String serviceRoot) throws SerializerException;
/**
* Writes the metadata document into an InputStream.
@ -52,13 +51,12 @@ public interface ODataSerializer {
/**
* Writes an ODataError into an InputStream.
* @param error the main error
* @return inputStream containing the OData-formatted error
*/
SerializerResult error(ODataServerError error) throws SerializerException;
/**
* Writes entity-collection data into an InputStream.
* @param metadata Metadata for the service
* @param metadata metadata for the service
* @param entityType the {@link EdmEntityType}
* @param entitySet the data of the entity set
* @param options options for the serializer
@ -68,7 +66,7 @@ public interface ODataSerializer {
/**
* Writes entity data into an InputStream.
* @param metadata Metadata for the service
* @param metadata metadata for the service
* @param entityType the {@link EdmEntityType}
* @param entity the data of the entity
* @param options options for the serializer
@ -78,16 +76,17 @@ public interface ODataSerializer {
/**
* Writes primitive-type instance data into an InputStream.
* @param metadata metadata for the service
* @param type primitive type
* @param property property value
* @param options options for the serializer
*/
SerializerResult primitive(EdmPrimitiveType type, Property property, PrimitiveSerializerOptions options)
throws SerializerException;
SerializerResult primitive(ServiceMetadata metadata, EdmPrimitiveType type, Property property,
PrimitiveSerializerOptions options) throws SerializerException;
/**
* Writes complex-type instance data into an InputStream.
* @param metadata Metadata for the service
* @param metadata metadata for the service
* @param type complex type
* @param property property value
* @param options options for the serializer
@ -97,16 +96,17 @@ public interface ODataSerializer {
/**
* Writes data of a collection of primitive-type instances into an InputStream.
* @param metadata metadata for the service
* @param type primitive type
* @param property property value
* @param options options for the serializer
*/
SerializerResult primitiveCollection(EdmPrimitiveType type, Property property, PrimitiveSerializerOptions options)
throws SerializerException;
SerializerResult primitiveCollection(ServiceMetadata metadata, EdmPrimitiveType type, Property property,
PrimitiveSerializerOptions options) throws SerializerException;
/**
* Writes data of a collection of complex-type instances into an InputStream.
* @param metadata Metadata for the service
* @param metadata metadata for the service
* @param type complex type
* @param property property value
* @param options options for the serializer
@ -115,28 +115,22 @@ public interface ODataSerializer {
ComplexSerializerOptions options) throws SerializerException;
/**
* Writes a single entity reference into an InputStream
*
* @param metadata Metadata for the service
* Writes a single entity reference into an InputStream.
* @param metadata metadata for the service
* @param edmEntitySet {@link EdmEntitySet}
* @param entity data of the entity
* @param contextUrl {@link ContextURL}
* @return Serialized entity reference
* @throws SerializerException
* @param contextURL {@link ContextURL}
*/
SerializerResult reference(ServiceMetadata metadata, EdmEntitySet edmEntitySet, Entity entity,
final ContextURL contextUrl) throws SerializerException;
ContextURL contextURL) throws SerializerException;
/**
* Writes entity collection references into an InputStream
*
* @param metadata Metadata for the service
* Writes entity-collection references into an InputStream.
* @param metadata metadata for the service
* @param edmEntitySet {@link EdmEntitySet}
* @param entityCollection data of the entity collection
* @param contextURL
* @return Serialized entity reference
* @throws SerializerException
* @param contextURL {@link ContextURL}
*/
SerializerResult referenceCollection(ServiceMetadata metadata, EdmEntitySet edmEntitySet,
EntityCollection entityCollection, final ContextURL contextURL) throws SerializerException;
EntityCollection entityCollection, ContextURL contextURL) throws SerializerException;
}

View File

@ -120,9 +120,11 @@ public class PropertyResponse extends ServiceResponse {
private void writePrimitiveProperty(EdmPrimitiveType type, Property property)
throws SerializerException {
if(this.collection) {
this.response.setContent(this.serializer.primitiveCollection(type, property, this.primitiveOptions).getContent());
this.response.setContent(
this.serializer.primitiveCollection(metadata, type, property, this.primitiveOptions).getContent());
} else {
this.response.setContent(this.serializer.primitive(type, property, this.primitiveOptions).getContent());
this.response.setContent(
this.serializer.primitive(metadata, type, property, this.primitiveOptions).getContent());
}
writeOK(this.responseContentType.toContentTypeString());
close();

View File

@ -51,7 +51,7 @@ public class ServiceDocumentResponse extends ServiceResponse {
public void writeServiceDocument(String serviceRoot)
throws ODataLibraryException {
assert (!isClosed());
this.response.setContent(this.serializer.serviceDocument(this.metadata.getEdm(), serviceRoot).getContent());
this.response.setContent(this.serializer.serviceDocument(metadata, serviceRoot).getContent());
writeOK(this.responseContentType.toContentTypeString());
close();
}

View File

@ -31,7 +31,6 @@ import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Linked;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -80,7 +79,8 @@ public class ODataJsonSerializer implements ODataSerializer {
}
@Override
public SerializerResult serviceDocument(final Edm edm, final String serviceRoot) throws SerializerException {
public SerializerResult serviceDocument(final ServiceMetadata metadata, final String serviceRoot)
throws SerializerException {
CircleStreamBuffer buffer;
JsonGenerator gen = null;
@ -89,7 +89,7 @@ public class ODataJsonSerializer implements ODataSerializer {
gen = new JsonFactory().createGenerator(buffer.getOutputStream())
.setPrettyPrinter(new DefaultPrettyPrinter());
new ServiceDocumentJsonSerializer(edm, serviceRoot).writeServiceDocument(gen);
new ServiceDocumentJsonSerializer(metadata, serviceRoot, format).writeServiceDocument(gen);
gen.close();
@ -146,6 +146,8 @@ public class ODataJsonSerializer implements ODataSerializer {
ContextURLBuilder.create(contextURL).toASCIIString());
}
writeMetadataETag(metadata, json);
if (options != null && options.getCount() != null && options.getCount().getValue()
&& entitySet.getCount() != null) {
writeCount(entitySet, json);
@ -196,6 +198,16 @@ public class ODataJsonSerializer implements ODataSerializer {
return contextURL;
}
private void writeMetadataETag(final ServiceMetadata metadata, JsonGenerator json) throws IOException {
if (format != ODataFormat.JSON_NO_METADATA
&& metadata != null
&& metadata.getServiceMetadataETagSupport() != null
&& metadata.getServiceMetadataETagSupport().getMetadataETag() != null) {
json.writeStringField(Constants.JSON_METADATA_ETAG,
metadata.getServiceMetadataETagSupport().getMetadataETag());
}
}
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
final boolean onlyReference, final JsonGenerator json) throws IOException,
@ -219,8 +231,9 @@ public class ODataJsonSerializer implements ODataSerializer {
throws IOException, SerializerException {
json.writeStartObject();
if (format != ODataFormat.JSON_NO_METADATA) {
if (contextURL != null) {
if (contextURL != null) { // top-level entity
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
writeMetadataETag(metadata, json);
}
if (entity.getETag() != null) {
json.writeStringField(Constants.JSON_ETAG, entity.getETag());
@ -529,8 +542,8 @@ public class ODataJsonSerializer implements ODataSerializer {
}
@Override
public SerializerResult primitive(final EdmPrimitiveType type, final Property property,
final PrimitiveSerializerOptions options) throws SerializerException {
public SerializerResult primitive(final ServiceMetadata metadata, final EdmPrimitiveType type,
final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
CircleStreamBuffer buffer = new CircleStreamBuffer();
try {
@ -539,6 +552,7 @@ public class ODataJsonSerializer implements ODataSerializer {
if (contextURL != null) {
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
}
writeMetadataETag(metadata, json);
if (property.isNull()) {
throw new SerializerException("Property value can not be null.", SerializerException.MessageKeys.NULL_INPUT);
} else {
@ -572,6 +586,7 @@ public class ODataJsonSerializer implements ODataSerializer {
if (contextURL != null) {
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
}
writeMetadataETag(metadata, json);
EdmComplexType resolvedType = resolveComplexType(metadata, type, property.getType());
if (!resolvedType.equals(type)) {
json.writeStringField(Constants.JSON_TYPE, "#" + property.getType());
@ -593,8 +608,8 @@ public class ODataJsonSerializer implements ODataSerializer {
}
@Override
public SerializerResult primitiveCollection(final EdmPrimitiveType type, final Property property,
final PrimitiveSerializerOptions options) throws SerializerException {
public SerializerResult primitiveCollection(final ServiceMetadata metadata, final EdmPrimitiveType type,
final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
CircleStreamBuffer buffer = new CircleStreamBuffer();
try {
@ -603,6 +618,7 @@ public class ODataJsonSerializer implements ODataSerializer {
if (contextURL != null) {
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
}
writeMetadataETag(metadata, json);
json.writeFieldName(Constants.VALUE);
writePrimitiveCollection(type, property,
options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(),
@ -632,6 +648,7 @@ public class ODataJsonSerializer implements ODataSerializer {
if (contextURL != null) {
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
}
writeMetadataETag(metadata, json);
json.writeFieldName(Constants.VALUE);
writeComplexCollection(type, property, null, json);
json.writeEndObject();
@ -656,7 +673,7 @@ public class ODataJsonSerializer implements ODataSerializer {
try {
final JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
writeReference(edmEntitySet, entity, contextURL, uriHelper, json);
writeReference(metadata, edmEntitySet, entity, contextURL, uriHelper, json);
json.close();
} catch (IOException e) {
@ -682,7 +699,8 @@ public class ODataJsonSerializer implements ODataSerializer {
}
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
writeReferenceCollection(metadata, edmEntitySet, entityCollection, uriHelper,json);
writeMetadataETag(metadata, json);
writeReferenceCollection(edmEntitySet, entityCollection, uriHelper,json);
if(entityCollection.getNext() != null) {
writeNextLink(entityCollection, json);
@ -697,25 +715,24 @@ public class ODataJsonSerializer implements ODataSerializer {
return SerializerResultImpl.with().content(buffer.getInputStream()).build();
}
protected void writeReferenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
final EntityCollection entityCollection, final UriHelper uriHelper, final JsonGenerator json)
throws IOException, SerializerException {
protected void writeReferenceCollection(final EdmEntitySet edmEntitySet, final EntityCollection entityCollection,
final UriHelper uriHelper, final JsonGenerator json) throws IOException, SerializerException {
json.writeArrayFieldStart(Constants.VALUE);
for(final Entity entity : entityCollection.getEntities()) {
writeReference(edmEntitySet, entity, null, uriHelper, json);
writeReference(null, edmEntitySet, entity, null, uriHelper, json);
}
json.writeEndArray();
}
protected void writeReference(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL,
final UriHelper uriHelper, final JsonGenerator json) throws IOException, SerializerException {
protected void writeReference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, final Entity entity,
final ContextURL contextURL, final UriHelper uriHelper, final JsonGenerator json)
throws IOException, SerializerException {
json.writeStartObject();
if(contextURL != null) {
if (contextURL != null) {
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
writeMetadataETag(metadata, json);
}
json.writeStringField(Constants.JSON_ID, uriHelper.buildCanonicalURL(edmEntitySet, entity));

View File

@ -26,6 +26,8 @@ import org.apache.olingo.commons.api.edm.EdmEntityContainer;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
import org.apache.olingo.commons.api.edm.EdmSingleton;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.server.api.ServiceMetadata;
import com.fasterxml.jackson.core.JsonGenerator;
@ -36,32 +38,37 @@ public class ServiceDocumentJsonSerializer {
public static final String SINGLETON = "Singleton";
public static final String SERVICE_DOCUMENT = "ServiceDocument";
private final Edm edm;
private final ServiceMetadata metadata;
private final String serviceRoot;
private final ODataFormat format;
public ServiceDocumentJsonSerializer(final Edm edm, final String serviceRoot) {
this.edm = edm;
public ServiceDocumentJsonSerializer(final ServiceMetadata metadata, final String serviceRoot,
final ODataFormat format) {
this.metadata = metadata;
this.serviceRoot = serviceRoot;
this.format = format;
}
public void writeServiceDocument(final JsonGenerator gen) throws IOException {
gen.writeStartObject();
Object metadataUri;
if (serviceRoot == null) {
metadataUri = Constants.METADATA;
} else {
if (serviceRoot.endsWith("/")) {
metadataUri = serviceRoot + Constants.METADATA;
} else {
metadataUri = serviceRoot + "/" + Constants.METADATA;
}
}
final String metadataUri =
(serviceRoot == null ? "" :
serviceRoot.endsWith("/") ? serviceRoot : (serviceRoot + "/"))
+ Constants.METADATA;
gen.writeObjectField(Constants.JSON_CONTEXT, metadataUri);
if (format != ODataFormat.JSON_NO_METADATA
&& metadata != null
&& metadata.getServiceMetadataETagSupport() != null
&& metadata.getServiceMetadataETagSupport().getMetadataETag() != null) {
gen.writeStringField(Constants.JSON_METADATA_ETAG,
metadata.getServiceMetadataETagSupport().getMetadataETag());
}
gen.writeArrayFieldStart(Constants.VALUE);
final Edm edm = metadata.getEdm();
writeEntitySets(gen, edm);
writeFunctionImports(gen, edm);
writeSingletons(gen, edm);

View File

@ -26,7 +26,6 @@ import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -53,7 +52,8 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
private static final Logger log = LoggerFactory.getLogger(ODataXmlSerializerImpl.class);
@Override
public SerializerResultImpl serviceDocument(final Edm edm, final String serviceRoot) throws SerializerException {
public SerializerResultImpl serviceDocument(final ServiceMetadata metadata, final String serviceRoot)
throws SerializerException {
throw new SerializerException("Service Document not implemented for XML format",
SerializerException.MessageKeys.NOT_IMPLEMENTED);
}
@ -110,8 +110,8 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
}
@Override
public SerializerResult primitive(final EdmPrimitiveType type, final Property property,
final PrimitiveSerializerOptions options) throws SerializerException {
public SerializerResult primitive(final ServiceMetadata metadata, final EdmPrimitiveType type,
final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
throw new SerializerException("Serialization not implemented for XML format.",
SerializerException.MessageKeys.NOT_IMPLEMENTED);
}
@ -124,8 +124,8 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
}
@Override
public SerializerResult primitiveCollection(final EdmPrimitiveType type, final Property property,
final PrimitiveSerializerOptions options) throws SerializerException {
public SerializerResult primitiveCollection(final ServiceMetadata metadata, final EdmPrimitiveType type,
final Property property, final PrimitiveSerializerOptions options) throws SerializerException {
throw new SerializerException("Serialization not implemented for XML format.",
SerializerException.MessageKeys.NOT_IMPLEMENTED);
}

View File

@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.etag;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.etag.ETagHelper;
import org.apache.olingo.server.api.etag.PreconditionException;
import org.junit.Test;
public class ETagHelperTest {
private static final ETagHelper eTagHelper = OData.newInstance().createETagHelper();
@Test
public void readPrecondition() throws Exception {
assertFalse(eTagHelper.checkReadPreconditions(null, null, null));
assertFalse(eTagHelper.checkReadPreconditions("\"ETag\"", null, null));
assertFalse(eTagHelper.checkReadPreconditions(null, Collections.singleton("\"ETag\""), null));
assertFalse(eTagHelper.checkReadPreconditions(null, null, Collections.singleton("\"ETag\"")));
assertFalse(eTagHelper.checkReadPreconditions("\"ETag\"", Collections.singleton("\"ETag\""), null));
assertFalse(eTagHelper.checkReadPreconditions("\"ETag\"", Collections.singleton("*"), null));
assertTrue(eTagHelper.checkReadPreconditions("\"ETag\"", null, Collections.singleton("\"ETag\"")));
assertTrue(eTagHelper.checkReadPreconditions("\"ETag\"", null, Collections.singleton("*")));
assertFalse(eTagHelper.checkReadPreconditions("\"ETag\"", null, Collections.singleton("\"ETag2\"")));
}
@Test(expected = PreconditionException.class)
public void readPreconditionFail() throws Exception {
eTagHelper.checkReadPreconditions("\"ETag\"", Collections.singleton("\"ETag2\""), null);
}
@Test
public void changePrecondition() throws Exception {
eTagHelper.checkChangePreconditions(null, null, null);
eTagHelper.checkChangePreconditions("\"ETag\"", null, null);
eTagHelper.checkChangePreconditions(null, Collections.singleton("\"ETag\""), null);
eTagHelper.checkChangePreconditions(null, Collections.singleton("*"), null);
eTagHelper.checkChangePreconditions(null, null, Collections.singleton("*"));
eTagHelper.checkChangePreconditions("\"ETag\"", Collections.singleton("\"ETag\""), null);
eTagHelper.checkChangePreconditions("\"ETag\"", Collections.singleton("*"), null);
eTagHelper.checkChangePreconditions("\"ETag\"", null, Collections.singleton("\"ETag2\""));
}
@Test(expected = PreconditionException.class)
public void changePreconditionFailIfMatch() throws Exception {
eTagHelper.checkChangePreconditions("\"ETag\"", Collections.singleton("\"ETag2\""), null);
}
@Test(expected = PreconditionException.class)
public void changePreconditionFailIfNoneMatch() throws Exception {
eTagHelper.checkChangePreconditions("\"ETag\"", null, Collections.singleton("\"ETag\""));
}
@Test(expected = PreconditionException.class)
public void changePreconditionFailIfNoneMatchAll() throws Exception {
eTagHelper.checkChangePreconditions("\"ETag\"", null, Collections.singleton("*"));
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc;
import org.apache.olingo.server.api.etag.ServiceMetadataETagSupport;
public class MetadataETagSupport implements ServiceMetadataETagSupport {
private final String metadataETag;
public MetadataETagSupport(final String metadataETag) {
this.metadataETag = metadataETag;
}
@Override
public String getMetadataETag() {
return metadataETag;
}
@Override
public String getServiceDocumentETag() {
return metadataETag;
}
}

View File

@ -20,7 +20,7 @@ package org.apache.olingo.server.tecsvc;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletException;
@ -47,6 +47,16 @@ public class TechnicalServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(TechnicalServlet.class);
/**
* <p>ETag for the service document and the metadata document</p>
* <p>We use the same field for service-document and metadata-document ETags.
* It must change whenever the corresponding document changes.
* We don't know when someone changed the EDM in a way that changes one of these
* documents, but we do know that the EDM is defined completely in code and that
* therefore any change must be deployed, resulting in re-loading of this class,
* giving this field a new and hopefully unique value.</p>
*/
private static final String metadataETag = "W/\"" + System.nanoTime() + "\"";
@Override
protected void service(final HttpServletRequest request, final HttpServletResponse response)
@ -55,8 +65,9 @@ public class TechnicalServlet extends HttpServlet {
OData odata = OData.newInstance();
EdmxReference reference = new EdmxReference(URI.create("../v4.0/cs02/vocabularies/Org.OData.Core.V1.xml"));
reference.addInclude(new EdmxReferenceInclude("Org.OData.Core.V1", "Core"));
final List<EdmxReference> references = Arrays.asList(reference);
final ServiceMetadata serviceMetadata = odata.createServiceMetadata(new EdmTechProvider(references), references);
final List<EdmxReference> references = Collections.singletonList(reference);
final ServiceMetadata serviceMetadata = odata.createServiceMetadata(
new EdmTechProvider(references), references, new MetadataETagSupport(metadataETag));
HttpSession session = request.getSession(true);
DataProvider dataProvider = (DataProvider) session.getAttribute(DataProvider.class.getName());

View File

@ -176,7 +176,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor
SerializerResult result =
odata.createSerializer(ODataFormat.fromContentType(responseFormat))
.primitiveCollection(type, property, options);
.primitiveCollection(serviceMetadata, type, property, options);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setContent(result.getContent());
@ -208,8 +208,8 @@ public class TechnicalActionProcessor extends TechnicalProcessor
ContextURL contextURL = ContextURL.with().type(type).build();
PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextURL).build();
SerializerResult result = odata.createSerializer(ODataFormat.fromContentType(responseFormat)).primitive(type,
property, options);
SerializerResult result = odata.createSerializer(ODataFormat.fromContentType(responseFormat))
.primitive(serviceMetadata, type, property, options);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setContent(result.getContent());

View File

@ -278,6 +278,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
property.setValue(property.getValueType(), edmProperty.isCollection() ? Collections.emptyList() : null);
dataProvider.updateETag(entity);
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
if (entity.getETag() != null) {
response.setHeader(HttpHeader.ETAG, entity.getETag());
}
} else {
throw new ODataApplicationException("Not nullable.", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
}
@ -333,7 +336,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
SerializerResult result = null;
switch (representationType) {
case PRIMITIVE:
result = serializer.primitive((EdmPrimitiveType) type, property,
result = serializer.primitive(serviceMetadata, (EdmPrimitiveType) type, property,
PrimitiveSerializerOptions.with().contextURL(contextURL)
.nullable(edmProperty == null ? returnType.isNullable() : edmProperty.isNullable())
.maxLength(edmProperty == null ? returnType.getMaxLength() : edmProperty.getMaxLength())
@ -349,7 +352,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
.build());
break;
case COLLECTION_PRIMITIVE:
result = serializer.primitiveCollection((EdmPrimitiveType) type, property,
result = serializer.primitiveCollection(serviceMetadata, (EdmPrimitiveType) type, property,
PrimitiveSerializerOptions.with().contextURL(contextURL)
.nullable(edmProperty == null ? returnType.isNullable() : edmProperty.isNullable())
.maxLength(edmProperty == null ? returnType.getMaxLength() : edmProperty.getMaxLength())

View File

@ -30,14 +30,12 @@ import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ServiceMetadata;
@ -57,6 +55,7 @@ import org.apache.olingo.server.api.uri.queryoption.SelectItem;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.serializer.ExpandSelectMock;
import org.apache.olingo.server.core.uri.UriHelperImpl;
import org.apache.olingo.server.tecsvc.MetadataETagSupport;
import org.apache.olingo.server.tecsvc.data.DataProvider;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.hamcrest.CoreMatchers;
@ -66,10 +65,8 @@ import org.mockito.Mockito;
public class ODataJsonSerializerTest {
private static final ServiceMetadata metadata = OData.newInstance().createServiceMetadata(
new EdmTechProvider(), Collections.<EdmxReference> emptyList());
private static final Edm edm = metadata.getEdm();
private static final EdmEntityContainer entityContainer = edm.getEntityContainer(
new FullQualifiedName("olingo.odata.test1", "Container"));
new EdmTechProvider(), Collections.<EdmxReference> emptyList(), new MetadataETagSupport("W/\"metadataETag\""));
private static final EdmEntityContainer entityContainer = metadata.getEdm().getEntityContainer();
private final DataProvider data = new DataProvider();
private final ODataSerializer serializer = new ODataJsonSerializer(ODataFormat.JSON);
private final UriHelper helper = new UriHelperImpl();
@ -85,6 +82,7 @@ public class ODataJsonSerializerTest {
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32767,"
+ "\"PropertyString\":\"First Resource - positive values\","
+ "\"PropertyBoolean\":true,"
@ -116,6 +114,7 @@ public class ODataJsonSerializerTest {
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
.build()).getContent());
final String expectedResult = "{\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32767,"
+ "\"PropertyString\":null,\"PropertyBoolean\":null,"
+ "\"PropertyByte\":null,\"PropertySByte\":null,"
@ -174,6 +173,7 @@ public class ODataJsonSerializerTest {
Assert.assertThat(resultString, CoreMatchers.startsWith("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"@odata.count\":3,\"value\":["));
Assert.assertThat(resultString, CoreMatchers.endsWith("],"
+ "\"@odata.nextLink\":\"/next\"}"));
@ -198,6 +198,7 @@ public class ODataJsonSerializerTest {
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"http://host/service/$metadata#ESCollAllPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":1,"
+ "\"CollPropertyString\":"
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
@ -233,6 +234,7 @@ public class ODataJsonSerializerTest {
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"@odata.etag\":\"W/\\\"32767\\\"\","
+ "\"PropertyInt16\":32767,"
+ "\"PropertyComp\":{"
@ -267,6 +269,7 @@ public class ODataJsonSerializerTest {
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32767,"
+ "\"CollPropertyString\":"
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
@ -288,6 +291,7 @@ public class ODataJsonSerializerTest {
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
.build()).getContent());
final String expectedResult = "{\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32767,"
+ "\"CollPropertyString\":null,\"PropertyComp\":null,\"CollPropertyComp\":null}";
Assert.assertEquals(expectedResult, resultString);
@ -331,6 +335,7 @@ public class ODataJsonSerializerTest {
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
.build()).getContent());
final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"@odata.mediaEtag\":\"W/\\\"1\\\"\",\"@odata.mediaContentType\":\"image/svg+xml\","
+ "\"PropertyInt16\":1}";
Assert.assertEquals(expectedResult, resultString);
@ -344,7 +349,9 @@ public class ODataJsonSerializerTest {
edmEntitySet.getEntityType(), entitySet,
EntityCollectionSerializerOptions.with()
.contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build()).getContent());
final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia\",\"value\":["
final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":["
+ "{\"@odata.mediaEtag\":\"W/\\\"1\\\"\",\"@odata.mediaContentType\":\"image/svg+xml\",\"PropertyInt16\":1},"
+ "{\"@odata.mediaEtag\":\"W/\\\"2\\\"\",\"@odata.mediaContentType\":\"image/svg+xml\",\"PropertyInt16\":2},"
+ "{\"@odata.mediaEtag\":\"W/\\\"3\\\"\",\"@odata.mediaContentType\":\"image/svg+xml\",\"PropertyInt16\":3},"
@ -361,7 +368,9 @@ public class ODataJsonSerializerTest {
EntityCollectionSerializerOptions.with()
.contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build()).getContent());
final String expected = "{\"@odata.context\":\"$metadata#ESAllNullable\",\"value\":[{\"PropertyKey\":1,"
final String expected = "{\"@odata.context\":\"$metadata#ESAllNullable\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":[{\"PropertyKey\":1,"
+ "\"PropertyInt16\":null,\"PropertyString\":null,\"PropertyBoolean\":null,\"PropertyByte\":null,"
+ "\"PropertySByte\":null,\"PropertyInt32\":null,\"PropertyInt64\":null,\"PropertySingle\":null,"
+ "\"PropertyDouble\":null,\"PropertyDecimal\":null,\"PropertyBinary\":null,\"PropertyDate\":null,"
@ -400,6 +409,7 @@ public class ODataJsonSerializerTest {
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"$metadata#ESAllPrim(PropertyBoolean,PropertyDate)/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyBoolean\":true,\"PropertyDate\":\"2012-12-03\"}";
Assert.assertEquals(expectedResult, resultString);
}
@ -419,6 +429,7 @@ public class ODataJsonSerializerTest {
.build()).getContent();
final String resultString = IOUtils.toString(result);
final String expectedResult = "{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
Assert.assertEquals(expectedResult, resultString);
}
@ -441,6 +452,7 @@ public class ODataJsonSerializerTest {
final String resultString = IOUtils.toString(result);
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":["
+ "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 1\"}}},"
+ "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 2\"}}}]}",
@ -465,6 +477,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp)\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":["
+ "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":123,\"PropertyString\":\"String 1\"}}},"
+ "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":987,\"PropertyString\":\"String 2\"}}}]}",
@ -484,6 +497,7 @@ public class ODataJsonSerializerTest {
.build()).getContent();
final String resultString = IOUtils.toString(result);
Assert.assertEquals("{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
+ "\"NavPropertyETAllPrimOne\":{"
+ "\"PropertyInt16\":32767,"
@ -525,6 +539,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimOne(PropertyDate))/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
+ "\"NavPropertyETAllPrimOne\":{\"PropertyDate\":\"2012-12-03\"}}",
resultString);
@ -553,6 +568,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim(PropertySByte)/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertySByte\":127,"
+ "\"NavPropertyETTwoPrimOne\":{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"},"
+ "\"NavPropertyETTwoPrimMany\":[{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"}]}",
@ -580,6 +596,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim(PropertyTimeOfDay)/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyTimeOfDay\":\"23:49:14\","
+ "\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]}",
resultString);
@ -610,6 +627,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimMany(PropertyInt32))/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\","
+ "\"NavPropertyETAllPrimMany\":["
+ "{\"PropertyInt32\":-2147483648,\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]},"
@ -627,7 +645,7 @@ public class ODataJsonSerializerTest {
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
final String resultString = IOUtils.toString(serializer
.primitive((EdmPrimitiveType) edmProperty.getType(), property,
.primitive(metadata, (EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
@ -635,6 +653,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyString\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":\"First Resource - positive values\"}",
resultString);
}
@ -644,7 +663,7 @@ public class ODataJsonSerializerTest {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
final Property property = new Property("Edm.String", edmProperty.getName(), ValueType.PRIMITIVE, null);
serializer.primitive((EdmPrimitiveType) edmProperty.getType(), property,
serializer.primitive(metadata, (EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("4242").navOrPropertyPath(edmProperty.getName())
@ -659,7 +678,7 @@ public class ODataJsonSerializerTest {
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
final String resultString = IOUtils.toString(serializer
.primitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
.primitiveCollection(metadata, (EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName())
@ -667,6 +686,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyString\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]}",
resultString);
}
@ -686,6 +706,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESMixPrimCollComp(32767)/PropertyComp\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}",
resultString);
}
@ -705,6 +726,7 @@ public class ODataJsonSerializerTest {
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESMixPrimCollComp(32767)/CollPropertyComp\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":[{\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"},"
+ "{\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},"
+ "{\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"}]}",
@ -720,7 +742,10 @@ public class ODataJsonSerializerTest {
ContextURL.with().suffix(Suffix.REFERENCE).build());
final String resultString = IOUtils.toString(serializerResult.getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#$ref\",\"@odata.id\":\"ESAllPrim(32767)\"}", resultString);
Assert.assertEquals("{\"@odata.context\":\"$metadata#$ref\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"@odata.id\":\"ESAllPrim(32767)\"}",
resultString);
}
@Test
@ -731,14 +756,16 @@ public class ODataJsonSerializerTest {
final SerializerResult serializerResult = serializer.referenceCollection(metadata,
edmEntitySet,
entityCollection,
ContextURL.with().asCollection()
.suffix(Suffix.REFERENCE).build());
ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build());
final String resultString = IOUtils.toString(serializerResult.getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\",\"value\":[{\"@odata.id\":" +
"\"ESAllPrim(32767)\"},{\"@odata.id\":\"ESAllPrim(-32768)\"},{\"@odata.id\":" +
"\"ESAllPrim(0)\"}]}", resultString);
Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":[{\"@odata.id\":\"ESAllPrim(32767)\"},"
+ "{\"@odata.id\":\"ESAllPrim(-32768)\"},"
+ "{\"@odata.id\":\"ESAllPrim(0)\"}]}",
resultString);
}
@Test
@ -749,11 +776,12 @@ public class ODataJsonSerializerTest {
final SerializerResult serializerResult = serializer.referenceCollection(metadata,
edmEntitySet,
entityCollection,
ContextURL.with().asCollection()
.suffix(Suffix.REFERENCE).build());
ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build());
final String resultString = IOUtils.toString(serializerResult.getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\",\"value\":[]}", resultString);
Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":[]}", resultString);
}
}

View File

@ -21,92 +21,28 @@ package org.apache.olingo.server.core.serializer.json;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
import org.apache.olingo.commons.api.edm.EdmSingleton;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.junit.Before;
import org.apache.olingo.server.tecsvc.MetadataETagSupport;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.junit.Test;
public class ServiceDocumentTest {
private Edm edm;
@Before
public void before() {
EdmEntitySet edmEntitySet1 = mock(EdmEntitySet.class);
when(edmEntitySet1.getName()).thenReturn("entitySetName1");
when(edmEntitySet1.isIncludeInServiceDocument()).thenReturn(true);
EdmEntitySet edmEntitySet2 = mock(EdmEntitySet.class);
when(edmEntitySet2.getName()).thenReturn("entitySetName2");
when(edmEntitySet2.isIncludeInServiceDocument()).thenReturn(true);
EdmEntitySet edmEntitySet3 = mock(EdmEntitySet.class);
when(edmEntitySet3.getName()).thenReturn("entitySetName3");
when(edmEntitySet3.isIncludeInServiceDocument()).thenReturn(false);
List<EdmEntitySet> entitySets = new ArrayList<EdmEntitySet>();
entitySets.add(edmEntitySet1);
entitySets.add(edmEntitySet2);
entitySets.add(edmEntitySet3);
EdmFunctionImport functionImport1 = mock(EdmFunctionImport.class);
when(functionImport1.getName()).thenReturn("functionImport1");
when(functionImport1.isIncludeInServiceDocument()).thenReturn(true);
EdmFunctionImport functionImport2 = mock(EdmFunctionImport.class);
when(functionImport2.getName()).thenReturn("functionImport2");
when(functionImport2.isIncludeInServiceDocument()).thenReturn(true);
EdmFunctionImport functionImport3 = mock(EdmFunctionImport.class);
when(functionImport3.getName()).thenReturn("functionImport3");
when(functionImport3.isIncludeInServiceDocument()).thenReturn(false);
List<EdmFunctionImport> functionImports = new ArrayList<EdmFunctionImport>();
functionImports.add(functionImport1);
functionImports.add(functionImport2);
functionImports.add(functionImport3);
EdmSingleton singleton1 = mock(EdmSingleton.class);
when(singleton1.getName()).thenReturn("singleton1");
EdmSingleton singleton2 = mock(EdmSingleton.class);
when(singleton2.getName()).thenReturn("singleton2");
EdmSingleton singleton3 = mock(EdmSingleton.class);
when(singleton3.getName()).thenReturn("singleton3");
List<EdmSingleton> singletons = new ArrayList<EdmSingleton>();
singletons.add(singleton1);
singletons.add(singleton2);
singletons.add(singleton3);
EdmEntityContainer edmEntityContainer = mock(EdmEntityContainer.class);
when(edmEntityContainer.getEntitySets()).thenReturn(entitySets);
when(edmEntityContainer.getFunctionImports()).thenReturn(functionImports);
when(edmEntityContainer.getSingletons()).thenReturn(singletons);
edm = mock(Edm.class);
when(edm.getEntityContainer(null)).thenReturn(edmEntityContainer);
}
private static final ServiceMetadata metadata = OData.newInstance().createServiceMetadata(
new EdmTechProvider(), Collections.<EdmxReference> emptyList(), new MetadataETagSupport("W/\"metadataETag\""));
@Test
public void writeServiceDocumentJson() throws Exception {
String serviceRoot = "http://localhost:8080/odata.svc";
final String serviceRoot = "http://localhost:8080/odata.svc";
OData server = OData.newInstance();
assertNotNull(server);
@ -114,20 +50,26 @@ public class ServiceDocumentTest {
ODataSerializer serializer = server.createSerializer(ODataFormat.JSON);
assertNotNull(serializer);
InputStream result = serializer.serviceDocument(edm, serviceRoot).getContent();
InputStream result = serializer.serviceDocument(metadata, serviceRoot).getContent();
assertNotNull(result);
String jsonString = IOUtils.toString(result);
final String jsonString = IOUtils.toString(result);
assertTrue(jsonString.contains("entitySetName1"));
assertTrue(jsonString.contains("entitySetName2"));
assertFalse(jsonString.contains("entitySetName3"));
assertTrue(jsonString.contains(metadata.getServiceMetadataETagSupport().getMetadataETag().replace("\"", "\\\"")));
assertTrue(jsonString.contains("functionImport1"));
assertTrue(jsonString.contains("functionImport2"));
assertFalse(jsonString.contains("functionImport3"));
assertTrue(jsonString.contains("ESAllPrim"));
assertTrue(jsonString.contains("ESCollAllPrim"));
assertTrue(jsonString.contains("ESKeyNavCont"));
assertFalse(jsonString.contains("ESInvisible"));
assertTrue(jsonString.contains("singleton1"));
assertTrue(jsonString.contains("singleton2"));
assertTrue(jsonString.contains("singleton3"));
assertTrue(jsonString.contains("FINRTInt16"));
assertTrue(jsonString.contains("FINRTCollETMixPrimCollCompTwoParam"));
assertTrue(jsonString.contains("FICRTCollESKeyNavContParam"));
assertFalse(jsonString.contains("FINInvisibleRTInt16"));
assertTrue(jsonString.contains("FunctionImport"));
assertTrue(jsonString.contains("SI"));
assertTrue(jsonString.contains("SINav"));
assertTrue(jsonString.contains("SIMedia"));
assertTrue(jsonString.contains("Singleton"));
}
}

View File

@ -260,7 +260,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
InputStream serializerContent = complex ?
serializer.complex(edm, (EdmComplexType) edmProperty.getType(), property,
ComplexSerializerOptions.with().contextURL(contextURL).build()).getContent() :
serializer.primitive((EdmPrimitiveType) edmProperty.getType(), property,
serializer.primitive(edm, (EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(contextURL)
.scale(edmProperty.getScale())