OLINGO-573: merging to master
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/3ac433b0 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/3ac433b0 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/3ac433b0 Branch: refs/heads/OLINGO-573 Commit: 3ac433b0771fcfc3edf3c205f4a037c302e547d5 Parents: 547725d Author: Ramesh Reddy <[email protected]> Authored: Sun Apr 5 17:54:44 2015 -0500 Committer: Ramesh Reddy <[email protected]> Committed: Mon Apr 20 08:59:28 2015 -0500 ---------------------------------------------------------------------- lib/server-core-ext/pom.xml | 1 - .../server/core/ReturnRepresentation.java | 2 +- .../olingo/server/core/ServiceRequest.java | 17 ++- .../server/core/requests/ActionRequest.java | 29 ++++- .../server/core/requests/DataRequest.java | 110 +++++++++++++++---- .../server/core/requests/FunctionRequest.java | 29 +++-- .../server/core/responses/EntityResponse.java | 62 +++++++++-- .../core/responses/EntitySetResponse.java | 13 ++- .../server/core/responses/MetadataResponse.java | 9 ++ .../core/responses/PrimitiveValueResponse.java | 10 ++ .../server/core/responses/PropertyResponse.java | 15 +++ .../server/core/responses/ResponseUtil.java | 86 +++++++++++++++ .../core/responses/ServiceDocumentResponse.java | 9 ++ .../server/core/responses/ServiceResponse.java | 9 ++ .../server/core/ServiceDispatcherTest.java | 4 - .../olingo/server/example/TripPinDataModel.java | 93 ++++++++-------- .../olingo/server/example/TripPinHandler.java | 40 ++----- .../server/example/TripPinServiceTest.java | 22 +++- .../src/test/resources/airlines.json | 6 +- .../serializer/json/ODataJsonSerializer.java | 6 + 20 files changed, 437 insertions(+), 135 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/pom.xml ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/pom.xml b/lib/server-core-ext/pom.xml index 5249ed4..6070052 100644 --- a/lib/server-core-ext/pom.xml +++ b/lib/server-core-ext/pom.xml @@ -81,7 +81,6 @@ <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <scope>test</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ReturnRepresentation.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ReturnRepresentation.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ReturnRepresentation.java index e9a213e..6779d76 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ReturnRepresentation.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ReturnRepresentation.java @@ -19,5 +19,5 @@ package org.apache.olingo.server.core; public enum ReturnRepresentation { - REPRESENTATION, MINIMAL + REPRESENTATION, MINIMAL, NONE } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java index e9a8cfe..0fda018 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java @@ -41,6 +41,7 @@ import org.apache.olingo.server.api.serializer.CustomContentTypeSupport; import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions; import org.apache.olingo.server.api.serializer.EntitySerializerOptions; import org.apache.olingo.server.api.serializer.ODataSerializer; +import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.core.requests.DataRequest; @@ -155,19 +156,23 @@ public abstract class ServiceRequest { } else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) { return (T) ComplexSerializerOptions.with().contextURL(contextUrl) .expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption()).build(); + } else if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) { + return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl) + .build(); } return null; } public ReturnRepresentation getReturnRepresentation() { String prefer = this.request.getHeader(HttpHeader.PREFER); - if (prefer == null) { - return ReturnRepresentation.REPRESENTATION; - } - if (prefer.contains("return=minimal")) { //$NON-NLS-1$ - return ReturnRepresentation.MINIMAL; + if (prefer != null) { + if (prefer.contains("return=minimal")) { //$NON-NLS-1$ + return ReturnRepresentation.MINIMAL; + } else if (prefer.contains("return=representation")) { + return ReturnRepresentation.REPRESENTATION; + } } - return ReturnRepresentation.REPRESENTATION; + return ReturnRepresentation.NONE; } public String getHeader(String key) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java index 133ee3e..d4502cc 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java @@ -19,6 +19,9 @@ package org.apache.olingo.server.core.requests; +import java.io.InputStream; + +import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmReturnType; import org.apache.olingo.server.api.OData; @@ -26,7 +29,9 @@ import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; +import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.uri.UriResourceAction; +import org.apache.olingo.server.core.ContentNegotiatorException; import org.apache.olingo.server.core.ServiceHandler; import org.apache.olingo.server.core.responses.EntityResponse; import org.apache.olingo.server.core.responses.EntitySetResponse; @@ -59,10 +64,7 @@ public class ActionRequest extends OperationRequest { if (!hasReturnType()) { handler.invoke(this, getETag(), new NoContentResponse(getServiceMetaData(), response)); } else { - if (isReturnTypePrimitive()) { - handler.invoke(this, getETag(), - PrimitiveValueResponse.getInstance(this, response, isCollection(), getReturnType())); - } else if (isReturnTypeComplex()) { + if (isReturnTypePrimitive() || isReturnTypeComplex()) { handler.invoke(this, getETag(), PropertyResponse.getInstance(this, response, getReturnType().getType(), getContextURL(this.odata), isCollection())); } else { @@ -83,6 +85,21 @@ public class ActionRequest extends OperationRequest { // 11.5.4.1 Invoking an Action - only allows POST return (isPOST()); } + + @Override + public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl, boolean references) + throws ContentNegotiatorException { + if (hasReturnType() && serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) { + return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl) + .nullable(getReturnType().isNullable()) + .maxLength(getReturnType().getMaxLength()) + .precision(getReturnType().getPrecision()) + .scale(getReturnType().getScale()) + .unicode(null) + .build(); + } + return super.getSerializerOptions(serilizerOptions, contextUrl, references); + } public UriResourceAction getUriResourceAction() { return uriResourceAction; @@ -117,4 +134,8 @@ public class ActionRequest extends OperationRequest { public boolean hasReturnType() { return getAction().getReturnType() != null; } + + public InputStream getPayload() { + return getODataRequest().getBody(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java index cebaf64..8855486 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java @@ -18,27 +18,31 @@ */ package org.apache.olingo.server.core.requests; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.LinkedList; import java.util.List; +import org.apache.commons.io.IOUtils; import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.api.data.ValueType; import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmNavigationProperty; +import org.apache.olingo.commons.api.edm.EdmNavigationPropertyBinding; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpHeader; -import org.apache.olingo.commons.core.data.PropertyImpl; import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.commons.core.edm.primitivetype.EdmStream; import org.apache.olingo.server.api.OData; @@ -66,6 +70,7 @@ import org.apache.olingo.server.api.uri.UriResourceProperty; import org.apache.olingo.server.api.uri.UriResourceSingleton; import org.apache.olingo.server.core.ContentNegotiator; import org.apache.olingo.server.core.ContentNegotiatorException; +import org.apache.olingo.server.core.ReturnRepresentation; import org.apache.olingo.server.core.ServiceHandler; import org.apache.olingo.server.core.ServiceRequest; import org.apache.olingo.server.core.responses.CountResponse; @@ -261,6 +266,11 @@ public class DataRequest extends ServiceRequest { if (!getNavigations().isEmpty() && !isGET()) { return false; } + + if ((isGET() || isDELETE()) && getReturnRepresentation() != ReturnRepresentation.NONE) { + return false; + } + return true; } @@ -290,7 +300,8 @@ public class DataRequest extends ServiceRequest { // an If-None-Match or an If-Modified-Since header fields is undefined // by this specification. boolean ifMatch = getHeader(HttpHeader.IF_MATCH) != null; - boolean ifNoneMatch = getHeader(HttpHeader.IF_NONE_MATCH).equals("*"); + boolean ifNoneMatch = (getHeader(HttpHeader.IF_NONE_MATCH)!= null + && getHeader(HttpHeader.IF_NONE_MATCH).equals("*")); if(ifMatch) { handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(), entityResponse); @@ -332,6 +343,10 @@ public class DataRequest extends ServiceRequest { @Override public boolean allowedMethod() { + if (getReturnRepresentation() != ReturnRepresentation.NONE) { + return false; + } + return isGET(); } @@ -359,6 +374,10 @@ public class DataRequest extends ServiceRequest { @Override public boolean allowedMethod() { + if ((isGET() || isDELETE()) && getReturnRepresentation() != ReturnRepresentation.NONE) { + return false; + } + // references are only allowed on the navigation properties if (getNavigations().isEmpty()) { return false; @@ -448,6 +467,10 @@ public class DataRequest extends ServiceRequest { @Override public boolean allowedMethod() { + if ((isGET() || isDELETE() || isPropertyStream()) && getReturnRepresentation() != ReturnRepresentation.NONE) { + return false; + } + // create of properties is not allowed, // only read, update, delete. Note that delete is // same as update with null @@ -502,13 +525,11 @@ public class DataRequest extends ServiceRequest { } } else if (isDELETE()) { if (isPropertyStream()) { - handler.upsertStreamProperty(DataRequest.this, getETag(), request.getBody(), + handler.upsertStreamProperty(DataRequest.this, getETag(), null, new NoContentResponse(getServiceMetaData(), response)); } else { - Property property = new PropertyImpl(); - property.setName(edmProperty.getName()); - property.setType(edmProperty.getType().getFullQualifiedName() - .getFullQualifiedNameAsString()); + Property property = new Property(edmProperty.getType().getFullQualifiedName() + .getFullQualifiedNameAsString(), edmProperty.getName()); handler.updateProperty(DataRequest.this, property, false, getETag(), buildResponse(response, edmProperty)); } @@ -527,8 +548,8 @@ public class DataRequest extends ServiceRequest { final UriHelper helper = odata.createUriHelper(); EdmProperty edmProperty = getUriResourceProperty().getProperty(); - ContextURL.Builder builder = ContextURL.with().entitySet(getEntitySet()); - builder = ContextURL.with().entitySet(getEntitySet()); + ContextURL.Builder builder = + ContextURL.with().entitySetOrSingletonOrType(getTargetEntitySet(getEntitySet(), getNavigations())); builder.keyPath(helper.buildContextURLKeyPredicate(getUriResourceEntitySet() .getKeyPredicates())); String navPath = buildNavPath(helper, getEntitySet().getEntityType(), getNavigations(), true); @@ -551,11 +572,17 @@ public class DataRequest extends ServiceRequest { @Override public boolean allowedMethod() { - //part2-url-conventions # 4.2 + //part2-url-conventions # 4.7 + // Properties of type Edm.Stream already return the raw value of + // the media stream and do not support appending the $value segment. if (isPropertyStream() && isGET()) { return false; } + if ((isGET() || isDELETE() || isPropertyStream()) && getReturnRepresentation() != ReturnRepresentation.NONE) { + return false; + } + return isGET() || isDELETE() || isPUT(); } @@ -576,17 +603,20 @@ public class DataRequest extends ServiceRequest { handler.read(DataRequest.this, PrimitiveValueResponse.getInstance(DataRequest.this, response, isCollection(), getUriResourceProperty().getProperty())); } else if (isDELETE()) { - Property property = new PropertyImpl(); - property.setName(edmProperty.getName()); - property.setType(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString()); - + Property property = new Property( + edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString(), + edmProperty.getName()); PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response, edmProperty.getType(), getContextURL(odata), edmProperty.isCollection()); handler.updateProperty(DataRequest.this, property, false, getETag(), propertyResponse); } else if (isPUT()) { PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response, edmProperty.getType(), getContextURL(odata), edmProperty.isCollection()); - handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), false, + Property property = new Property( + edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString(), + edmProperty.getName()); + property.setValue(ValueType.PRIMITIVE, getRawValueFromClient(edmProperty)); + handler.updateProperty(DataRequest.this, property, false, getETag(), propertyResponse); } } @@ -659,20 +689,38 @@ public class DataRequest extends ServiceRequest { private org.apache.olingo.commons.api.data.Property getPropertyValueFromClient( EdmProperty edmProperty) throws DeserializerException { - // TODO:this is not right, we should be deserializing the property - // (primitive, complex, collection of) - // for now it is responsibility of the user ODataDeserializer deserializer = odata.createDeserializer(ODataFormat .fromContentType(getRequestContentType())); return deserializer.property(getODataRequest().getBody(), edmProperty).getProperty(); } + + private Object getRawValueFromClient( + EdmProperty edmProperty) throws DeserializerException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(1024); + byte[] buffer = new byte[1024]; + int read = 0; + do { + try { + read = IOUtils.read(getODataRequest().getBody(), buffer, 0, 1024); + bos.write(buffer, 0, read); + if (read < 1024) { + break; + } + } catch (IOException e) { + new DeserializerException("Error reading raw value", + SerializerException.MessageKeys.IO_EXCEPTION); + } + } while (true); + return bos.toByteArray(); + } static ContextURL.Builder buildEntitySetContextURL(UriHelper helper, EdmBindingTarget edmEntitySet, List<UriParameter> keyPredicates, UriInfo uriInfo, LinkedList<UriResourceNavigation> navigations, boolean collectionReturn, boolean singleton) throws SerializerException { - ContextURL.Builder builder = ContextURL.with().entitySetOrSingletonOrType(edmEntitySet.getName()); + ContextURL.Builder builder = + ContextURL.with().entitySetOrSingletonOrType(getTargetEntitySet(edmEntitySet, navigations)); String select = helper.buildContextURLSelectList(edmEntitySet.getEntityType(), uriInfo.getExpandOption(), uriInfo.getSelectOption()); if (!singleton) { @@ -718,6 +766,30 @@ public class DataRequest extends ServiceRequest { return result.length() == 0?null:result.toString(); } + static String getTargetEntitySet(EdmBindingTarget root, LinkedList<UriResourceNavigation> navigations) { + EdmEntityType type = root.getEntityType(); + EdmBindingTarget targetEntitySet = root; + String targetEntitySetName = root.getName(); + String name = null; + for (UriResourceNavigation nav:navigations) { + name = nav.getProperty().getName(); + EdmNavigationProperty property = type.getNavigationProperty(name); + if (property.containsTarget()) { + return root.getName(); + } + type = nav.getProperty().getType(); + + for(EdmNavigationPropertyBinding enb:targetEntitySet.getNavigationPropertyBindings()) { + if (enb.getPath().equals(name)) { + targetEntitySetName = enb.getTarget(); + } else if (enb.getPath().endsWith("/"+name)) { + targetEntitySetName = enb.getTarget(); + } + } + } + return targetEntitySetName; + } + static String buildNavPath(UriHelper helper, EdmEntityType rootType, LinkedList<UriResourceNavigation> navigations, boolean includeLastPredicates) throws SerializerException { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java index a9f9341..b77fb2b 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java @@ -21,6 +21,7 @@ package org.apache.olingo.server.core.requests; import java.util.List; +import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.edm.EdmReturnType; import org.apache.olingo.server.api.OData; @@ -28,8 +29,10 @@ import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; +import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.uri.UriParameter; import org.apache.olingo.server.api.uri.UriResourceFunction; +import org.apache.olingo.server.core.ContentNegotiatorException; import org.apache.olingo.server.core.ServiceHandler; import org.apache.olingo.server.core.responses.EntityResponse; import org.apache.olingo.server.core.responses.EntitySetResponse; @@ -52,14 +55,9 @@ public class FunctionRequest extends OperationRequest { } // Functions always have return per 11.5.3 - if (isReturnTypePrimitive()) { - // functions can not return a typed property in the context of entity, so - // it must be treated - // as value based response - handler.invoke(this, getODataRequest().getMethod(), - PrimitiveValueResponse.getInstance(this, response, isCollection(), getReturnType())); - } else if (isReturnTypeComplex()) { - handler.invoke(this, getODataRequest().getMethod(), PropertyResponse.getInstance(this, response, + if (isReturnTypePrimitive() || isReturnTypeComplex()) { + // per odata-json-format/v4.0 = 11 Individual Property or Operation Response + handler.invoke(this, getODataRequest().getMethod(), PropertyResponse.getInstance(this, response, getReturnType().getType(), getContextURL(this.odata), isCollection())); } else { // returnType.getType().getKind() == EdmTypeKind.ENTITY @@ -83,6 +81,21 @@ public class FunctionRequest extends OperationRequest { return isGET(); } + @Override + public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl, boolean references) + throws ContentNegotiatorException { + if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) { + return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl) + .nullable(getReturnType().isNullable()) + .maxLength(getReturnType().getMaxLength()) + .precision(getReturnType().getPrecision()) + .scale(getReturnType().getScale()) + .unicode(null) + .build(); + } + return super.getSerializerOptions(serilizerOptions, contextUrl, references); + } + public UriResourceFunction getUriResourceFunction() { return uriResourceFunction; } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java index e90681d..eb79c07 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java @@ -22,12 +22,14 @@ import java.util.Map; import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.Entity; +import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.serializer.EntitySerializerOptions; @@ -42,15 +44,17 @@ public class EntityResponse extends ServiceResponse { private final ODataSerializer serializer; private final EntitySerializerOptions options; private final ContentType responseContentType; + private final String baseURL; private EntityResponse(ServiceMetadata metadata, ODataResponse response, ODataSerializer serializer, EntitySerializerOptions options, ContentType responseContentType, - Map<String, String> preferences, ReturnRepresentation returnRepresentation) { + Map<String, String> preferences, ReturnRepresentation returnRepresentation, String baseURL) { super(metadata, response, preferences); this.serializer = serializer; this.options = options; this.responseContentType = responseContentType; this.returnRepresentation = returnRepresentation; + this.baseURL = baseURL; } public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL, @@ -59,7 +63,8 @@ public class EntityResponse extends ServiceResponse { EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class, contextURL, references); return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(), - options, request.getResponseContentType(), request.getPreferences(), returnRepresentation); + options, request.getResponseContentType(), request.getPreferences(), returnRepresentation, + request.getODataRequest().getRawBaseUri()); } public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL, @@ -68,7 +73,8 @@ public class EntityResponse extends ServiceResponse { EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class, contextURL, references); return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(), - options, request.getResponseContentType(), request.getPreferences(), null); + options, request.getResponseContentType(), request.getPreferences(), null, + request.getODataRequest().getRawBaseUri()); } // write single entity @@ -87,19 +93,24 @@ public class EntityResponse extends ServiceResponse { close(); } - public void writeCreatedEntity(EdmEntityType entityType, Entity entity, String locationHeader) + public void writeCreatedEntity(EdmEntitySet entitySet, Entity entity) throws SerializerException { // upsert/insert must created a entity, otherwise should have throw an // exception assert (entity != null); + + String locationHeader = buildLocation(this.baseURL, entity, entitySet.getName(), entitySet.getEntityType()); // Note that if media written just like Stream, but on entity URL // 8.2.8.7 - if (this.returnRepresentation == ReturnRepresentation.MINIMAL) { + if (this.returnRepresentation == ReturnRepresentation.MINIMAL || + this.returnRepresentation == ReturnRepresentation.NONE) { writeNoContent(false); writeHeader(HttpHeader.LOCATION, locationHeader); - writeHeader("Preference-Applied", "return=minimal"); //$NON-NLS-1$ //$NON-NLS-2$ + if (this.returnRepresentation == ReturnRepresentation.MINIMAL) { + writeHeader("Preference-Applied", "return=minimal"); //$NON-NLS-1$ //$NON-NLS-2$ + } // 8.3.3 writeHeader("OData-EntityId", entity.getId().toASCIIString()); //$NON-NLS-1$ close(); @@ -107,7 +118,8 @@ public class EntityResponse extends ServiceResponse { } // return the content of the created entity - this.response.setContent(this.serializer.entity(this.metadata, entityType, entity, this.options).getContent()); + this.response.setContent(this.serializer.entity(this.metadata, entitySet.getEntityType(), entity, this.options) + .getContent()); writeCreated(false); writeHeader(HttpHeader.LOCATION, locationHeader); writeHeader("Preference-Applied", "return=representation"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -137,4 +149,40 @@ public class EntityResponse extends ServiceResponse { close(); } } + + public void writeError(ODataServerError error) { + try { + writeContent(this.serializer.error(error).getContent(), error.getStatusCode(), true); + } catch (SerializerException e) { + writeServerError(true); + } + } + + public void writeNotModified() { + this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode()); + close(); + } + + public static String buildLocation(String baseURL, Entity entity, String enitySetName, EdmEntityType type) { + String location = baseURL + "/" + enitySetName + "("; + int i = 0; + boolean usename = type.getKeyPredicateNames().size() > 1; + + for (String key : type.getKeyPredicateNames()) { + if (i > 0) { + location += ","; + } + i++; + if (usename) { + location += (key + "="); + } + if (entity.getProperty(key).getType().equals("Edm.String")) { + location = location + "'" + entity.getProperty(key).getValue().toString() + "'"; + } else { + location = location + entity.getProperty(key).getValue().toString(); + } + } + location += ")"; + return location; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java index c70854b..27675c3 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java @@ -21,11 +21,12 @@ package org.apache.olingo.server.core.responses; import java.util.Map; import org.apache.olingo.commons.api.data.ContextURL; -import org.apache.olingo.commons.api.data.EntitySet; +import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions; @@ -58,7 +59,7 @@ public class EntitySetResponse extends ServiceResponse { // write collection of entities // TODO: server paging needs to be implemented. - public void writeReadEntitySet(EdmEntityType entityType, EntitySet entitySet) + public void writeReadEntitySet(EdmEntityType entityType, EntityCollection entitySet) throws SerializerException { assert (!isClosed()); @@ -80,4 +81,12 @@ public class EntitySetResponse extends ServiceResponse { ODataApplicationException { visitor.visit(this); } + + public void writeError(ODataServerError error) { + try { + writeContent(this.serializer.error(error).getContent(), error.getStatusCode(), true); + } catch (SerializerException e) { + writeServerError(true); + } + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java index b325421..a644358 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.serializer.ODataSerializer; @@ -59,4 +60,12 @@ public class MetadataResponse extends ServiceResponse { ODataApplicationException { visitor.visit(this); } + + public void writeError(ODataServerError error) { + try { + writeContent(this.serializer.error(error).getContent(), error.getStatusCode(), true); + } catch (SerializerException e) { + writeServerError(true); + } + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java index 005bfca..d5fa32b 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java @@ -18,6 +18,7 @@ */ package org.apache.olingo.server.core.responses; +import java.io.ByteArrayInputStream; import java.util.Map; import org.apache.olingo.commons.api.edm.EdmPrimitiveType; @@ -92,6 +93,15 @@ public class PrimitiveValueResponse extends ServiceResponse { writeOK(HttpContentType.TEXT_PLAIN); } + + public void writeEdmBinary(byte[] value) throws SerializerException { + if (value == null) { + writeNoContent(true); + return; + } + this.response.setContent(new ByteArrayInputStream(value)); + writeOK(HttpContentType.APPLICATION_OCTET_STREAM); + } public boolean isReturnCollection() { return returnCollection; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java index 79ac90d..86ce46f 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java @@ -27,8 +27,10 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.constants.EdmTypeKind; import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.serializer.ComplexSerializerOptions; @@ -141,4 +143,17 @@ public class PropertyResponse extends ServiceResponse { public void writePropertyDeleted() { writeNoContent(true); } + + public void writeError(ODataServerError error) { + try { + writeContent(this.serializer.error(error).getContent(), error.getStatusCode(), true); + } catch (SerializerException e) { + writeServerError(true); + } + } + + public void writeNotModified() { + this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode()); + close(); + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ResponseUtil.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ResponseUtil.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ResponseUtil.java new file mode 100644 index 0000000..257f8c7 --- /dev/null +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ResponseUtil.java @@ -0,0 +1,86 @@ +/* + * 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.responses; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.olingo.commons.api.data.ComplexValue; +import org.apache.olingo.commons.api.data.Entity; +import org.apache.olingo.commons.api.data.EntityCollection; +import org.apache.olingo.commons.api.data.Link; +import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.api.data.ValueType; +import org.apache.olingo.commons.api.domain.ODataLinkType; + +public class ResponseUtil { + public static Property createPrimitive(final String name, final String type, final Object value) { + return new Property(type, name, ValueType.PRIMITIVE, value); + } + + public static Property createPrimitiveCollection(final String name, final Object... values) { + return new Property(null, name, ValueType.COLLECTION_PRIMITIVE, Arrays.asList(values)); + } + + public static Property createComplex(final String name, final String type, final Property... properties) { + ComplexValue complexValue = new ComplexValue(); + for (final Property property : properties) { + complexValue.getValue().add(property); + } + return new Property(type, name, ValueType.COMPLEX, complexValue); + } + + public static Property createComplexCollection(final String name, final String type, + final List<Property>... propertiesList) { + List<ComplexValue> complexCollection = new ArrayList<ComplexValue>(); + for (final List<Property> properties : propertiesList) { + ComplexValue complexValue = new ComplexValue(); + complexValue.getValue().addAll(properties); + complexCollection.add(complexValue); + } + return new Property(type, name, ValueType.COLLECTION_COMPLEX, complexCollection); + } + + public static void setLink(Entity entity, final String navigationPropertyName, final Entity target) { + Link link = entity.getNavigationLink(navigationPropertyName); + if (link == null) { + link = new Link(); + link.setType(ODataLinkType.ENTITY_NAVIGATION.toString()); + link.setTitle(navigationPropertyName); + entity.getNavigationLinks().add(link); + } + link.setInlineEntity(target); + } + + public static void setLinks(Entity entity, final String navigationPropertyName, final Entity... targets) { + Link link = entity.getNavigationLink(navigationPropertyName); + if (link == null) { + link = new Link(); + link.setType(ODataLinkType.ENTITY_SET_NAVIGATION.toString()); + link.setTitle(navigationPropertyName); + EntityCollection target = new EntityCollection(); + target.getEntities().addAll(Arrays.asList(targets)); + link.setInlineEntitySet(target); + entity.getNavigationLinks().add(link); + } else { + link.getInlineEntitySet().getEntities().addAll(Arrays.asList(targets)); + } + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java index 8b77684..0f3733c 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.serializer.ODataSerializer; @@ -60,4 +61,12 @@ public class ServiceDocumentResponse extends ServiceResponse { ODataApplicationException { visitor.visit(this); } + + public void writeError(ODataServerError error) { + try { + writeContent(this.serializer.error(error).getContent(), error.getStatusCode(), true); + } catch (SerializerException e) { + writeServerError(true); + } + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java index a306551..bf000e0 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java @@ -19,6 +19,7 @@ package org.apache.olingo.server.core.responses; +import java.io.InputStream; import java.util.Map; import org.apache.olingo.commons.api.http.HttpHeader; @@ -105,6 +106,14 @@ public abstract class ServiceResponse { this.response.setHeader(key, value); } } + + public void writeContent(InputStream content, int statusCode, boolean closeResponse) { + this.response.setContent(content); + this.response.setStatusCode(statusCode); + if (closeResponse) { + close(); + } + } /** * When true; the "Preference-Applied" header is strictly checked. http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java index faabafc..a289738 100644 --- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java +++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java @@ -36,7 +36,6 @@ import org.apache.catalina.startup.Tomcat; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -62,7 +61,6 @@ import org.apache.olingo.server.core.responses.NoContentResponse; import org.apache.olingo.server.core.responses.PrimitiveValueResponse; import org.apache.olingo.server.core.responses.PropertyResponse; import org.apache.olingo.server.core.responses.StreamResponse; -import org.apache.olingo.server.example.TripPinServiceTest; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -70,7 +68,6 @@ import org.mockito.Mockito; public class ServiceDispatcherTest { private static final int TOMCAT_PORT = 9900; private Tomcat tomcat = new Tomcat(); - private String baseURL; public class SampleODataServlet extends HttpServlet { private final ServiceHandler handler; // must be stateless @@ -103,7 +100,6 @@ public class ServiceDispatcherTest { Context cxt = tomcat.addContext("/trippin", baseDir.getAbsolutePath()); Tomcat.addServlet(cxt, "trippin", new SampleODataServlet(serviceHandler, edmProvider)); cxt.addServletMapping("/*", "trippin"); - baseURL = "http://" + tomcat.getHost().getName() + ":"+ TOMCAT_PORT; tomcat.setPort(TOMCAT_PORT); tomcat.start(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java index 055f073..a960d67 100644 --- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java +++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java @@ -33,7 +33,7 @@ import java.util.Map; import java.util.UUID; import org.apache.olingo.commons.api.data.Entity; -import org.apache.olingo.commons.api.data.EntitySet; +import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.edm.EdmEntityContainer; @@ -45,21 +45,19 @@ import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.constants.EdmTypeKind; -import org.apache.olingo.commons.core.data.EntityImpl; -import org.apache.olingo.commons.core.data.EntitySetImpl; -import org.apache.olingo.commons.core.data.LinkImpl; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.uri.UriParameter; import org.apache.olingo.server.api.uri.UriResourceNavigation; import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer; +import org.apache.olingo.server.core.responses.EntityResponse; import com.fasterxml.jackson.databind.ObjectMapper; public class TripPinDataModel { private final ServiceMetadata metadata; - private HashMap<String, EntitySet> entitySetMap; + private HashMap<String, EntityCollection> entitySetMap; private Map<Integer, Map> tripLinks; private Map<String, Map> peopleLinks; private Map<Integer, Map> flightLinks; @@ -70,7 +68,7 @@ public class TripPinDataModel { } public void loadData() throws Exception { - this.entitySetMap = new HashMap<String, EntitySet>(); + this.entitySetMap = new HashMap<String, EntityCollection>(); this.tripLinks = new HashMap<Integer, Map>(); this.peopleLinks = new HashMap<String, Map>(); this.flightLinks = new HashMap<Integer, Map>(); @@ -78,7 +76,7 @@ public class TripPinDataModel { EdmEntityContainer ec = metadata.getEdm().getEntityContainer(null); for (EdmEntitySet edmEntitySet : ec.getEntitySets()) { String entitySetName = edmEntitySet.getName(); - EntitySet set = loadEnities(entitySetName, edmEntitySet.getEntityType()); + EntityCollection set = loadEnities(entitySetName, edmEntitySet.getEntityType()); if (set != null) { this.entitySetMap.put(entitySetName, set); } @@ -119,19 +117,19 @@ public class TripPinDataModel { } } - private EntitySet loadEnities(String entitySetName, EdmEntityType type) { + private EntityCollection loadEnities(String entitySetName, EdmEntityType type) { try { ODataJsonDeserializer deserializer = new ODataJsonDeserializer(); - EntitySet set = deserializer.entityCollection(new FileInputStream(new File( + EntityCollection set = deserializer.entityCollection(new FileInputStream(new File( "src/test/resources/" + entitySetName.toLowerCase() + ".json")), type).getEntityCollection(); // TODO: the count needs to be part of deserializer set.setCount(set.getEntities().size()); for (Entity entity : set.getEntities()) { - ((EntityImpl) entity).setETag(UUID.randomUUID().toString()); - ((EntityImpl) entity).setId(new URI(TripPinHandler.buildLocation(entity, entitySetName, + entity.setETag(UUID.randomUUID().toString()); + entity.setId(new URI(EntityResponse.buildLocation("", entity, entitySetName, type))); - ((EntityImpl) entity).setType(type.getFullQualifiedName().getFullQualifiedNameAsString()); + entity.setType(type.getFullQualifiedName().getFullQualifiedNameAsString()); } return set; } catch (FileNotFoundException e) { @@ -149,17 +147,17 @@ public class TripPinDataModel { return null; } - public EntitySet getEntitySet(String name) { + public EntityCollection getEntitySet(String name) { return getEntitySet(name, -1, -1); } - public EntitySet getEntitySet(String name, int skip, int pageSize) { - EntitySet set = this.entitySetMap.get(name); + public EntityCollection getEntitySet(String name, int skip, int pageSize) { + EntityCollection set = this.entitySetMap.get(name); if (set == null) { return null; } - EntitySetImpl modifiedES = new EntitySetImpl(); + EntityCollection modifiedES = new EntityCollection(); int i = 0; for (Entity e : set.getEntities()) { if (skip >= 0 && i >= skip && modifiedES.getEntities().size() < pageSize) { @@ -232,11 +230,11 @@ public class TripPinDataModel { } public Entity getEntity(String name, List<UriParameter> keys) throws ODataApplicationException { - EntitySet es = getEntitySet(name); + EntityCollection es = getEntitySet(name); return getEntity(es, keys); } - public Entity getEntity(EntitySet es, List<UriParameter> keys) throws ODataApplicationException { + public Entity getEntity(EntityCollection es, List<UriParameter> keys) throws ODataApplicationException { List<Entity> search = es.getEntities(); for (UriParameter param : keys) { search = getMatch(param, search); @@ -247,15 +245,15 @@ public class TripPinDataModel { return search.get(0); } - private EntitySet getFriends(String userName) { + private EntityCollection getFriends(String userName) { Map<String, Object> map = this.peopleLinks.get(userName); if (map == null) { return null; } ArrayList<String> friends = (ArrayList<String>) map.get("Friends"); - EntitySet set = getEntitySet("People"); + EntityCollection set = getEntitySet("People"); - EntitySetImpl result = new EntitySetImpl(); + EntityCollection result = new EntityCollection(); int i = 0; if (friends != null) { for (String friend : friends) { @@ -272,16 +270,16 @@ public class TripPinDataModel { return result; } - private EntitySet getTrips(String userName) { + private EntityCollection getTrips(String userName) { Map<String, Object> map = this.peopleLinks.get(userName); if (map == null) { return null; } ArrayList<Integer> trips = (ArrayList<Integer>) map.get("Trips"); - EntitySet set = getEntitySet("Trip"); + EntityCollection set = getEntitySet("Trip"); - EntitySetImpl result = new EntitySetImpl(); + EntityCollection result = new EntityCollection(); int i = 0; if (trips != null) { for (int trip : trips) { @@ -305,7 +303,7 @@ public class TripPinDataModel { } Integer photoID = (Integer) map.get("Photo"); - EntitySet set = getEntitySet("Photos"); + EntityCollection set = getEntitySet("Photos"); if (photoID != null) { for (Entity e : set.getEntities()) { if (e.getProperty("Id").getValue().equals(photoID.longValue())) { @@ -316,20 +314,20 @@ public class TripPinDataModel { return null; } - private EntitySet getPlanItems(int tripId, EntitySetImpl result) { + private EntityCollection getPlanItems(int tripId, EntityCollection result) { getFlights(tripId, result); getEvents(tripId, result); return result; } - private EntitySet getEvents(int tripId, EntitySetImpl result) { + private EntityCollection getEvents(int tripId, EntityCollection result) { Map<Integer, Object> map = this.tripLinks.get(tripId); if (map == null) { return null; } ArrayList<Integer> events = (ArrayList<Integer>) map.get("Events"); - EntitySet set = getEntitySet("Event"); + EntityCollection set = getEntitySet("Event"); int i = result.getEntities().size(); if (events != null) { for (int event : events) { @@ -346,14 +344,14 @@ public class TripPinDataModel { return result; } - private EntitySet getFlights(int tripId, EntitySetImpl result) { + private EntityCollection getFlights(int tripId, EntityCollection result) { Map<Integer, Object> map = this.tripLinks.get(tripId); if (map == null) { return null; } ArrayList<Integer> flights = (ArrayList<Integer>) map.get("Flights"); - EntitySet set = getEntitySet("Flight"); + EntityCollection set = getEntitySet("Flight"); int i = result.getEntities().size(); if (flights != null) { for (int flight : flights) { @@ -370,7 +368,7 @@ public class TripPinDataModel { return result; } - private EntitySet getTripPhotos(int tripId) { + private EntityCollection getTripPhotos(int tripId) { Map<Integer, Object> map = this.tripLinks.get(tripId); if (map == null) { return null; @@ -378,8 +376,8 @@ public class TripPinDataModel { ArrayList<Integer> photos = (ArrayList<Integer>) map.get("Photos"); - EntitySet set = getEntitySet("Photos"); - EntitySetImpl result = new EntitySetImpl(); + EntityCollection set = getEntitySet("Photos"); + EntityCollection result = new EntityCollection(); int i = 0; if (photos != null) { for (int photo : photos) { @@ -403,7 +401,7 @@ public class TripPinDataModel { } String from = (String) map.get("From"); - EntitySet set = getEntitySet("Airports"); + EntityCollection set = getEntitySet("Airports"); if (from != null) { for (Entity e : set.getEntities()) { @@ -422,7 +420,7 @@ public class TripPinDataModel { } String to = (String) map.get("To"); - EntitySet set = getEntitySet("Airports"); + EntityCollection set = getEntitySet("Airports"); if (to != null) { for (Entity e : set.getEntities()) { @@ -441,7 +439,7 @@ public class TripPinDataModel { } String airline = (String) map.get("Airline"); - EntitySet set = getEntitySet("Airlines"); + EntityCollection set = getEntitySet("Airlines"); if (airline != null) { for (Entity e : set.getEntities()) { @@ -560,7 +558,7 @@ public class TripPinDataModel { protected static void setLink(Entity entity, final String navigationPropertyName, final Entity target) { - Link link = new LinkImpl(); + Link link = new Link(); link.setTitle(navigationPropertyName); link.setInlineEntity(target); entity.getNavigationLinks().add(link); @@ -607,18 +605,19 @@ public class TripPinDataModel { return updated; } - public Entity createEntity(String entitySetName, Entity entity, String location) + public Entity createEntity(EdmEntitySet edmEntitySet, Entity entity, String baseURL) throws ODataApplicationException { - EntitySet set = this.entitySetMap.get(entitySetName); - EntityImpl copy = new EntityImpl(); + EntityCollection set = this.entitySetMap.get(edmEntitySet.getName()); + Entity copy = new Entity(); copy.setType(entity.getType()); for (Property p : entity.getProperties()) { copy.addProperty(p); } try { - copy.setId(new URI(location)); + copy.setId(new URI(EntityResponse.buildLocation(baseURL, entity, edmEntitySet.getName(), edmEntitySet + .getEntityType()))); copy.setETag(UUID.randomUUID().toString()); } catch (URISyntaxException e) { throw new ODataApplicationException("Failed to create ID for entity", 500, @@ -630,7 +629,7 @@ public class TripPinDataModel { } public boolean deleteEntity(String entitySetName, String eTag, String key, Object keyValue) { - EntitySet set = getEntitySet(entitySetName); + EntityCollection set = getEntitySet(entitySetName); Iterator<Entity> it = set.getEntities().iterator(); boolean removed = false; while (it.hasNext()) { @@ -647,7 +646,7 @@ public class TripPinDataModel { public boolean updateProperty(String entitySetName, String eTag, String key, Object keyValue, Property property) { - EntitySet set = getEntitySet(entitySetName); + EntityCollection set = getEntitySet(entitySetName); Iterator<Entity> it = set.getEntities().iterator(); boolean replaced = false; while (it.hasNext()) { @@ -663,20 +662,20 @@ public class TripPinDataModel { return replaced; } - public EntitySet getNavigableEntitySet(Entity parentEntity, UriResourceNavigation navigation) { + public EntityCollection getNavigableEntitySet(Entity parentEntity, UriResourceNavigation navigation) { EdmEntityType type = this.metadata.getEdm().getEntityType( new FullQualifiedName(parentEntity.getType())); String key = type.getKeyPredicateNames().get(0); String linkName = navigation.getProperty().getName(); - EntitySet results = null; + EntityCollection results = null; if (type.getName().equals("Person") && linkName.equals("Friends")) { results = getFriends((String) parentEntity.getProperty(key).getValue()); } else if (type.getName().equals("Person") && linkName.equals("Trips")) { results = getTrips((String) parentEntity.getProperty(key).getValue()); } else if (type.getName().equals("Trip") && linkName.equals("PlanItems")) { - EntitySetImpl planitems = new EntitySetImpl(); + EntityCollection planitems = new EntityCollection(); if (navigation.getTypeFilterOnCollection() == null) { results = getPlanItems((Integer) parentEntity.getProperty(key).getValue(), planitems); } else if (navigation.getTypeFilterOnCollection().getName().equals("Flight")) { @@ -700,7 +699,7 @@ public class TripPinDataModel { String key = type.getKeyPredicateNames().get(0); String linkName = navigation.getProperty().getName(); - EntitySet results = null; + EntityCollection results = null; if (navigation.getProperty().isCollection()) { results = getNavigableEntitySet(parentEntity, navigation); return this.getEntity(results, navigation.getKeyPredicates()); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java index 040a7da..7172818 100644 --- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java +++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java @@ -27,7 +27,7 @@ import java.util.Locale; import java.util.Random; import org.apache.olingo.commons.api.data.Entity; -import org.apache.olingo.commons.api.data.EntitySet; +import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.edm.EdmAction; @@ -36,9 +36,9 @@ import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmSingleton; +import org.apache.olingo.commons.api.edm.provider.EntitySet; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpMethod; -import org.apache.olingo.commons.core.data.EntitySetImpl; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataRequest; @@ -94,7 +94,7 @@ public class TripPinHandler implements ServiceHandler { } static class EntityDetails { - EntitySet entitySet = null; + EntityCollection entitySet = null; Entity entity = null; EdmEntityType entityType; String navigationProperty; @@ -102,7 +102,7 @@ public class TripPinHandler implements ServiceHandler { } private EntityDetails process(final DataRequest request) throws ODataApplicationException { - EntitySet entitySet = null; + EntityCollection entitySet = null; Entity entity = null; EdmEntityType entityType; Entity parentEntity = null; @@ -206,7 +206,7 @@ public class TripPinHandler implements ServiceHandler { response.writeHeader("Preference-Applied", "odata.maxpagesize="+request.getPreference("odata.maxpagesize")); } if (details.entity == null && !request.getNavigations().isEmpty()) { - response.writeReadEntitySet(details.entityType, new EntitySetImpl()); + response.writeReadEntitySet(details.entityType, new EntityCollection()); } else { response.writeReadEntitySet(details.entityType, details.entitySet); } @@ -237,8 +237,7 @@ public class TripPinHandler implements ServiceHandler { throws ODataTranslatedException, ODataApplicationException { EdmEntitySet edmEntitySet = request.getEntitySet(); - String location = buildLocation(entity, edmEntitySet.getName(), edmEntitySet.getEntityType()); - Entity created = this.dataModel.createEntity(edmEntitySet.getName(), entity, location); + Entity created = this.dataModel.createEntity(edmEntitySet, entity, request.getODataRequest().getRawBaseUri()); try { // create references, they come in "@odata.bind" value @@ -271,30 +270,7 @@ public class TripPinHandler implements ServiceHandler { throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault()); } - response.writeCreatedEntity(edmEntitySet.getEntityType(), created, location); - } - - static String buildLocation(Entity entity, String name, EdmEntityType type) { - String location = "/" + name + "("; - int i = 0; - boolean usename = type.getKeyPredicateNames().size() > 1; - - for (String key : type.getKeyPredicateNames()) { - if (i > 0) { - location += ","; - } - i++; - if (usename) { - location += (key + "="); - } - if (entity.getProperty(key).getType().equals("Edm.String")) { - location = location + "'" + entity.getProperty(key).getValue().toString() + "'"; - } else { - location = location + entity.getProperty(key).getValue().toString(); - } - } - location += ")"; - return location; + response.writeCreatedEntity(edmEntitySet, created); } @Override @@ -360,7 +336,7 @@ public class TripPinHandler implements ServiceHandler { final EdmEntityType type = serviceMetadata.getEdm().getEntityContainer(null) .getEntitySet("Airports").getEntityType(); - EntitySet es = this.dataModel.getEntitySet("Airports"); + EntityCollection es = this.dataModel.getEntitySet("Airports"); int i = new Random().nextInt(es.getEntities().size()); final Entity entity = es.getEntities().get(i); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java index 3547b50..1766f1a 100644 --- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java +++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java @@ -147,6 +147,7 @@ public class TripPinServiceTest { JsonNode node = getJSONNode(response); assertEquals("$metadata#Airlines/$entity", node.get("@odata.context").asText()); assertEquals("American Airlines", node.get("Name").asText()); + //assertEquals("/Airlines('AA')/Picture", node.get("[email protected]").asText()); } @Test @@ -278,7 +279,7 @@ public class TripPinServiceTest { @Test public void testLambdaAny() throws Exception { - // this is just testing to see the labba expresions are going through the + // this is just testing to see the lamda expressions are going through the // framework, none of the system options are not implemented in example service String query = "Friends/any(d:d/UserName eq 'foo')"; HttpResponse response = httpGET(baseURL + "/People?$filter="+Encoder.encode(query), 200); @@ -405,10 +406,10 @@ public class TripPinServiceTest { HttpResponse response = httpSend(postRequest, 204); // the below woud be 204, if minimal was not supplied - assertEquals("/People('olingodude')", getHeader(response, "Location")); + assertEquals("http://localhost:9900/trippin/People('olingodude')", getHeader(response, "Location")); assertEquals("return=minimal", getHeader(response, "Preference-Applied")); - String location = baseURL+getHeader(response, "Location"); + String location = getHeader(response, "Location"); response = httpGET(location, 200); EntityUtils.consumeQuietly(response.getEntity()); @@ -527,6 +528,21 @@ public class TripPinServiceTest { } @Test + public void testReadNavigationPropertyNoContainsTarget() throws Exception { + String editUrl = baseURL + "/People('scottketchum')/Photo"; + HttpResponse response = httpGET(editUrl, 200); + + JsonNode node = getJSONNode(response); + assertEquals("$metadata#Photos/$entity", node.get("@odata.context").asText()); + } + + @Test + public void testReadNavigationPropertyNonExistingNavigation() throws Exception { + String editUrl = baseURL + "/People('russellwhyte')/Foobar"; + httpGET(editUrl, 404); + } + + @Test public void testReadNavigationPropertyEntityCollection2() throws Exception { String editUrl = baseURL + "/People('russellwhyte')/Friends('scottketchum')/Trips"; HttpResponse response = httpGET(editUrl, 200); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core-ext/src/test/resources/airlines.json ---------------------------------------------------------------------- diff --git a/lib/server-core-ext/src/test/resources/airlines.json b/lib/server-core-ext/src/test/resources/airlines.json index 78eccdc..1d93aa7 100644 --- a/lib/server-core-ext/src/test/resources/airlines.json +++ b/lib/server-core-ext/src/test/resources/airlines.json @@ -2,7 +2,11 @@ "value":[ { "AirlineCode":"AA", - "Name":"American Airlines" + "Name":"American Airlines", + "[email protected]": "/Airlines('AA')/Picture", + "[email protected]": "/Airlines('AA')/Picture", + "[email protected]": "image/jpeg", + "[email protected]": "12345" }, { "AirlineCode":"FM", http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ac433b0/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java index ff7eff2..1de8562 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java @@ -229,6 +229,12 @@ public class ODataJsonSerializer implements ODataSerializer { if (entity.getMediaContentType() != null) { json.writeStringField(Constants.JSON_MEDIA_CONTENT_TYPE, entity.getMediaContentType()); } + if (entity.getMediaContentSource() != null) { + json.writeStringField(Constants.JSON_MEDIA_READ_LINK, entity.getMediaContentSource().toString()); + } + if (entity.getMediaEditLinks() != null && !entity.getMediaEditLinks().isEmpty()) { + json.writeStringField(Constants.JSON_MEDIA_EDIT_LINK, entity.getMediaEditLinks().get(0).getHref()); + } } } if (onlyReference) {
