From da4d754892c3227437f3c50dfd5de9777dc9631b Mon Sep 17 00:00:00 2001 From: Klaus Straubinger Date: Fri, 12 Dec 2014 14:51:14 +0100 Subject: [PATCH] [OLINGO-507] server support for entity-media create Change-Id: I71f246e72c02fd9df04a8c6b0a8170cdf8e9b6f6 Signed-off-by: Christian Amend --- .../olingo/fit/tecsvc/client/MediaITCase.java | 34 ++++++++ .../org/apache/olingo/server/api/OData.java | 7 ++ .../api/serializer/ODataSerializer.java | 22 ----- .../olingo/server/api/uri/UriHelper.java | 59 +++++++++++++ .../olingo/server/core/ODataHandler.java | 15 +--- .../apache/olingo/server/core/ODataImpl.java | 7 ++ .../serializer/json/ODataJsonSerializer.java | 13 --- .../xml/ODataXmlSerializerImpl.java | 19 +---- .../olingo/server/core/uri/UriHelperImpl.java | 84 +++++++++++++++++++ .../server/tecsvc/data/DataProvider.java | 15 ++++ .../processor/TechnicalEntityProcessor.java | 55 ++++++++---- .../TechnicalPrimitiveComplexProcessor.java | 6 +- .../server/tecsvc/data/DataProviderTest.java | 24 ++++-- .../olingo/server/core/ODataHandlerTest.java | 10 ++- .../json/ODataJsonSerializerTest.java | 17 ++-- .../olingo/server/core/uri/UriHelperTest.java | 82 ++++++++++++++++++ .../sample/processor/CarsProcessor.java | 3 +- 17 files changed, 374 insertions(+), 98 deletions(-) create mode 100644 lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java create mode 100644 lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java create mode 100644 lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java index 8a1ac8f66..e7e4f783f 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java @@ -31,8 +31,10 @@ import org.apache.olingo.client.api.CommonODataClient; import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataMediaRequest; +import org.apache.olingo.client.api.communication.request.streamed.ODataMediaEntityCreateRequest; 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.ODataMediaEntityCreateResponse; import org.apache.olingo.client.api.communication.response.ODataMediaEntityUpdateResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.v4.ODataClient; @@ -118,6 +120,38 @@ public final class MediaITCase extends AbstractBaseTestITCase { assertEquals("just a test", IOUtils.toString(mediaResponse.getBody())); } + @Test + public void create() throws Exception { + final CommonODataClient client = getClient(); + ODataMediaEntityCreateRequest request = + client.getCUDRequestFactory().getMediaEntityCreateRequest( + client.newURIBuilder(TecSvcConst.BASE_URI).appendEntitySetSegment("ESMedia").build(), + IOUtils.toInputStream("just a test")); + request.setContentType(ContentType.TEXT_PLAIN.toContentTypeString()); + assertNotNull(request); + + final ODataMediaEntityCreateResponse response = request.payloadManager().getResponse(); + assertEquals(HttpStatusCode.CREATED.getStatusCode(), response.getStatusCode()); + assertEquals(request.getURI() + "(5)", response.getHeader(HttpHeader.LOCATION).iterator().next()); + final CommonODataEntity entity = response.getBody(); + assertNotNull(entity); + final CommonODataProperty property = entity.getProperty("PropertyInt16"); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals(5, property.getPrimitiveValue().toValue()); + + // Check that the media stream has been created. + // This check has to be in the same session in order to access the same data provider. + ODataMediaRequest mediaRequest = client.getRetrieveRequestFactory().getMediaRequest( + client.newURIBuilder(TecSvcConst.BASE_URI).appendEntitySetSegment("ESMedia") + .appendKeySegment(5).appendValueSegment().build()); + mediaRequest.addCustomHeader(HttpHeader.COOKIE, response.getHeader(HttpHeader.SET_COOKIE).iterator().next()); + ODataRetrieveResponse mediaResponse = mediaRequest.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), mediaResponse.getStatusCode()); + assertEquals(ContentType.TEXT_PLAIN.toContentTypeString(), mediaResponse.getContentType()); + assertEquals("just a test", IOUtils.toString(mediaResponse.getBody())); + } + @Override protected CommonODataClient getClient() { ODataClient odata = ODataClientFactory.getV4(); diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java index 0a6f369c6..7e0562965 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java @@ -28,6 +28,7 @@ import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.serializer.FixedFormatSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.UriHelper; /** * Root object for serving factory tasks and support loose coupling of implementation (core) from the API. @@ -89,4 +90,10 @@ public abstract class OData { * @param references list of edmx references */ public abstract ServiceMetadata createServiceMetadata(EdmProvider edmProvider, List references); + + /** + * Creates a new URI helper object for performing URI-related tasks. + * It can be used in Processor implementations. + */ + public abstract UriHelper createUriHelper(); } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java index 2f16be12a..72f8ee862 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java @@ -19,7 +19,6 @@ package org.apache.olingo.server.api.serializer; import java.io.InputStream; -import java.util.List; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; @@ -28,12 +27,8 @@ import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmPrimitiveType; -import org.apache.olingo.commons.api.edm.EdmStructuredType; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ServiceMetadata; -import org.apache.olingo.server.api.uri.UriParameter; -import org.apache.olingo.server.api.uri.queryoption.ExpandOption; -import org.apache.olingo.server.api.uri.queryoption.SelectOption; /** OData serializer */ public interface ODataSerializer { @@ -114,21 +109,4 @@ public interface ODataSerializer { */ InputStream complexCollection(EdmComplexType type, Property property, ComplexSerializerOptions options) throws SerializerException; - - /** - * Builds the select-list part of a {@link org.apache.olingo.commons.api.data.ContextURL ContextURL}. - * @param type the {@link EdmStructuredType} - * @param expand the $expand option - * @param select the $select option - * @return a String with the select list - */ - String buildContextURLSelectList(EdmStructuredType type, ExpandOption expand, SelectOption select) - throws SerializerException; - - /** - * Builds the key-predicate part of a {@link org.apache.olingo.commons.api.data.ContextURL ContextURL}. - * @param keys the keys as a list of {@link UriParameter} instances - * @return a String with the key predicate - */ - String buildContextURLKeyPredicate(List keys) throws SerializerException; } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java new file mode 100644 index 000000000..16ec27689 --- /dev/null +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java @@ -0,0 +1,59 @@ +/* + * 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.api.uri; + +import java.util.List; + +import org.apache.olingo.commons.api.data.Entity; +import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmStructuredType; +import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.queryoption.ExpandOption; +import org.apache.olingo.server.api.uri.queryoption.SelectOption; + +/** + * Used for URI-related tasks. + */ +public interface UriHelper { + + /** + * Builds the select-list part of a {@link org.apache.olingo.commons.api.data.ContextURL ContextURL}. + * @param type the {@link EdmStructuredType} + * @param expand the $expand option + * @param select the $select option + * @return a String with the select list + */ + String buildContextURLSelectList(EdmStructuredType type, ExpandOption expand, SelectOption select) + throws SerializerException; + + /** + * Builds the key-predicate part of a {@link org.apache.olingo.commons.api.data.ContextURL ContextURL}. + * @param keys the keys as a list of {@link UriParameter} instances + * @return a String with the key predicate + */ + String buildContextURLKeyPredicate(List keys) throws SerializerException; + + /** + * Builds the relative canonical URL for the given entity in the given entity set. + * @param edmEntitySet the entity set + * @param entity the entity data + * @return the relative canonical URL + */ + String buildCanonicalURL(EdmEntitySet edmEntitySet, Entity entity) throws SerializerException; +} diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java index 3f899decb..cbb4ed655 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java @@ -220,10 +220,9 @@ public class ODataHandler { .readEntityCollection(request, response, uriInfo, requestedContentType); } else if (method.equals(HttpMethod.POST)) { if (isMedia(lastPathSegment)) { + final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, customContentTypeSupport, RepresentationType.ENTITY); - final ContentType requestFormat = - ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); selectProcessor(MediaEntityProcessor.class) .createEntity(request, response, uriInfo, requestFormat, responseFormat); } else { @@ -242,13 +241,8 @@ public class ODataHandler { selectProcessor(EntityProcessor.class) .readEntity(request, response, uriInfo, requestedContentType); } else if (method.equals(HttpMethod.DELETE)) { - if (isMedia(lastPathSegment)) { - selectProcessor(MediaEntityProcessor.class) - .deleteEntity(request, response, uriInfo); - } else { - throw new ODataHandlerException("not implemented", - ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); - } + selectProcessor(isMedia(lastPathSegment) ? MediaEntityProcessor.class : EntityProcessor.class) + .deleteEntity(request, response, uriInfo); } else { throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); @@ -337,8 +331,7 @@ public class ODataHandler { selectProcessor(MediaEntityProcessor.class) .readMediaEntity(request, response, uriInfo, requestedContentType); } else if (method.equals(HttpMethod.PUT)) { - final ContentType requestFormat = - ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); + final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, customContentTypeSupport, RepresentationType.ENTITY); selectProcessor(MediaEntityProcessor.class) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java index a13281ef6..81e1ce145 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java @@ -31,10 +31,12 @@ import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.serializer.FixedFormatSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl; import org.apache.olingo.server.core.serializer.FixedFormatSerializerImpl; import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer; import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializerImpl; +import org.apache.olingo.server.core.uri.UriHelperImpl; public class ODataImpl extends OData { @@ -77,4 +79,9 @@ public class ODataImpl extends OData { public FixedFormatDeserializer createFixedFormatDeserializer() { return new FixedFormatDeserializerImpl(); } + + @Override + public UriHelper createUriHelper() { + return new UriHelperImpl(); + } } 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 d72dbc7a1..606731206 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 @@ -51,13 +51,11 @@ 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.serializer.EntitySerializerOptions; -import org.apache.olingo.server.api.uri.UriParameter; import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder; -import org.apache.olingo.server.core.serializer.utils.ContextURLHelper; import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -559,15 +557,4 @@ public class ODataJsonSerializer implements ODataSerializer { } return buffer.getInputStream(); } - - @Override - public String buildContextURLSelectList(final EdmStructuredType type, - final ExpandOption expand, final SelectOption select) throws SerializerException { - return ContextURLHelper.buildSelectList(type, expand, select); - } - - @Override - public String buildContextURLKeyPredicate(final List keys) throws SerializerException { - return ContextURLHelper.buildKeyPredicate(keys); - } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java index 429a1d230..ac856a730 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerImpl.java @@ -19,7 +19,6 @@ package org.apache.olingo.server.core.serializer.xml; import java.io.InputStream; -import java.util.List; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; @@ -32,20 +31,15 @@ import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmPrimitiveType; -import org.apache.olingo.commons.api.edm.EdmStructuredType; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.serializer.ComplexSerializerOptions; 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.serializer.EntitySerializerOptions; -import org.apache.olingo.server.api.uri.UriParameter; -import org.apache.olingo.server.api.uri.queryoption.ExpandOption; -import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; -import org.apache.olingo.server.core.serializer.utils.ContextURLHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -140,15 +134,4 @@ public class ODataXmlSerializerImpl implements ODataSerializer { throw new SerializerException("Serialization not implemented for XML format.", SerializerException.MessageKeys.NOT_IMPLEMENTED); } - - @Override - public String buildContextURLSelectList(final EdmStructuredType type, - final ExpandOption expand, final SelectOption select) throws SerializerException { - return ContextURLHelper.buildSelectList(type, expand, select); - } - - @Override - public String buildContextURLKeyPredicate(final List keys) throws SerializerException { - return ContextURLHelper.buildKeyPredicate(keys); - } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java new file mode 100644 index 000000000..8bbbc3fef --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java @@ -0,0 +1,84 @@ +/* + * 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.uri; + +import java.util.List; + +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.edm.EdmPrimitiveType; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; +import org.apache.olingo.commons.api.edm.EdmProperty; +import org.apache.olingo.commons.api.edm.EdmStructuredType; +import org.apache.olingo.commons.core.Encoder; +import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.UriHelper; +import org.apache.olingo.server.api.uri.UriParameter; +import org.apache.olingo.server.api.uri.queryoption.ExpandOption; +import org.apache.olingo.server.api.uri.queryoption.SelectOption; +import org.apache.olingo.server.core.serializer.utils.ContextURLHelper; + +public class UriHelperImpl implements UriHelper { + + @Override + public String buildContextURLSelectList(final EdmStructuredType type, + final ExpandOption expand, final SelectOption select) throws SerializerException { + return ContextURLHelper.buildSelectList(type, expand, select); + } + + @Override + public String buildContextURLKeyPredicate(final List keys) throws SerializerException { + return ContextURLHelper.buildKeyPredicate(keys); + } + + @Override + public String buildCanonicalURL(final EdmEntitySet edmEntitySet, final Entity entity) throws SerializerException { + StringBuilder result = new StringBuilder(edmEntitySet.getName()); + result.append('('); + final EdmEntityType entityType = edmEntitySet.getEntityType(); + final List keyNames = entityType.getKeyPredicateNames(); + boolean first = true; + for (final String keyName : keyNames) { + if (first) { + first = false; + } else { + result.append(','); + } + if (keyNames.size() > 1) { + result.append(Encoder.encode(keyName)).append('='); + } + final EdmProperty edmProperty = entityType.getStructuralProperty(keyName); + final EdmPrimitiveType type = (EdmPrimitiveType) edmProperty.getType(); + final Object propertyValue = entity.getProperty(keyName).getValue(); + try { + final String value = type.toUriLiteral( + type.valueToString(propertyValue, + edmProperty.isNullable(), edmProperty.getMaxLength(), + edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode())); + result.append(Encoder.encode(value)); + } catch (final EdmPrimitiveTypeException e) { + throw new SerializerException("Wrong key value!", + SerializerException.MessageKeys.WRONG_PROPERTY_VALUE, edmProperty.getName(), propertyValue.toString()); + } + } + result.append(')'); + return result.toString(); + } +} \ No newline at end of file diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java index 34e36a24a..07b748d22 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java @@ -137,6 +137,21 @@ public class DataProvider { } } + public Entity create(final EdmEntitySet edmEntitySet) throws DataProviderException { + List entities = readAll(edmEntitySet).getEntities(); + Entity entity = new EntityImpl(); + final List keyNames = edmEntitySet.getEntityType().getKeyPredicateNames(); + if (keyNames.size() == 1 && keyNames.get(0).equals("PropertyInt16")) { + entity.addProperty(createPrimitive("PropertyInt16", + entities.isEmpty() ? 1 : + (Integer) entities.get(entities.size() - 1).getProperty("PropertyInt16").getValue() + 1)); + } else { + throw new DataProviderException("Key construction not supported!"); + } + entities.add(entity); + return entity; + } + public byte[] readMedia(final Entity entity) { return (byte[]) entity.getProperty(MEDIA_PROPERTY_NAME).asPrimitive(); } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java index 016b7b295..4b1f5ddc5 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java @@ -79,7 +79,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor response.setContent(serializer.entityCollection(edmEntitySet.getEntityType(), entitySet, EntityCollectionSerializerOptions.with() .contextURL(format == ODataFormat.JSON_NO_METADATA ? null : - getContextUrl(serializer, edmEntitySet, false, expand, select)) + getContextUrl(edmEntitySet, false, expand, select)) .count(uriInfo.getCountOption()) .expand(expand).select(select) .build())); @@ -127,7 +127,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor response.setContent(serializer.entity(edmEntitySet.getEntityType(), entity, EntitySerializerOptions.with() .contextURL(format == ODataFormat.JSON_NO_METADATA ? null : - getContextUrl(serializer, edmEntitySet, true, expand, select)) + getContextUrl(edmEntitySet, true, expand, select)) .expand(expand).select(select) .build())); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); @@ -144,8 +144,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor if (entity == null) { throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } else { - response.setContent(odata.createFixedFormatSerializer() - .binary(dataProvider.readMedia(entity))); + response.setContent(odata.createFixedFormatSerializer().binary(dataProvider.readMedia(entity))); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, entity.getMediaContentType()); } @@ -156,13 +155,33 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { blockNavigation(uriInfo); - final String contentType = request.getHeader(HttpHeader.CONTENT_TYPE); - if (contentType == null) { - throw new ODataApplicationException("The Content-Type HTTP header is missing.", - HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); + final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); + final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet(); + Entity entity = null; + if (edmEntitySet.getEntityType().hasStream()) { + if (requestFormat == null) { + throw new ODataApplicationException("The content type has not been set in the request.", + HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); + } + entity = dataProvider.create(edmEntitySet); + dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()), + requestFormat.toContentTypeString()); + } else { + throw new ODataApplicationException("Entity creation is not supported yet.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - throw new ODataApplicationException("Not yet supported.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + + final ODataFormat format = ODataFormat.fromContentType(responseFormat); + ODataSerializer serializer = odata.createSerializer(format); + response.setContent(serializer.entity(edmEntitySet.getEntityType(), entity, + EntitySerializerOptions.with() + .contextURL(format == ODataFormat.JSON_NO_METADATA ? null : + getContextUrl(edmEntitySet, true, null, null)) + .build())); + response.setStatusCode(HttpStatusCode.CREATED.getStatusCode()); + response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); + response.setHeader(HttpHeader.LOCATION, + request.getRawBaseUri() + '/' + odata.createUriHelper().buildCanonicalURL(edmEntitySet, entity)); } @Override @@ -176,19 +195,19 @@ public class TechnicalEntityProcessor extends TechnicalProcessor if (entity == null) { throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } - final String contentType = request.getHeader(HttpHeader.CONTENT_TYPE); - if (contentType == null) { - throw new ODataApplicationException("The Content-Type HTTP header is missing.", + if (requestFormat == null) { + throw new ODataApplicationException("The content type has not been set in the request.", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); } - dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()), contentType); + dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()), + requestFormat.toContentTypeString()); final ODataFormat format = ODataFormat.fromContentType(responseFormat); ODataSerializer serializer = odata.createSerializer(format); response.setContent(serializer.entity(edmEntitySet.getEntityType(), entity, EntitySerializerOptions.with() .contextURL(format == ODataFormat.JSON_NO_METADATA ? null : - getContextUrl(serializer, edmEntitySet, true, null, null)) + getContextUrl(edmEntitySet, true, null, null)) .build())); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); @@ -229,11 +248,11 @@ public class TechnicalEntityProcessor extends TechnicalProcessor return entitySet; } - private ContextURL getContextUrl(final ODataSerializer serializer, - final EdmEntitySet entitySet, final boolean isSingleEntity, + private ContextURL getContextUrl(final EdmEntitySet entitySet, final boolean isSingleEntity, final ExpandOption expand, final SelectOption select) throws SerializerException { return ContextURL.with().entitySet(entitySet) - .selectList(serializer.buildContextURLSelectList(entitySet.getEntityType(), expand, select)) + .selectList(odata.createUriHelper() + .buildContextURLSelectList(entitySet.getEntityType(), expand, select)) .suffix(isSingleEntity ? Suffix.ENTITY : null) .build(); } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java index 5c0c88a75..3482d0331 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java @@ -51,6 +51,7 @@ import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.PrimitiveValueSerializerOptions; import org.apache.olingo.server.api.serializer.RepresentationType; import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfoResource; import org.apache.olingo.server.api.uri.UriResource; @@ -121,13 +122,14 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor ODataSerializer serializer = odata.createSerializer(format); final ExpandOption expand = uriInfo.getExpandOption(); final SelectOption select = uriInfo.getSelectOption(); + final UriHelper helper = odata.createUriHelper(); final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? null : ContextURL.with().entitySet(edmEntitySet) - .keyPath(serializer.buildContextURLKeyPredicate( + .keyPath(helper.buildContextURLKeyPredicate( ((UriResourceEntitySet) resourceParts.get(0)).getKeyPredicates())) .navOrPropertyPath(buildPropertyPath(path)) .selectList(edmProperty.isPrimitive() ? null : - serializer.buildContextURLSelectList((EdmStructuredType) edmProperty.getType(), expand, select)) + helper.buildContextURLSelectList((EdmStructuredType) edmProperty.getType(), expand, select)) .build(); switch (representationType) { case PRIMITIVE: diff --git a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java index b42bedb42..264febdbc 100644 --- a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java +++ b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java @@ -40,18 +40,18 @@ import org.mockito.Mockito; public class DataProviderTest { - private final Edm edm = - OData.newInstance().createServiceMetadata(new EdmTechProvider( - Collections.emptyList()), - Collections.emptyList()).getEdm(); + private final Edm edm = OData.newInstance().createServiceMetadata(new EdmTechProvider( + Collections. emptyList()), Collections. emptyList()) + .getEdm(); private final EdmEntityContainer entityContainer = edm.getEntityContainer( - new FullQualifiedName("olingo.odata.test1", "Container")); + new FullQualifiedName("olingo.odata.test1", "Container")); private final EdmEntitySet esAllPrim = entityContainer.getEntitySet("ESAllPrim"); private final EdmEntitySet esAllKey = entityContainer.getEntitySet("ESAllKey"); private final EdmEntitySet esCompAllPrim = entityContainer.getEntitySet("ESCompAllPrim"); private final EdmEntitySet esCollAllPrim = entityContainer.getEntitySet("ESCollAllPrim"); private final EdmEntitySet esMixPrimCollComp = entityContainer.getEntitySet("ESMixPrimCollComp"); + private final EdmEntitySet esMedia = entityContainer.getEntitySet("ESMedia"); @Test public void esAllPrimEntity() throws Exception { @@ -154,6 +154,20 @@ public class DataProviderTest { Assert.assertEquals(4, outSet.getEntities().get(2).getProperties().size()); } + @Test + public void esMedia() throws Exception { + DataProvider dataProvider = new DataProvider(); + Entity entity = dataProvider.read(esMedia, Arrays.asList(mockParameter("PropertyInt16", "3"))); + Assert.assertNotNull(dataProvider.readMedia(entity)); + dataProvider.delete(esMedia, entity); + Assert.assertEquals(3, dataProvider.readAll(esMedia).getEntities().size()); + entity = dataProvider.create(esMedia); + Assert.assertEquals(5, entity.getProperty("PropertyInt16").getValue()); + dataProvider.setMedia(entity, new byte[] { 1, 2, 3, 4 }, "x/y"); + Assert.assertArrayEquals(new byte[] { 1, 2, 3, 4 }, dataProvider.readMedia(entity)); + Assert.assertEquals("x/y", entity.getMediaContentType()); + } + private static UriParameter mockParameter(final String name, final String text) { UriParameter parameter = Mockito.mock(UriParameter.class); Mockito.when(parameter.getName()).thenReturn(name); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java index 67ce094ae..528397481 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java @@ -258,6 +258,14 @@ public class ODataHandlerTest { any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); } + @Test + public void dispatchEntityDelete() throws Exception { + final EntityProcessor processor = mock(EntityProcessor.class); + dispatch(HttpMethod.DELETE, "ESAllPrim(0)", processor); + + verify(processor).deleteEntity(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class)); + } + @Test public void dispatchMedia() throws Exception { final MediaEntityProcessor processor = mock(MediaEntityProcessor.class); @@ -277,7 +285,7 @@ public class ODataHandlerTest { } @Test - public void dispatchMediaPut() throws Exception { + public void dispatchMediaUpdate() throws Exception { final MediaEntityProcessor processor = mock(MediaEntityProcessor.class); dispatch(HttpMethod.PUT, "ESMedia(1)/$value", processor); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java index 7ca442a8d..038c6686b 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java @@ -48,12 +48,14 @@ import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.EntitySerializerOptions; import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; 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.data.DataProvider; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.hamcrest.CoreMatchers; @@ -69,6 +71,7 @@ public class ODataJsonSerializerTest { new FullQualifiedName("olingo.odata.test1", "Container")); private final DataProvider data = new DataProvider(); private final ODataSerializer serializer = new ODataJsonSerializer(ODataFormat.JSON); + private final UriHelper helper = new UriHelperImpl(); @Test public void entitySimple() throws Exception { @@ -358,7 +361,7 @@ public class ODataJsonSerializerTest { .entity(entityType, entity, EntitySerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, null, select)) + .selectList(helper.buildContextURLSelectList(entityType, null, select)) .suffix(Suffix.ENTITY).build()) .select(select) .build()); @@ -399,7 +402,7 @@ public class ODataJsonSerializerTest { .entityCollection(entityType, entitySet, EntityCollectionSerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, null, select)) + .selectList(helper.buildContextURLSelectList(entityType, null, select)) .build()) .select(select) .build()); @@ -424,7 +427,7 @@ public class ODataJsonSerializerTest { .entityCollection(entityType, entitySet, EntityCollectionSerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, null, select)) + .selectList(helper.buildContextURLSelectList(entityType, null, select)) .build()) .select(select) .build())); @@ -484,7 +487,7 @@ public class ODataJsonSerializerTest { .entity(entityType, entity, EntitySerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, expand, select)) + .selectList(helper.buildContextURLSelectList(entityType, expand, select)) .suffix(Suffix.ENTITY).build()) .expand(expand) .build())); @@ -511,7 +514,7 @@ public class ODataJsonSerializerTest { .entity(entityType, entity, EntitySerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, expand, select)) + .selectList(helper.buildContextURLSelectList(entityType, expand, select)) .suffix(Suffix.ENTITY).build()) .expand(expand) .select(select) @@ -538,7 +541,7 @@ public class ODataJsonSerializerTest { .entity(entityType, entity, EntitySerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, expand, select)) + .selectList(helper.buildContextURLSelectList(entityType, expand, select)) .suffix(Suffix.ENTITY).build()) .expand(expand) .select(select) @@ -569,7 +572,7 @@ public class ODataJsonSerializerTest { .entity(entityType, entity, EntitySerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet) - .selectList(serializer.buildContextURLSelectList(entityType, expand, select)) + .selectList(helper.buildContextURLSelectList(entityType, expand, select)) .suffix(Suffix.ENTITY).build()) .expand(expand) .build())); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java new file mode 100644 index 000000000..fe443053b --- /dev/null +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java @@ -0,0 +1,82 @@ +/* + * 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.uri; + +import java.util.Collections; + +import org.apache.olingo.commons.api.data.Entity; +import org.apache.olingo.commons.api.data.ValueType; +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.FullQualifiedName; +import org.apache.olingo.server.api.OData; +import org.apache.olingo.server.api.edmx.EdmxReference; +import org.apache.olingo.server.api.serializer.SerializerException; +import org.apache.olingo.server.api.uri.UriHelper; +import org.apache.olingo.server.tecsvc.data.DataProvider; +import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; +import org.junit.Assert; +import org.junit.Test; + +public class UriHelperTest { + + private static final Edm edm = OData.newInstance().createServiceMetadata( + new EdmTechProvider(), Collections. emptyList()).getEdm(); + private static final EdmEntityContainer container = edm.getEntityContainer( + new FullQualifiedName("olingo.odata.test1", "Container")); + private static final UriHelper helper = new UriHelperImpl(); + private final DataProvider data = new DataProvider(); + + @Test + public void canonicalURL() throws Exception { + final EdmEntitySet entitySet = container.getEntitySet("ESAllPrim"); + final Entity entity = data.readAll(entitySet).getEntities().get(0); + Assert.assertEquals("ESAllPrim(32767)", helper.buildCanonicalURL(entitySet, entity)); + } + + @Test + public void canonicalURLLong() throws Exception { + final EdmEntitySet entitySet = container.getEntitySet("ESAllKey"); + final Entity entity = data.readAll(entitySet).getEntities().get(0); + Assert.assertEquals("ESAllKey(" + + "PropertyString='First'," + + "PropertyBoolean=true," + + "PropertyByte=255," + + "PropertySByte=127," + + "PropertyInt16=32767," + + "PropertyInt32=2147483647," + + "PropertyInt64=9223372036854775807," + + "PropertyDecimal=34," + + "PropertyDate=2012-12-03," + + "PropertyDateTimeOffset=2012-12-03T07%3A16%3A23Z," + + "PropertyDuration=duration'PT6S'," + + "PropertyGuid=01234567-89ab-cdef-0123-456789abcdef," + + "PropertyTimeOfDay=02%3A48%3A21)", + helper.buildCanonicalURL(entitySet, entity)); + } + + @Test(expected = SerializerException.class) + public void canonicalURLWrong() throws Exception { + final EdmEntitySet entitySet = container.getEntitySet("ESAllPrim"); + Entity entity = data.readAll(entitySet).getEntities().get(0); + entity.getProperty("PropertyInt16").setValue(ValueType.PRIMITIVE, "wrong"); + helper.buildCanonicalURL(entitySet, entity); + } +} diff --git a/samples/server/src/main/java/org/apache/olingo/server/sample/processor/CarsProcessor.java b/samples/server/src/main/java/org/apache/olingo/server/sample/processor/CarsProcessor.java index 4fcd381e3..3b0b08ec2 100644 --- a/samples/server/src/main/java/org/apache/olingo/server/sample/processor/CarsProcessor.java +++ b/samples/server/src/main/java/org/apache/olingo/server/sample/processor/CarsProcessor.java @@ -56,6 +56,7 @@ 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.UriHelper; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfoResource; import org.apache.olingo.server.api.uri.UriResource; @@ -312,7 +313,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor throws SerializerException { return ContextURL.with().entitySet(entitySet) - .selectList(serializer.buildContextURLSelectList(entitySet.getEntityType(), expand, select)) + .selectList(odata.createUriHelper().buildContextURLSelectList(entitySet.getEntityType(), expand, select)) .suffix(isSingleEntity ? Suffix.ENTITY : null) .navOrPropertyPath(navOrPropertyPath) .build();