OLINGO-567: Support for odata.metadata=full
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/3c0225c9 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/3c0225c9 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/3c0225c9 Branch: refs/heads/master Commit: 3c0225c9dac6ac26ebe933a3c53e40cf849682ed Parents: b32a2ce Author: Ramesh Reddy <[email protected]> Authored: Mon May 23 14:44:12 2016 -0500 Committer: Ramesh Reddy <[email protected]> Committed: Sun Jun 26 07:50:39 2016 -0700 ---------------------------------------------------------------------- .../fit/tecsvc/client/BoundOpearionITCase.java | 149 ++++++++ .../tecsvc/client/EntityWithStreamITCase.java | 112 ++++++ .../fit/tecsvc/http/BasicStreamITCase.java | 2 +- .../client/api/domain/ClientEntitySet.java | 15 + .../olingo/client/api/domain/ClientLink.java | 25 +- .../client/api/domain/ClientLinkType.java | 9 + .../client/api/domain/ClientObjectFactory.java | 6 +- .../client/api/domain/ClientProperty.java | 17 + .../core/domain/ClientComplexValueImpl.java | 1 + .../client/core/domain/ClientEntityImpl.java | 1 + .../client/core/domain/ClientEntitySetImpl.java | 26 ++ .../core/domain/ClientObjectFactoryImpl.java | 18 +- .../client/core/domain/ClientPropertyImpl.java | 27 +- .../core/serialization/AtomDeserializer.java | 4 +- .../core/serialization/JsonDeserializer.java | 1 + .../serialization/JsonEntityDeserializer.java | 49 ++- .../JsonEntitySetDeserializer.java | 16 +- .../serialization/JsonPropertyDeserializer.java | 15 +- .../core/serialization/ODataBinderImpl.java | 26 +- .../apache/olingo/commons/api/Constants.java | 4 + .../api/data/AbstractEntityCollection.java | 3 + .../commons/api/data/EntityCollection.java | 13 +- .../olingo/commons/api/data/Operation.java | 20 +- .../olingo/commons/api/data/Property.java | 13 + .../org/apache/olingo/commons/api/edm/Edm.java | 21 ++ .../olingo/commons/core/edm/AbstractEdm.java | 36 ++ .../core/edm/primitivetype/EdmStream.java | 7 + .../olingo/server/core/ServiceRequest.java | 9 +- .../server/core/responses/EntityResponse.java | 19 + .../core/responses/EntitySetResponse.java | 64 +++- .../server/core/responses/PropertyResponse.java | 43 +++ .../server/core/responses/ServiceResponse.java | 50 ++- .../server/example/TripPinServiceTest.java | 24 ++ .../olingo/server/core/ContentNegotiator.java | 1 + .../apache/olingo/server/core/ODataImpl.java | 3 +- .../deserializer/xml/ODataXmlDeserializer.java | 3 +- .../serializer/json/ODataJsonSerializer.java | 179 +++++++-- .../serializer/utils/ContentTypeHelper.java | 5 + .../core/serializer/xml/ODataXmlSerializer.java | 18 +- .../server/core/ContentNegotiatorTest.java | 1 - .../olingo/server/core/ODataImplTest.java | 7 +- .../olingo/server/tecsvc/data/ActionData.java | 14 +- .../olingo/server/tecsvc/data/DataCreator.java | 232 ++++++++++-- .../olingo/server/tecsvc/data/DataProvider.java | 6 +- .../olingo/server/tecsvc/data/FunctionData.java | 5 + .../processor/TechnicalEntityProcessor.java | 7 + .../ExpandSystemQueryOptionHandler.java | 2 +- .../server/tecsvc/provider/ActionProvider.java | 22 +- .../tecsvc/provider/ContainerProvider.java | 5 + .../tecsvc/provider/EntityTypeProvider.java | 13 +- .../tecsvc/provider/FunctionProvider.java | 86 ++++- .../tecsvc/provider/PropertyProvider.java | 6 + .../json/ODataJsonSerializerTest.java | 360 ++++++++++++++++++- .../serializer/xml/ODataXmlSerializerTest.java | 188 +++++++++- 54 files changed, 1883 insertions(+), 125 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java new file mode 100644 index 0000000..a37ab49 --- /dev/null +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java @@ -0,0 +1,149 @@ +/* + * 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.fit.tecsvc.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; +import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest; +import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.client.api.domain.ClientAnnotation; +import org.apache.olingo.client.api.domain.ClientEntity; +import org.apache.olingo.client.api.domain.ClientEntitySet; +import org.apache.olingo.client.api.domain.ClientOperation; +import org.apache.olingo.client.api.domain.ClientProperty; +import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.junit.Test; +import org.junit.runners.Parameterized; + +public class BoundOpearionITCase extends AbstractParamTecSvcITCase { + private static final ContentType CONTENT_TYPE_JSON_FULL_METADATA = + ContentType.create(ContentType.JSON, ContentType.PARAMETER_ODATA_METADATA, + ContentType.VALUE_ODATA_METADATA_FULL); + + @Parameterized.Parameters(name = "{0}") + public static List<ContentType[]> parameters() { + ContentType[] a = new ContentType[1]; + a[0] = CONTENT_TYPE_JSON_FULL_METADATA; + ArrayList<ContentType[]> type = new ArrayList<ContentType[]>(); + type.add(a); + return type; + } + + @Test + public void readEntitySetOperation() { + ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory() + .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESAllPrim").build()); + assertNotNull(request); + setCookieHeader(request); + + final ODataRetrieveResponse<ClientEntitySet> response = request.execute(); + saveCookieHeader(response); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertEquals("application/json; odata.metadata=full", response.getContentType()); + + final ClientEntitySet entitySet = response.getBody(); + assertNotNull(entitySet); + + assertNull(entitySet.getCount()); + assertNull(entitySet.getNext()); + assertEquals(Collections.<ClientAnnotation> emptyList(), entitySet.getAnnotations()); + assertNull(entitySet.getDeltaLink()); + + List<ClientOperation> ecOperations = entitySet.getOperations(); + assertNotNull(ecOperations); + assertEquals(4, ecOperations.size()); + + assertEquals("#olingo.odata.test1.BAESAllPrimRTETAllPrim", ecOperations.get(0).getMetadataAnchor()); + assertEquals("olingo.odata.test1.BAESAllPrimRTETAllPrim", ecOperations.get(0).getTitle()); + assertEquals("/ESAllPrim/olingo.odata.test1.BAESAllPrimRTETAllPrim", + ecOperations.get(0).getTarget().toASCIIString()); + + assertEquals("#olingo.odata.test1.BAESAllPrimRT", ecOperations.get(1).getMetadataAnchor()); + assertEquals("olingo.odata.test1.BAESAllPrimRT", ecOperations.get(1).getTitle()); + assertEquals("/ESAllPrim/olingo.odata.test1.BAESAllPrimRT", + ecOperations.get(1).getTarget().toASCIIString()); + + + assertEquals("#olingo.odata.test1.BFNESAllPrimRTCTAllPrim", ecOperations.get(2).getMetadataAnchor()); + assertEquals("olingo.odata.test1.BFNESAllPrimRTCTAllPrim", ecOperations.get(2).getTitle()); + assertEquals("/ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim", + ecOperations.get(2).getTarget().toASCIIString()); + + assertEquals("#olingo.odata.test1.BFNESAllPrimRTCTAllPrim(Param2)", ecOperations.get(3).getMetadataAnchor()); + assertEquals("olingo.odata.test1.BFNESAllPrimRTCTAllPrim", ecOperations.get(3).getTitle()); + assertEquals("/ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim(Param2=@Param2)", + ecOperations.get(3).getTarget().toASCIIString()); + + final List<ClientEntity> entities = entitySet.getEntities(); + assertNotNull(entities); + assertEquals(3, entities.size()); + + ClientEntity entity = entities.get(0); + assertNotNull(entity); + List<ClientOperation> operations = entity.getOperations(); + assertNotNull(operations); + assertEquals(1, operations.size()); + + assertEquals("#olingo.odata.test1.BAETAllPrimRT", operations.get(0).getMetadataAnchor()); + assertEquals("olingo.odata.test1.BAETAllPrimRT", operations.get(0).getTitle()); + assertEquals("/ESAllPrim(32767)/olingo.odata.test1.BAETAllPrimRT", + operations.get(0).getTarget().toASCIIString()); + } + + @Test + public void readComplexPropertyOperation() { + ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() + .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESCompAllPrim") + .appendKeySegment(32767) + .appendPropertySegment("PropertyComp") + .build()); + assertNotNull(request); + setCookieHeader(request); + + final ODataRetrieveResponse<ClientProperty> response = request.execute(); + saveCookieHeader(response); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertEquals("application/json; odata.metadata=full", response.getContentType()); + + final ClientProperty property = response.getBody(); + assertNotNull(property); + + List<ClientOperation> operations = property.getOperations(); + assertNotNull(operations); + + assertEquals(1, operations.size()); + + assertEquals("#olingo.odata.test1.BFCColCTAllPrimRTESAllPrim", operations.get(0).getMetadataAnchor()); + assertEquals("olingo.odata.test1.BFCColCTAllPrimRTESAllPrim", operations.get(0).getTitle()); + assertEquals("PropertyComp/olingo.odata.test1.BFCColCTAllPrimRTESAllPrim", + operations.get(0).getTarget().toASCIIString()); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java new file mode 100644 index 0000000..a99f02c --- /dev/null +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java @@ -0,0 +1,112 @@ +/* + * 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.fit.tecsvc.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; +import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.client.api.domain.ClientAnnotation; +import org.apache.olingo.client.api.domain.ClientEntity; +import org.apache.olingo.client.api.domain.ClientEntitySet; +import org.apache.olingo.client.api.domain.ClientLink; +import org.apache.olingo.client.api.domain.ClientLinkType; +import org.apache.olingo.client.api.domain.ClientProperty; +import org.apache.olingo.commons.api.Constants; +import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.junit.Test; +import org.junit.runners.Parameterized; + +public class EntityWithStreamITCase extends AbstractParamTecSvcITCase { + private static final ContentType CONTENT_TYPE_JSON_FULL_METADATA = + ContentType.create(ContentType.JSON, ContentType.PARAMETER_ODATA_METADATA, + ContentType.VALUE_ODATA_METADATA_FULL); + private static final String PROPERTY_INT16 = "PropertyInt16"; + + @Parameterized.Parameters(name = "{0}") + public static List<ContentType[]> parameters() { + ContentType[] a = new ContentType[1]; + a[0] = CONTENT_TYPE_JSON_FULL_METADATA; + ArrayList<ContentType[]> type = new ArrayList<ContentType[]>(); + type.add(a); + return type; + } + + @Test + public void readEntitySetWithStreamProperty() { + ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory() + .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESWithStream").build()); + assertNotNull(request); + setCookieHeader(request); + + final ODataRetrieveResponse<ClientEntitySet> response = request.execute(); + saveCookieHeader(response); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertEquals("application/json; odata.metadata=full", response.getContentType()); + + final ClientEntitySet entitySet = response.getBody(); + assertNotNull(entitySet); + + assertNull(entitySet.getCount()); + assertNull(entitySet.getNext()); + assertEquals(Collections.<ClientAnnotation> emptyList(), entitySet.getAnnotations()); + assertNull(entitySet.getDeltaLink()); + + final List<ClientEntity> entities = entitySet.getEntities(); + assertNotNull(entities); + assertEquals(2, entities.size()); + + ClientEntity entity = entities.get(0); + assertNotNull(entity); + ClientProperty property = entity.getProperty(PROPERTY_INT16); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertShortOrInt(Short.MAX_VALUE, property.getPrimitiveValue().toValue()); + + ClientLink link = entity.getMediaEditLinks().get(0); + assertNotNull(link); + + assertEquals("/readLink", link.getLink().toASCIIString()); + assertEquals(ClientLinkType.MEDIA_READ, link.getType()); + + entity = entities.get(1); + assertNotNull(entity); + property = entity.getProperty(PROPERTY_INT16); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertShortOrInt(7, property.getPrimitiveValue().toValue()); + + assertEquals(1, entity.getMediaEditLinks().size()); + + link = entity.getMediaEditLinks().get(0); + assertNotNull(link); + assertEquals("http://mediaserver:1234/editLink", link.getLink().toASCIIString()); + assertEquals(ClientLinkType.fromString(Constants.NS_MEDIA_EDIT_LINK_REL, "image/jpeg").name(), + link.getType().name()); + assertEquals("eTag", link.getMediaETag()); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java index 566cb39..33eb4f5 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java @@ -70,7 +70,7 @@ public class BasicStreamITCase extends AbstractBaseTestITCase { assertEquals(ContentType.APPLICATION_XML, ContentType.create(connection.getHeaderField(HttpHeader.CONTENT_TYPE))); final String content = IOUtils.toString(connection.getInputStream()); - +System.out.println(content); assertTrue(content.contains("<m:element>[email protected]</m:element>" + "<m:element>[email protected]</m:element>" + "<m:element>[email protected]</m:element>")); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java index 6b5f1f1..e1664be 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java @@ -68,4 +68,19 @@ public interface ClientEntitySet extends ClientInvokeResult, ClientAnnotatable { * @param deltaLink delta link. */ void setDeltaLink(URI deltaLink); + + /** + * Searches for operation with given title. + * + * @param title operation to look for + * @return operation if found with given title, <tt>null</tt> otherwise + */ + ClientOperation getOperation(String title); + + /** + * Gets operations. + * + * @return operations. + */ + List<ClientOperation> getOperations(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java index 5307165..35f89fb 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java @@ -36,7 +36,9 @@ public class ClientLink extends ClientItem implements ClientAnnotatable { private ClientLinkType type; private String title; - + + private String mediaETag; + public Builder setURI(final URI uri) { this.uri = uri; return this; @@ -57,8 +59,13 @@ public class ClientLink extends ClientItem implements ClientAnnotatable { return this; } + public Builder setEtag(final String eTag) { + this.mediaETag= eTag; + return this; + } + public ClientLink build() { - return new ClientLink(uri, type, title); + return new ClientLink(uri, type, title, mediaETag); } } @@ -110,10 +117,15 @@ public class ClientLink extends ClientItem implements ClientAnnotatable { * @param title title. */ public ClientLink(final URI uri, final ClientLinkType type, final String title) { + this(uri, type, title, null); + } + + public ClientLink(final URI uri, final ClientLinkType type, final String title, final String eTag) { super(title); this.type = type; setLink(uri); + this.mediaETag = eTag; switch (this.type) { case ASSOCIATION: @@ -126,12 +138,19 @@ public class ClientLink extends ClientItem implements ClientAnnotatable { break; case MEDIA_EDIT: + rel = Constants.NS_MEDIA_EDIT_LINK_REL + title; + break; + + case MEDIA_READ: + rel = Constants.NS_MEDIA_READ_LINK_REL + title; + break; + default: rel = Constants.NS_MEDIA_EDIT_LINK_REL + title; break; } } - + /** * Constructor. * http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java index 2b89b95..ff1f6f4 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java @@ -42,6 +42,11 @@ public enum ClientLinkType { * Media-edit link. */ MEDIA_EDIT("*/*"), + + /** + * Media-read link + */ + MEDIA_READ("*/*"), /** * Entity binding link. @@ -80,6 +85,10 @@ public enum ClientLinkType { if (rel != null && rel.startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) { return MEDIA_EDIT.setType(type == null || type.isEmpty() ? "*/*" : type); } + + if (rel != null && rel.startsWith(Constants.NS_MEDIA_READ_LINK_REL)) { + return MEDIA_READ.setType(type == null || type.isEmpty() ? "*/*" : type); + } if (ClientLinkType.ENTITY_NAVIGATION.type.equals(type)) { return ENTITY_NAVIGATION; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java index 5bf1e08..774bd94 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java @@ -105,8 +105,10 @@ public interface ClientObjectFactory { ClientLink newAssociationLink(String name, URI link); - ClientLink newMediaEditLink(String name, URI link); - + ClientLink newMediaEditLink(String name, URI link, String type, String eTag); + + ClientLink newMediaReadLink(String name, URI link, String type, String eTag); + ClientPrimitiveValue.Builder newPrimitiveValueBuilder(); ClientEnumValue newEnumValue(String typeName, String value); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java index 2e5dde8..8e14c94 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java @@ -18,6 +18,8 @@ */ package org.apache.olingo.client.api.domain; +import java.util.List; + /** * OData entity property. */ @@ -29,4 +31,19 @@ public interface ClientProperty extends ClientInvokeResult, ClientAnnotatable, C * @return property name. */ String getName(); + + /** + * Searches for operation with given title. + * + * @param title operation to look for + * @return operation if found with given title, <tt>null</tt> otherwise + */ + ClientOperation getOperation(String title); + + /** + * Gets operations. + * + * @return operations. + */ + List<ClientOperation> getOperations(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java index 9cd083e..1338a92 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java @@ -89,6 +89,7 @@ public class ClientComplexValueImpl extends AbstractClientValue implements Clien break; case MEDIA_EDIT: + case MEDIA_READ: throw new IllegalArgumentException("Complex values cannot have media links!"); default: http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java index 4426e03..76ee05f 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java @@ -160,6 +160,7 @@ public class ClientEntityImpl extends AbstractClientPayload implements ClientEnt break; case MEDIA_EDIT: + case MEDIA_READ: result = mediaEditLinks.contains(link) ? false : mediaEditLinks.add(link); break; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java index 21e13b4..a979196 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java @@ -26,6 +26,7 @@ import org.apache.olingo.client.api.domain.AbstractClientPayload; import org.apache.olingo.client.api.domain.ClientAnnotation; import org.apache.olingo.client.api.domain.ClientEntity; import org.apache.olingo.client.api.domain.ClientEntitySet; +import org.apache.olingo.client.api.domain.ClientOperation; public class ClientEntitySetImpl extends AbstractClientPayload implements ClientEntitySet { @@ -46,6 +47,8 @@ public class ClientEntitySetImpl extends AbstractClientPayload implements Client private final List<ClientEntity> entities = new ArrayList<ClientEntity>(); private final List<ClientAnnotation> annotations = new ArrayList<ClientAnnotation>(); + + private final List<ClientOperation> operations = new ArrayList<ClientOperation>(); public ClientEntitySetImpl() { super(null); @@ -93,6 +96,29 @@ public class ClientEntitySetImpl extends AbstractClientPayload implements Client } @Override + public ClientOperation getOperation(final String title) { + ClientOperation result = null; + for (ClientOperation operation : operations) { + if (title.equals(operation.getTitle())) { + result = operation; + break; + } + } + + return result; + } + + /** + * Gets operations. + * + * @return operations. + */ + @Override + public List<ClientOperation> getOperations() { + return operations; + } + + @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java index 7bca6c3..5914cee 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java @@ -35,6 +35,7 @@ import org.apache.olingo.client.api.domain.ClientPrimitiveValue; import org.apache.olingo.client.api.domain.ClientProperty; import org.apache.olingo.client.api.domain.ClientSingleton; import org.apache.olingo.client.api.domain.ClientValue; +import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.edm.FullQualifiedName; public class ClientObjectFactoryImpl implements ClientObjectFactory { @@ -95,11 +96,20 @@ public class ClientObjectFactoryImpl implements ClientObjectFactory { } @Override - public ClientLink newMediaEditLink(final String name, final URI link) { - return new ClientLink.Builder().setURI(link). - setType(ClientLinkType.MEDIA_EDIT).setTitle(name).build(); + public ClientLink newMediaEditLink(String name, URI link, String type, String eTag) { + return new ClientLink.Builder().setURI(link).setEtag(eTag). + setType(ClientLinkType.fromString(Constants.NS_MEDIA_EDIT_LINK_REL, + type == null ? Constants.MEDIA_EDIT_LINK_TYPE : type)) + .setTitle(name).build(); } - + + public ClientLink newMediaReadLink(String name, URI link, String type, String eTag) { + return new ClientLink.Builder().setURI(link).setEtag(eTag). + setType(ClientLinkType.fromString(Constants.NS_MEDIA_READ_LINK_REL, + type == null ? Constants.MEDIA_EDIT_LINK_TYPE : type)) + .setTitle(name).build(); + } + @Override public ClientPrimitiveValue.Builder newPrimitiveValueBuilder() { return new ClientPrimitiveValueImpl.BuilderImpl(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java index 8c8c3ee..d9aa892 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.olingo.client.api.domain.ClientAnnotation; +import org.apache.olingo.client.api.domain.ClientOperation; import org.apache.olingo.client.api.domain.ClientProperty; import org.apache.olingo.client.api.domain.ClientValue; @@ -29,7 +30,8 @@ public final class ClientPropertyImpl extends ClientValuableImpl implements Clie private final List<ClientAnnotation> annotations = new ArrayList<ClientAnnotation>(); private final String name; - + private final List<ClientOperation> operations = new ArrayList<ClientOperation>(); + public ClientPropertyImpl(final String name, final ClientValue value) { super(value); this.name = name; @@ -45,6 +47,29 @@ public final class ClientPropertyImpl extends ClientValuableImpl implements Clie return name; } + @Override + public ClientOperation getOperation(final String title) { + ClientOperation result = null; + for (ClientOperation operation : operations) { + if (title.equals(operation.getTitle())) { + result = operation; + break; + } + } + + return result; + } + + /** + * Gets operations. + * + * @return operations. + */ + @Override + public List<ClientOperation> getOperations() { + return operations; + } + /** * Checks if has null value. * http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java index 5c3b59e..037ebb5 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java @@ -640,8 +640,8 @@ public class AtomDeserializer extends AbstractAtomDealer implements ODataDeseria inline(reader, event.asStartElement(), link); } else if (link.getRel().startsWith(Constants.NS_ASSOCIATION_LINK_REL)) { entity.getAssociationLinks().add(link); - } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) { - + } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL) || + link.getRel().startsWith(Constants.NS_MEDIA_READ_LINK_REL)) { final Attribute metag = event.asStartElement().getAttributeByName(etagQName); if (metag != null) { link.setMediaETag(metag.getValue()); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java index 3691d8b..8775f17 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.olingo.client.api.data.ResWrap; import org.apache.olingo.client.api.serialization.ODataDeserializer; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java index 53de9cb..53a0cab 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java @@ -148,29 +148,41 @@ public class JsonEntityDeserializer extends JsonDeserializer { final Matcher customAnnotation = CUSTOM_ANNOTATION.matcher(field.getKey()); links(field, entity, toRemove, tree, parser.getCodec()); - if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_EDIT_LINK))) { + if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_READ_LINK))) { final Link link = new Link(); link.setTitle(getTitle(field)); - link.setRel(Constants.NS_MEDIA_EDIT_LINK_REL + getTitle(field)); - link.setHref(field.getValue().textValue()); + link.setRel(Constants.NS_MEDIA_READ_LINK_REL + getTitle(field)); link.setType(Constants.MEDIA_EDIT_LINK_TYPE); + link.setHref(field.getValue().textValue()); entity.getMediaEditLinks().add(link); - + if (tree.has(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_ETAG))) { link.setMediaETag(tree.get(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_ETAG)).asText()); toRemove.add(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_ETAG)); } + if (tree.has(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE))) { + link.setType(tree.get(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE)).asText()); + toRemove.add(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE)); + } + + toRemove.add(field.getKey()); + toRemove.add(setInline(field.getKey(), getJSONAnnotation(Constants.JSON_MEDIA_READ_LINK), tree, parser + .getCodec(), link)); + } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_EDIT_LINK))) { + final Link link = getOrCreateMediaLink(entity, getTitle(field)); + link.setRel(Constants.NS_MEDIA_EDIT_LINK_REL + getTitle(field)); + link.setHref(field.getValue().textValue()); toRemove.add(field.getKey()); toRemove.add(setInline(field.getKey(), getJSONAnnotation(Constants.JSON_MEDIA_EDIT_LINK), tree, parser .getCodec(), link)); - } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE))) { - final String linkTitle = getTitle(field); - for (Link link : entity.getMediaEditLinks()) { - if (linkTitle.equals(link.getTitle())) { - link.setType(field.getValue().asText()); - } - } + } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE))) { + final Link link = getOrCreateMediaLink(entity, getTitle(field)); + link.setType(field.getValue().asText()); + toRemove.add(field.getKey()); + } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_ETAG))) { + final Link link = getOrCreateMediaLink(entity, getTitle(field)); + link.setMediaETag(field.getValue().asText()); toRemove.add(field.getKey()); } else if (field.getKey().charAt(0) == '#') { final Operation operation = new Operation(); @@ -226,4 +238,19 @@ public class JsonEntityDeserializer extends JsonDeserializer { return new ResWrap<Entity>(contextURL, metadataETag, entity); } + + private Link getOrCreateMediaLink(final Entity entity, final String name) { + final String rel = Constants.NS_MEDIA_EDIT_LINK_REL + name; + for (Link link : entity.getMediaEditLinks()) { + if (link.getRel().equals(rel)) { + return link; + } + } + final Link link = new Link(); + link.setTitle(name); + link.setRel(rel); + link.setType(Constants.MEDIA_EDIT_LINK_TYPE); + entity.getMediaEditLinks().add(link); + return link; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java index 401b31a..d54b98b 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java @@ -20,14 +20,17 @@ package org.apache.olingo.client.core.serialization; import java.io.IOException; import java.net.URI; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.olingo.client.api.data.ResWrap; import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.data.Annotation; import org.apache.olingo.commons.api.data.EntityCollection; +import org.apache.olingo.commons.api.data.Operation; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import com.fasterxml.jackson.core.JsonParser; @@ -98,7 +101,7 @@ public class JsonEntitySetDeserializer extends JsonDeserializer { } tree.remove(Constants.VALUE); } - + final Set<String> toRemove = new HashSet<String>(); // any remaining entry is supposed to be an annotation or is ignored for (final Iterator<Map.Entry<String, JsonNode>> itor = tree.fields(); itor.hasNext();) { final Map.Entry<String, JsonNode> field = itor.next(); @@ -112,9 +115,18 @@ public class JsonEntitySetDeserializer extends JsonDeserializer { throw new IOException(e); } entitySet.getAnnotations().add(annotation); + } else if (field.getKey().charAt(0) == '#') { + final Operation operation = new Operation(); + operation.setMetadataAnchor(field.getKey()); + + final ObjectNode opNode = (ObjectNode) tree.get(field.getKey()); + operation.setTitle(opNode.get(Constants.ATTR_TITLE).asText()); + operation.setTarget(URI.create(opNode.get(Constants.ATTR_TARGET).asText())); + entitySet.getOperations().add(operation); + toRemove.add(field.getKey()); } } - + tree.remove(toRemove); return new ResWrap<EntityCollection>(contextURL, metadataETag, entitySet); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java index cb1c65a..af21df7 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java @@ -20,13 +20,16 @@ package org.apache.olingo.client.core.serialization; import java.io.IOException; import java.net.URI; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.olingo.client.api.data.ResWrap; import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.data.Annotation; +import org.apache.olingo.commons.api.data.Operation; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.ValueType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; @@ -93,6 +96,7 @@ public class JsonPropertyDeserializer extends JsonDeserializer { tree.remove(Constants.VALUE); } + Set<String> toRemove = new HashSet<String>(); // any remaining entry is supposed to be an annotation or is ignored for (final Iterator<Map.Entry<String, JsonNode>> itor = tree.fields(); itor.hasNext();) { final Map.Entry<String, JsonNode> field = itor.next(); @@ -106,9 +110,18 @@ public class JsonPropertyDeserializer extends JsonDeserializer { throw new IOException(e); } property.getAnnotations().add(annotation); + } else if (field.getKey().charAt(0) == '#') { + final Operation operation = new Operation(); + operation.setMetadataAnchor(field.getKey()); + + final ObjectNode opNode = (ObjectNode) tree.get(field.getKey()); + operation.setTitle(opNode.get(Constants.ATTR_TITLE).asText()); + operation.setTarget(URI.create(opNode.get(Constants.ATTR_TARGET).asText())); + property.getOperations().add(operation); + toRemove.add(field.getKey()); } } - + tree.remove(toRemove); return new ResWrap<Property>(contextURL, metadataETag, property); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java index a67de48..1059c58 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java @@ -414,6 +414,14 @@ public class ODataBinderImpl implements ODataBinder { if (resource.getPayload().getCount() != null) { entitySet.setCount(resource.getPayload().getCount()); } + + for (Operation op : resource.getPayload().getOperations()) { + ClientOperation operation = new ClientOperation(); + operation.setTarget(URIUtils.getURI(base, op.getTarget())); + operation.setTitle(op.getTitle()); + operation.setMetadataAnchor(op.getMetadataAnchor()); + entitySet.getOperations().add(operation); + } for (Entity entityResource : resource.getPayload().getEntities()) { add(entitySet, getODataEntity( @@ -660,8 +668,13 @@ public class ODataBinderImpl implements ODataBinder { odataNavigationLinks(edmType, resource.getPayload(), entity, resource.getMetadataETag(), base); for (Link link : resource.getPayload().getMediaEditLinks()) { - entity.addLink(client.getObjectFactory(). - newMediaEditLink(link.getTitle(), URIUtils.getURI(base, link.getHref()))); + if (link.getRel().startsWith(Constants.NS_MEDIA_READ_LINK_REL)) { + entity.addLink(client.getObjectFactory().newMediaReadLink(link.getTitle(), + URIUtils.getURI(base, link.getHref()), link.getType(), link.getMediaETag())); + } else { + entity.addLink(client.getObjectFactory().newMediaEditLink(link.getTitle(), + URIUtils.getURI(base, link.getHref()), link.getType(), link.getMediaETag())); + } } for (Operation op : resource.getPayload().getOperations()) { @@ -735,7 +748,14 @@ public class ODataBinderImpl implements ODataBinder { getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(), payload, resource.getContextURL(), resource.getMetadataETag())); odataAnnotations(payload, property); - + + for (Operation op : resource.getPayload().getOperations()) { + ClientOperation operation = new ClientOperation(); + operation.setTarget(op.getTarget()); + operation.setTitle(op.getTitle()); + operation.setMetadataAnchor(op.getMetadataAnchor()); + property.getOperations().add(operation); + } return property; } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java index 88b3d86..74db088 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java @@ -51,6 +51,8 @@ public interface Constants { String NS_ASSOCIATION_LINK_REL = "http://docs.oasis-open.org/odata/ns/relatedlinks/"; String NS_MEDIA_EDIT_LINK_REL = "http://docs.oasis-open.org/odata/ns/edit-media/"; + + String NS_MEDIA_READ_LINK_REL = "http://docs.oasis-open.org/odata/ns/mediaresource/"; String NS_DELTA_LINK_REL = "http://docs.oasis-open.org/odata/ns/delta"; @@ -274,6 +276,8 @@ public interface Constants { QName QNAME_ATOM_ELEM_CONTENT = new QName(NS_ATOM, ATOM_ELEM_CONTENT); String ATOM_ELEM_ACTION = "action"; + + String ATOM_ELEM_FUNCTION = "function"; String ATOM_ELEM_INLINE = "inline"; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java index 2d7a689..9521591 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java @@ -19,6 +19,7 @@ package org.apache.olingo.commons.api.data; import java.net.URI; +import java.util.List; public abstract class AbstractEntityCollection extends AbstractODataObject implements Iterable<Entity> { public abstract Integer getCount(); @@ -26,4 +27,6 @@ public abstract class AbstractEntityCollection extends AbstractODataObject imple public abstract URI getNext(); public abstract URI getDeltaLink(); + + public abstract List<Operation> getOperations(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java index 86d8747..d95c536 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java @@ -32,7 +32,8 @@ public class EntityCollection extends AbstractEntityCollection { private Integer count; private URI next; private URI deltaLink; - + private final List<Operation> operations = new ArrayList<Operation>(); + /** * Sets number of entries. * @@ -98,6 +99,16 @@ public class EntityCollection extends AbstractEntityCollection { public void setDeltaLink(final URI deltaLink) { this.deltaLink = deltaLink; } + + /** + * Gets operations. + * + * @return operations. + */ + @Override + public List<Operation> getOperations() { + return operations; + } @Override public Iterator<Entity> iterator() { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java index f7bf1fa..515de03 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java @@ -24,13 +24,16 @@ import java.net.URI; * Data representation for an operation. */ public class Operation { - + public enum Type {ACTION, FUNCTION}; + private String metadataAnchor; private String title; private URI target; + private Type type; + /** * Gets metadata anchor. * @@ -84,5 +87,20 @@ public class Operation { public void setTarget(final URI target) { this.target = target; } + + /** + * Gets the Operation Type + * @return + */ + public Type getType() { + return type; + } + /** + * Set the Operation type + * @param type + */ + public void setType(Type type) { + this.type = type; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java index 2117241..c8ad3c8 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java @@ -18,12 +18,16 @@ */ package org.apache.olingo.commons.api.data; +import java.util.ArrayList; +import java.util.List; + /** * Data representation for a property. */ public class Property extends Valuable { private String name; + private final List<Operation> operations = new ArrayList<Operation>(); /** * Creates a new property @@ -79,6 +83,15 @@ public class Property extends Valuable { public boolean isNull() { return getValue() == null || "Edm.Null".equals(getType()); } + + /** + * Gets operations. + * + * @return operations. + */ + public List<Operation> getOperations() { + return operations; + } @Override public boolean equals(final Object o) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java index 19ae049..1efdaca 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java @@ -121,6 +121,17 @@ public interface Edm { Boolean isBindingParameterCollection); /** + * Get Action by full qualified name and binding parameter type. + * Note: action can not be overloaded on binding type + * + * @param bindingParameterTypeName must not be null + * @param isBindingParameterCollection may be null + * @return {@link EdmAction} + */ + EdmAction getBoundActionWithBindingType(FullQualifiedName bindingParameterTypeName, + Boolean isBindingParameterCollection); + + /** * Get Function by full qualified name. * * @param functionName must not be null @@ -150,6 +161,16 @@ public interface Edm { Boolean isBindingParameterCollection, List<String> parameterNames); /** + * Get Function by binding parameter type + * + * @param bindingParameterTypeName must not be null + * @param isBindingParameterCollection may be null + * @return {@link EdmFunction} + */ + List<EdmFunction> getBoundFunctionsWithBindingType(FullQualifiedName bindingParameterTypeName, + Boolean isBindingParameterCollection); + + /** * Get Term full by qualified name. * * @param termName must not be null http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java ---------------------------------------------------------------------- diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java index 44597f3..bcfd394 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java @@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.EdmFunction; +import org.apache.olingo.commons.api.edm.EdmParameter; import org.apache.olingo.commons.api.edm.EdmSchema; import org.apache.olingo.commons.api.edm.EdmTerm; import org.apache.olingo.commons.api.edm.EdmTypeDefinition; @@ -416,4 +417,39 @@ public abstract class AbstractEdm implements Edm { TargetQualifierMapKey key = new TargetQualifierMapKey(targetName, annotationsGroup.getQualifier()); annotationGroups.put(key, annotationsGroup); } + + @Override + public EdmAction getBoundActionWithBindingType(FullQualifiedName bindingParameterTypeName, + Boolean isBindingParameterCollection) { + for (EdmSchema schema:getSchemas()) { + for (EdmAction action: schema.getActions()) { + if (action.isBound()) { + EdmParameter bindingParameter = action.getParameter(action.getParameterNames().get(0)); + if (bindingParameter.getType().getFullQualifiedName().equals(bindingParameterTypeName) + && bindingParameter.isCollection() == isBindingParameterCollection) { + return action; + } + } + } + } + return null; + } + + @Override + public List<EdmFunction> getBoundFunctionsWithBindingType(FullQualifiedName bindingParameterTypeName, + Boolean isBindingParameterCollection){ + List<EdmFunction> functions = new ArrayList<EdmFunction>(); + for (EdmSchema schema:getSchemas()) { + for (EdmFunction function: schema.getFunctions()) { + if (function.isBound()) { + EdmParameter bindingParameter = function.getParameter(function.getParameterNames().get(0)); + if (bindingParameter.getType().getFullQualifiedName().equals(bindingParameterTypeName) + && bindingParameter.isCollection() == isBindingParameterCollection) { + functions.add(function); + } + } + } + } + return functions; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java ---------------------------------------------------------------------- diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java index ff46b7d..b9f3a6c 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java @@ -21,6 +21,7 @@ package org.apache.olingo.commons.core.edm.primitivetype; import java.net.URI; import java.net.URISyntaxException; +import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; /** @@ -69,6 +70,10 @@ public final class EdmStream extends SingletonPrimitiveType { if (returnType.isAssignableFrom(URI.class)) { return returnType.cast(stream); + } else if (returnType.isAssignableFrom(Link.class)) { + Link link = new Link(); + link.setHref(value); + return returnType.cast(link); } else { throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported."); } @@ -81,6 +86,8 @@ public final class EdmStream extends SingletonPrimitiveType { if (value instanceof URI) { return ((URI) value).toASCIIString(); + } else if (value instanceof Link) { + return ((Link)value).getHref(); } else { throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported."); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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 67d794c..29c7134 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 @@ -220,14 +220,14 @@ public abstract class ServiceRequest { if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) { return (T) EntitySerializerOptions.with() - .contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl) + .contextURL(contextUrl) .expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption()) .writeOnlyReferences(references) .xml10InvalidCharReplacement(xmlReplacement) .build(); } else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) { return (T) EntityCollectionSerializerOptions.with() - .contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl) + .contextURL(contextUrl) .count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption()) .select(uriInfo.getSelectOption()).writeOnlyReferences(references) .id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath()) @@ -346,9 +346,4 @@ public abstract class ServiceRequest { dispatcher.request.setUriInfo(uriInfo); return (DataRequest)dispatcher.request; } - - private boolean isODataMetadataNone(final ContentType contentType) { - return contentType.isCompatible(ContentType.JSON) - && ContentType.VALUE_ODATA_METADATA_NONE.equals(contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA)); - } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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 b55d3dd..6d92abc 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 @@ -18,12 +18,15 @@ */ package org.apache.olingo.server.core.responses; +import java.util.List; 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.EdmAction; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.format.ContentType; @@ -43,6 +46,7 @@ import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.core.ContentNegotiatorException; import org.apache.olingo.server.core.ReturnRepresentation; import org.apache.olingo.server.core.ServiceRequest; +import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper; public class EntityResponse extends ServiceResponse { private final ReturnRepresentation returnRepresentation; @@ -92,6 +96,21 @@ public class EntityResponse extends ServiceResponse { return; } + if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) { + EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType( + entityType.getFullQualifiedName(), false); + if (action != null) { + entity.getOperations().add(buildOperation(action, entity.getId().toASCIIString())); + } + + List<EdmFunction> functions = this.metadata.getEdm() + .getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),false); + + for (EdmFunction function:functions) { + entity.getOperations().add(buildOperation(function, entity.getId().toASCIIString())); + } + } + // write the entity to response this.response.setContent(this.serializer.entity(this.metadata, entityType, entity, this.options).getContent()); writeOK(responseContentType); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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 622c95d..88762d2 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 @@ -18,13 +18,18 @@ */ package org.apache.olingo.server.core.responses; +import java.util.List; 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.data.EntityCollection; +import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpHeader; +import org.apache.olingo.commons.core.Encoder; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataServerError; @@ -35,6 +40,7 @@ import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.core.ContentNegotiatorException; import org.apache.olingo.server.core.ServiceRequest; +import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper; public class EntitySetResponse extends ServiceResponse { private final ODataSerializer serializer; @@ -70,6 +76,9 @@ public class EntitySetResponse extends ServiceResponse { return; } + if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) { + buildOperations(entityType, entitySet); + } // write the whole collection to response this.response.setContent(this.serializer.entityCollection(metadata, entityType, entitySet, this.options) .getContent()); @@ -90,5 +99,58 @@ public class EntitySetResponse extends ServiceResponse { } catch (SerializerException e) { writeServerError(true); } - } + } + + private void buildOperations(EdmEntityType entityType, + EntityCollection entitySet) { + EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType( + entityType.getFullQualifiedName(), true); + if (action != null) { + entitySet.getOperations().add(buildOperation(action, buildOperationTarget(options.getContextURL()))); + } + + action = this.metadata.getEdm().getBoundActionWithBindingType( + entityType.getFullQualifiedName(), false); + if (action != null) { + for (Entity entity:entitySet.getEntities()) { + entity.getOperations().add(buildOperation(action, entity.getId().toASCIIString())); + } + } + + List<EdmFunction> functions = this.metadata.getEdm() + .getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),true); + + for (EdmFunction function:functions) { + entitySet.getOperations().add(buildOperation(function, buildOperationTarget(options.getContextURL()))); + } + + functions = this.metadata.getEdm() + .getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),false); + + for (Entity entity:entitySet.getEntities()) { + for (EdmFunction function:functions) { + entity.getOperations().add(buildOperation(function, entity.getId().toASCIIString())); + } + } + } + + private String buildOperationTarget(ContextURL contextURL) { + StringBuilder result = new StringBuilder(); + if (contextURL.getServiceRoot() != null) { + result.append(contextURL.getServiceRoot()); + } + if (contextURL.getEntitySetOrSingletonOrType() != null) { + if (result.length() != 0) { + result.append("/"); + } + result.append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType())); + } + if (contextURL.getKeyPath() != null) { + result.append('(').append(contextURL.getKeyPath()).append(')'); + } + if (contextURL.getNavOrPropertyPath() != null) { + result.append('/').append(contextURL.getNavOrPropertyPath()); + } + return result.toString(); + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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 9dac341..4be20fc 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 @@ -18,17 +18,21 @@ */ package org.apache.olingo.server.core.responses; +import java.util.List; import java.util.Map; import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmComplexType; +import org.apache.olingo.commons.api.edm.EdmFunction; 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.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.commons.core.Encoder; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataServerError; @@ -40,6 +44,7 @@ import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.core.ContentNegotiatorException; import org.apache.olingo.server.core.ServiceRequest; +import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper; public class PropertyResponse extends ServiceResponse { private PrimitiveSerializerOptions primitiveOptions; @@ -108,6 +113,24 @@ public class PropertyResponse extends ServiceResponse { writeNoContent(true); return; } + + if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) { + ContextURL contextURL = (this.complexOptions != null) + ? this.complexOptions.getContextURL() + : this.primitiveOptions.getContextURL(); + EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType( + edmType.getFullQualifiedName(), this.collection); + if (action != null) { + property.getOperations().add(buildOperation(action, buildOperationTarget(contextURL))); + } + + List<EdmFunction> functions = this.metadata.getEdm() + .getBoundFunctionsWithBindingType(edmType.getFullQualifiedName(), this.collection); + + for (EdmFunction function:functions) { + property.getOperations().add(buildOperation(function, buildOperationTarget(contextURL))); + } + } if (edmType.getKind() == EdmTypeKind.PRIMITIVE) { writePrimitiveProperty((EdmPrimitiveType) edmType, property); @@ -170,5 +193,25 @@ public class PropertyResponse extends ServiceResponse { public void writeNotModified() { this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode()); close(); + } + + private String buildOperationTarget(ContextURL contextURL) { + StringBuilder result = new StringBuilder(); + if (contextURL.getServiceRoot() != null) { + result.append(contextURL.getServiceRoot()); + } + if (contextURL.getEntitySetOrSingletonOrType() != null) { + if (result.length() != 0) { + result.append("/"); + } + result.append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType())); + } + if (contextURL.getKeyPath() != null) { + result.append('(').append(contextURL.getKeyPath()).append(')'); + } + if (contextURL.getNavOrPropertyPath() != null) { + result.append('/').append(contextURL.getNavOrPropertyPath()); + } + return result.toString(); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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 17dd272..d0a9f23 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 @@ -20,14 +20,19 @@ package org.apache.olingo.server.core.responses; import java.io.InputStream; +import java.net.URI; import java.util.Map; +import org.apache.olingo.commons.api.data.Operation; +import org.apache.olingo.commons.api.edm.EdmAction; +import org.apache.olingo.commons.api.edm.EdmFunction; +import org.apache.olingo.commons.api.edm.EdmParameter; 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.ODataLibraryException; +import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ServiceMetadata; public abstract class ServiceResponse { @@ -126,4 +131,47 @@ public abstract class ServiceResponse { public abstract void accepts(ServiceResponseVisior visitor) throws ODataLibraryException, ODataApplicationException; + + protected static Operation buildOperation(EdmFunction function, String id) { + String fqn = function.getFullQualifiedName().getFullQualifiedNameAsString(); + Operation operation = new Operation(); + operation.setType(Operation.Type.FUNCTION); + operation.setTitle(fqn); + StringBuilder params = new StringBuilder(); + StringBuilder nameFQN = new StringBuilder(); + params.append(fqn); + nameFQN.append(fqn); + if (!function.getParameterNames().isEmpty() && function.getParameterNames().size() > 1) { + params.append("("); + nameFQN.append("("); + boolean first = true; + for (int i = 1; i < function.getParameterNames().size(); i++) { + String parameterName = function.getParameterNames().get(i); + EdmParameter p = function.getParameter(parameterName); + if (first) { + first = false; + } else { + params.append(","); + nameFQN.append(","); + } + params.append(p.getName()).append("=").append("@").append(p.getName()); + nameFQN.append(p.getName()); + } + params.append(")"); + nameFQN.append(")"); + } + operation.setMetadataAnchor("#"+nameFQN); + operation.setTarget(URI.create(id+"/"+params.toString())); + return operation; + } + + protected Operation buildOperation(EdmAction action, String id) { + String fqn = action.getFullQualifiedName().getFullQualifiedNameAsString(); + Operation operation = new Operation(); + operation.setMetadataAnchor("#"+fqn); + operation.setType(Operation.Type.ACTION); + operation.setTitle(fqn); + operation.setTarget(URI.create(id+"/"+fqn)); + return operation; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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 1299f68..5d7e2b2 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 @@ -163,6 +163,30 @@ public class TripPinServiceTest { } @Test + public void testReadEntityWithFullMetadata() throws Exception { + HttpResponse response = httpGET( + baseURL+ "/People('russellwhyte')?$format=application/json;odata.metadata=full", + 200); + JsonNode node = getJSONNode(response); + assertEquals("#Collection(String)", node.get("[email protected]").asText()); + assertEquals("Microsoft.OData.SampleService.Models.TripPin.ShareTrip", + node.get("#Microsoft.OData.SampleService.Models.TripPin.ShareTrip").get("title").asText()); + assertEquals("/People('russellwhyte')/Microsoft.OData.SampleService.Models.TripPin.ShareTrip", + node.get("#Microsoft.OData.SampleService.Models.TripPin.ShareTrip").get("target").asText()); + + assertEquals("Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline", + node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline").get("title").asText()); + assertEquals("/People('russellwhyte')/Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline", + node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline").get("target").asText()); + + assertEquals("Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips", + node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips(userName)").get("title").asText()); + assertEquals("/People('russellwhyte')/Microsoft.OData." + + "SampleService.Models.TripPin.GetFriendsTrips(userName=@userName)", + node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips(userName)").get("target").asText()); + } + + @Test public void testErrorResponse() throws Exception { HttpResponse response = httpGET(baseURL + "/Airlines(1)", 400); Header[] headers = response.getHeaders("Content-Type"); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java index 86697d5..63452f4 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java @@ -41,6 +41,7 @@ public final class ContentNegotiator { ContentType.JSON, ContentType.JSON_NO_METADATA, ContentType.APPLICATION_JSON, + ContentType.JSON_FULL_METADATA, ContentType.APPLICATION_ATOM_XML, ContentType.APPLICATION_XML)); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java ---------------------------------------------------------------------- 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 71ea0e7..b638ae7 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 @@ -64,7 +64,8 @@ public class ODataImpl extends OData { final String metadata = contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA); if (metadata == null || ContentType.VALUE_ODATA_METADATA_MINIMAL.equals(metadata) - || ContentType.VALUE_ODATA_METADATA_NONE.equals(metadata)) { + || ContentType.VALUE_ODATA_METADATA_NONE.equals(metadata) + || ContentType.VALUE_ODATA_METADATA_FULL.equals(metadata)) { serializer = new ODataJsonSerializer(contentType); } } else if (contentType.isCompatible(ContentType.APPLICATION_XML) http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java index c8b5f96..21c9b37 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java @@ -543,7 +543,8 @@ public class ODataXmlDeserializer implements ODataDeserializer { } } else if (link.getRel().startsWith(Constants.NS_ASSOCIATION_LINK_REL)) { entity.getAssociationLinks().add(link); - } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) { + } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL) || + link.getRel().startsWith(Constants.NS_MEDIA_READ_LINK_REL)) { final Attribute metag = event.asStartElement().getAttributeByName(etagQName); if (metag != null) { link.setMediaETag(metag.getValue());
