This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 895dee3d9fe5fbc0f07afc1e12cbd2f9450a330b Author: Marc Giger <gigerst...@gmx.ch> AuthorDate: Sun Aug 11 14:08:01 2019 +0200 CAMEL-13852: Support OData action's --- .../camel/component/olingo4/api/Olingo4App.java | 10 +++ .../component/olingo4/api/impl/Olingo4AppImpl.java | 31 ++++++--- .../camel/component/olingo4/Olingo4AppAPITest.java | 73 ++++++++++++++++++++++ .../camel-olingo4/camel-olingo4-component/pom.xml | 1 + .../src/signatures/olingo-api-signature.txt | 1 + .../olingo4/Olingo4ComponentProducerTest.java | 21 +++++++ 6 files changed, 129 insertions(+), 8 deletions(-) diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4App.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4App.java index 3863c1b..0649a7c 100644 --- a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4App.java +++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4App.java @@ -149,4 +149,14 @@ public interface Olingo4App { * @param responseHandler callback handler */ void batch(Edm edm, Map<String, String> endpointHttpHeaders, Object data, Olingo4ResponseHandler<List<Olingo4BatchResponse>> responseHandler); + + /** + * Calls a OData action + * @param edm service Edm + * @param resourcePath resource path to action + * @param endpointHttpHeaders HTTP Headers to add/override the component versions + * @param data action data + * @param responseHandler {@link org.apache.olingo.client.api.domain.ClientEntity} callback handler + */ + <T> void action(Edm edm, String resourcePath, Map<String, String> endpointHttpHeaders, Object data, Olingo4ResponseHandler<T> responseHandler); } diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java index c59e562..84ef1e3 100644 --- a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java +++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java @@ -40,14 +40,7 @@ import org.apache.camel.util.ObjectHelper; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; import org.apache.commons.lang3.StringUtils; -import org.apache.http.Consts; -import org.apache.http.Header; -import org.apache.http.HttpException; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpResponse; -import org.apache.http.HttpResponseFactory; -import org.apache.http.HttpVersion; -import org.apache.http.StatusLine; +import org.apache.http.*; import org.apache.http.client.entity.DecompressingEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; @@ -60,6 +53,7 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.concurrent.FutureCallback; import org.apache.http.config.MessageConstraints; import org.apache.http.entity.AbstractHttpEntity; +import org.apache.http.entity.BasicHttpEntity; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.DefaultHttpResponseFactory; @@ -311,6 +305,13 @@ public final class Olingo4AppImpl implements Olingo4App { writeContent(edm, new HttpPost(createUri(SegmentType.BATCH.getValue(), null)), uriInfo, data, endpointHttpHeaders, responseHandler); } + @Override + public <T> void action(final Edm edm, final String resourcePath, final Map<String, String> endpointHttpHeaders, final Object data, final Olingo4ResponseHandler<T> responseHandler) { + final UriInfo uriInfo = parseUri(edm, resourcePath, null, serviceUri); + + writeContent(edm, new HttpPost(createUri(resourcePath, null)), uriInfo, data, endpointHttpHeaders, responseHandler); + } + private ContentType getResourceContentType(UriInfo uriInfo) { ContentType resourceContentType; switch (uriInfo.getKind()) { @@ -478,6 +479,7 @@ public final class Olingo4AppImpl implements Olingo4App { List<UriResource> listResource = uriInfo.getUriResourceParts(); UriResourceKind lastResourceKind = listResource.get(listResource.size() - 1).getKind(); switch (lastResourceKind) { + case action: case entitySet: ClientEntity entity = odataReader.readEntity(result.getEntity().getContent(), ContentType.parse(result.getEntity().getContentType().getValue())); @@ -511,6 +513,19 @@ public final class Olingo4AppImpl implements Olingo4App { List<UriResource> listResource = uriInfo.getUriResourceParts(); UriResourceKind lastResourceKind = listResource.get(listResource.size() - 1).getKind(); switch (lastResourceKind) { + case action: + if (content == null) { + requestStream = new ByteArrayInputStream(new byte[0]); + } else if (content instanceof ClientEntity) { + requestStream = odataWriter.writeEntity((ClientEntity)content, getResourceContentType(uriInfo)); + } else if (content instanceof String) { + httpEntity = new StringEntity((String) content, org.apache.http.entity.ContentType.APPLICATION_JSON); + httpEntity.setChunked(false); + return httpEntity; + } else { + throw new ODataException("Unsupported content type: " + content); + } + break; case entitySet: if (content instanceof ClientEntity) { requestStream = odataWriter.writeEntity((ClientEntity)content, getResourceContentType(uriInfo)); diff --git a/components/camel-olingo4/camel-olingo4-api/src/test/java/org/apache/camel/component/olingo4/Olingo4AppAPITest.java b/components/camel-olingo4/camel-olingo4-api/src/test/java/org/apache/camel/component/olingo4/Olingo4AppAPITest.java index 728cb2d..86ebfc6 100644 --- a/components/camel-olingo4/camel-olingo4-api/src/test/java/org/apache/camel/component/olingo4/Olingo4AppAPITest.java +++ b/components/camel-olingo4/camel-olingo4-api/src/test/java/org/apache/camel/component/olingo4/Olingo4AppAPITest.java @@ -39,11 +39,16 @@ import org.apache.camel.component.olingo4.api.batch.Olingo4BatchRequest; import org.apache.camel.component.olingo4.api.batch.Olingo4BatchResponse; import org.apache.camel.component.olingo4.api.batch.Operation; import org.apache.camel.component.olingo4.api.impl.Olingo4AppImpl; +import org.apache.http.HttpException; import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpResponseInterceptor; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.ExecutionContext; @@ -60,6 +65,8 @@ import org.apache.olingo.client.api.domain.ClientProperty; import org.apache.olingo.client.api.domain.ClientServiceDocument; import org.apache.olingo.client.api.domain.ClientValue; import org.apache.olingo.client.api.serialization.ODataReader; +import org.apache.olingo.client.api.serialization.ODataSerializerException; +import org.apache.olingo.client.api.serialization.ODataWriter; import org.apache.olingo.client.core.ODataClientFactory; import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.edm.Edm; @@ -98,6 +105,8 @@ public class Olingo4AppAPITest { private static final String TEST_AIRPORTS_COMPLEX_PROPERTY = TEST_AIRPORT + "/Location"; private static final String TEST_AIRPORTS_SIMPLE_PROPERTY_VALUE = TEST_AIRPORTS_SIMPLE_PROPERTY + "/$value"; private static final String COUNT_OPTION = "/$count"; + private static final String TEST_UNBOUND_ACTION_RESETDATASOURCE = "ResetDataSource"; + private static final String TEST_BOUND_ACTION_PEOPLE_SHARETRIP = TEST_PEOPLE +"/Microsoft.OData.Service.Sample.TrippinInMemory.Models.ShareTrip"; private static final String TEST_SERVICE_BASE_URL = "http://services.odata.org/TripPinRESTierService"; private static final ContentType TEST_FORMAT = ContentType.APPLICATION_JSON; @@ -405,6 +414,70 @@ public class Olingo4AppAPITest { assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), responseParts.get(7).getStatusCode()); } + @Test + public void testUnboundActionRequest() throws Exception { + final TestOlingo4ResponseHandler<HttpStatusCode> responseHandler = new TestOlingo4ResponseHandler<>(); + olingoApp.action(edm, TEST_UNBOUND_ACTION_RESETDATASOURCE, null, null, responseHandler); + + final HttpStatusCode statusCode = responseHandler.await(15, TimeUnit.MINUTES); + assertEquals(204, statusCode.getStatusCode()); + } + + @Test + public void testBoundActionRequest() throws Exception { + final ClientEntity clientEntity = objFactory.newEntity(null); + clientEntity.getProperties().add(objFactory.newPrimitiveProperty("userName", objFactory.newPrimitiveValueBuilder().buildString("scottketchum"))); + clientEntity.getProperties().add(objFactory.newPrimitiveProperty("tripId", objFactory.newPrimitiveValueBuilder().buildInt32(0))); + + final TestOlingo4ResponseHandler<HttpStatusCode> responseHandler = new TestOlingo4ResponseHandler<>(); + olingoApp.action(edm, TEST_BOUND_ACTION_PEOPLE_SHARETRIP, null, clientEntity, responseHandler); + + final HttpStatusCode statusCode = responseHandler.await(15, TimeUnit.MINUTES); + assertEquals(204, statusCode.getStatusCode()); + } + + + // Unfortunately there is no action that returns a client entity. So we fake one + @Test + public void testBoundActionRequestWithClientEntityResponse() throws Exception { + final ODataClient odataClient = ODataClientFactory.getClient(); + final ODataWriter odataWriter = odataClient.getWriter(); + + final HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); + httpClientBuilder.addInterceptorFirst(new HttpResponseInterceptor() { + @Override + public void process(HttpResponse response, HttpContext context) throws HttpException, IOException { + if (response.getStatusLine().getStatusCode() == 204) { + try { + response.setEntity( + new InputStreamEntity( + odataWriter.writeEntity(createEntity(), ContentType.JSON), + org.apache.http.entity.ContentType.parse(ContentType.JSON.toContentTypeString()))); + response.setStatusCode(200); + } catch (ODataSerializerException e) { + throw new IOException(e); + } + } + } + }); + final Olingo4App olingoApp = new Olingo4AppImpl(getRealServiceUrl(TEST_SERVICE_BASE_URL), httpClientBuilder); + olingoApp.setContentType(TEST_FORMAT_STRING); + + final TestOlingo4ResponseHandler<Edm> responseHandler = new TestOlingo4ResponseHandler<>(); + olingoApp.read(null, Constants.METADATA, null, null, responseHandler); + final Edm edm = responseHandler.await(); + + final ClientEntity clientEntity = objFactory.newEntity(null); + clientEntity.getProperties().add(objFactory.newPrimitiveProperty("userName", objFactory.newPrimitiveValueBuilder().buildString("scottketchum"))); + clientEntity.getProperties().add(objFactory.newPrimitiveProperty("tripId", objFactory.newPrimitiveValueBuilder().buildInt32(0))); + + final TestOlingo4ResponseHandler<ClientEntity> actionResponseHandler = new TestOlingo4ResponseHandler<>(); + olingoApp.action(edm, TEST_BOUND_ACTION_PEOPLE_SHARETRIP, null, clientEntity, actionResponseHandler); + + final ClientEntity result = actionResponseHandler.await(15, TimeUnit.MINUTES); + assertEquals("lewisblack", result.getProperty("UserName").getValue().toString()); + } + private ClientEntity createEntity() { ClientEntity clientEntity = objFactory.newEntity(null); diff --git a/components/camel-olingo4/camel-olingo4-component/pom.xml b/components/camel-olingo4/camel-olingo4-component/pom.xml index adcd6af..0f14877 100644 --- a/components/camel-olingo4/camel-olingo4-component/pom.xml +++ b/components/camel-olingo4/camel-olingo4-component/pom.xml @@ -149,6 +149,7 @@ <nullableOption>endpointHttpHeaders</nullableOption> <nullableOption>edm</nullableOption> <nullableOption>responseHandler</nullableOption> + <nullableOption>data</nullableOption> </nullableOptions> </api> </apis> diff --git a/components/camel-olingo4/camel-olingo4-component/src/signatures/olingo-api-signature.txt b/components/camel-olingo4/camel-olingo4-component/src/signatures/olingo-api-signature.txt index fb941e6..66a2110 100644 --- a/components/camel-olingo4/camel-olingo4-component/src/signatures/olingo-api-signature.txt +++ b/components/camel-olingo4/camel-olingo4-component/src/signatures/olingo-api-signature.txt @@ -6,3 +6,4 @@ void update(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, java void patch(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, java.util.Map<String, String> endpointHttpHeaders, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler); void merge(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, java.util.Map<String, String> endpointHttpHeaders, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler); void batch(org.apache.olingo.commons.api.edm.Edm edm, java.util.Map<String, String> endpointHttpHeaders, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler); +void action(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, java.util.Map<String, String> endpointHttpHeaders, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler); diff --git a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java index 2493b94..13a1de6 100644 --- a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java +++ b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java @@ -273,6 +273,22 @@ public class Olingo4ComponentProducerTest extends AbstractOlingo4TestSupport { LOG.info("Read deleted entity error: {}", error.getMessage()); } + @Test + public void testUnboundActionRequest() throws Exception { + final HttpStatusCode status = requestBody("direct:unbound-action-ResetDataSource", null); + assertEquals(204, status.getStatusCode()); + } + + @Test + public void testBoundActionRequest() throws Exception { + final ClientEntity clientEntity = objFactory.newEntity(null); + clientEntity.getProperties().add(objFactory.newPrimitiveProperty("userName", objFactory.newPrimitiveValueBuilder().buildString("scottketchum"))); + clientEntity.getProperties().add(objFactory.newPrimitiveProperty("tripId", objFactory.newPrimitiveValueBuilder().buildInt32(0))); + + final HttpStatusCode status = requestBody("direct:bound-action-people", clientEntity); + assertEquals(204, status.getStatusCode()); + } + @SuppressWarnings("unchecked") @Test public void testEndpointHttpHeaders() throws Exception { @@ -425,6 +441,11 @@ public class Olingo4ComponentProducerTest extends AbstractOlingo4TestSupport { from("direct:read-people-nofilterseen").to("olingo4://read/" + PEOPLE).to("mock:producer-noalreadyseen"); from("direct:read-people-filterseen").to("olingo4://read/" + PEOPLE + "?filterAlreadySeen=true").to("mock:producer-alreadyseen"); + + // test routes action's + from("direct:unbound-action-ResetDataSource").to("olingo4://action/ResetDataSource"); + + from("direct:bound-action-people").to("olingo4://action/" + TEST_PEOPLE + "/Microsoft.OData.Service.Sample.TrippinInMemory.Models.ShareTrip"); } }; }