You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2017/03/24 08:59:32 UTC

[1/6] camel git commit: CAMEL-11056: Update camel-olingo4 component doc

Repository: camel
Updated Branches:
  refs/heads/master 46180b9cf -> ea11a6241


CAMEL-11056: Update camel-olingo4 component doc

Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/71c8bdd4
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/71c8bdd4
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/71c8bdd4

Branch: refs/heads/master
Commit: 71c8bdd4fd19f0e0295252ee35d676b047294849
Parents: e6eded4
Author: Dmitry Volodin <dm...@gmail.com>
Authored: Thu Mar 23 17:02:16 2017 +0300
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Fri Mar 24 09:49:39 2017 +0100

----------------------------------------------------------------------
 .../src/main/docs/olingo4-component.adoc        | 112 ++++++++-----------
 1 file changed, 45 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/71c8bdd4/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
index e9cfb97..cab1e53 100644
--- a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
@@ -2,17 +2,17 @@
 
 *Available as of Camel version 2.19.0*
 
-The Olingo2 component utilizes�http://olingo.apache.org/[Apache Olingo]
-version 2.0�APIs to interact with OData 2.0 and 3.0 compliant services.
-A number of popular commercial and enterprise vendors and products
-support the OData protocol. A sample list of supporting products can be
-found on the OData http://www.odata.org/ecosystem/[website].
-
-The Olingo2 component supports reading feeds, delta feeds, entities,
-simple and complex properties, links, counts, using custom and OData
-system query parameters. It supports updating entities, properties, and
-association links. It also supports submitting queries and change
-requests as a single OData batch operation.�
+The Olingo4 component utilizes�http://olingo.apache.org/[Apache Olingo]
+version 4.0�APIs to interact with OData 4.0 compliant service.
+Since verison 4.0 OData is OASIS standard and number of popular commercial
+and enterprise vendors and products support this protocol.
+A sample list of supporting products can be found on the OData 
+http://www.odata.org/ecosystem/[website].
+
+The Olingo4 component supports reading entitiy sets, entities,
+simple and complex properties, counts, using custom and OData
+system query parameters. It supports updating entities and properties.
+It also supports submitting queries and change requests as a single OData batch operation.�
 
 The component supports configuring HTTP connection parameters and
 headers for OData service connection. This allows configuring�use of
@@ -25,7 +25,7 @@ for this component:
 ----------------------------------------------
     <dependency>
         <groupId>org.apache.camel</groupId>
-        <artifactId>camel-olingo2</artifactId>
+        <artifactId>camel-olingo4</artifactId>
         <version>${camel-version}</version>
     </dependency>
 ----------------------------------------------
@@ -34,10 +34,10 @@ for this component:
 
 [source,java]
 ------------------------------------------------
-    olingo2://endpoint/<resource-path>?[options]
+    olingo4://endpoint/<resource-path>?[options]
 ------------------------------------------------
 
-### Olingo2 Options
+### Olingo4 Options
 
 
 
@@ -77,7 +77,7 @@ The Olingo4 component supports 16 endpoint options which are listed below:
 | httpHeaders | common |  | Map | Custom HTTP headers to inject into every request this could include OAuth tokens etc.
 | inBody | common |  | String | Sets the name of a parameter to be passed in the exchange In Body
 | proxy | common |  | HttpHost | HTTP proxy server configuration
-| serviceUri | common |  | String | Target OData service base URI e.g. http://services.odata.org/OData/OData.svc
+| serviceUri | common |  | String | Target OData service base URI e.g. http://services.odata.org/TripPinRESTierService/
 | socketTimeout | common | 30000 | int | HTTP request timeout in milliseconds defaults to 30000 (30 seconds)
 | sslContextParameters | common |  | SSLContextParameters | To configure security using SSLContextParameters
 | bridgeErrorHandler | consumer | false | boolean | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored.
@@ -99,16 +99,16 @@ defaults to *data*�for endpoints that take that�option.�
 
 Any of the endpoint options can be provided in either the endpoint URI,
 or dynamically in a message header. The message header name must be of
-the format�*`CamelOlingo2.<option>`*. Note that the�*`inBody`*�option
+the format�*`CamelOlingo4.<option>`*. Note that the�*`inBody`*�option
 overrides message header, i.e. the endpoint
 option�*`inBody=option`*�would override
-a�*`CamelOlingo2.option`*�header. In addition, query parameters can be
+a�*`CamelOlingo4.option`*�header. In addition, query parameters can be
 specified�
 
 Note that the resourcePath option can either in specified in the URI as
 a part of the URI path, as an endpoint option
 ?resourcePath=<resource-path> or as a header value
-CamelOlingo2.resourcePath. The OData entity key predicate can either be
+CamelOlingo4.resourcePath. The OData entity key predicate can either be
 a part of the resource path, e.g. _Manufacturers('1')_, where _'__1'_�is
 the key predicate, or be specified separately with resource path
 _Manufacturers_�and keyPredicate option _'1'_.�
@@ -117,20 +117,20 @@ _Manufacturers_�and keyPredicate option _'1'_.�
 |=======================================================================
 |Endpoint |Options |HTTP Method |Result Body Type
 
-|batch |data |POST with multipart/mixed batch request |java.util.List<org.apache.camel.component.olingo2.api.batch.Olingo2BatchResponse>
+|batch |data |POST with multipart/mixed batch request |java.util.List<org.apache.camel.component.olingo4.api.batch.Olingo4BatchResponse>
 
-|create |data, resourcePath |POST |org.apache.olingo.odata2.api.ep.entry.ODataEntry for new entries
-org.apache.olingo.odata2.api.commons.HttpStatusCodes for other OData resources
+|create |data, resourcePath |POST |org.apache.olingo.client.api.domain.ClientEntity for new entries
+org.apache.olingo.commons.api.http.HttpStatusCode for other OData resources
 
-|delete |resourcePath |DELETE |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+|delete |resourcePath |DELETE |org.apache.olingo.commons.api.http.HttpStatusCode
 
-|merge |data, resourcePath |MERGE |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+|merge |data, resourcePath |MERGE |org.apache.olingo.commons.api.http.HttpStatusCode
 
-|patch |data, resourcePath |PATCH |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+|patch |data, resourcePath |PATCH |org.apache.olingo.commons.api.http.HttpStatusCode
 
 |read |queryParams, resourcePath |GET |Depends on OData resource being queried as described next
 
-|update |data, resourcePath |PUT |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+|update |data, resourcePath |PUT |org.apache.olingo.commons.api.http.HttpStatusCode
 |=======================================================================
 
 ### OData Resource Type Mapping
@@ -142,26 +142,20 @@ the OData resource being queried, created or modified.�
 |=======================================================================
 |OData Resource Type |Resource URI from resourcePath and keyPredicate |In or Out Body Type
 
-|Entity data model |$metadata |org.apache.olingo.odata2.api.edm.Edm
+|Entity data model |$metadata |org.apache.olingo.commons.api.edm.Edm
 
-|Service document |/ |org.apache.olingo.odata2.api.servicedocument.ServiceDocument
+|Service document |/ |org.apache.olingo.client.api.domain.ClientServiceDocument
 
-|OData feed |<entity-set> |org.apache.olingo.odata2.api.ep.feed.ODataFeed
+|OData entity set |<entity-set> |org.apache.olingo.client.api.domain.ClientEntitySet
 
-|OData entry |<entity-set>(<key-predicate>) |org.apache.olingo.odata2.api.ep.entry.ODataEntry for Out body (response)
+|OData entity |<entity-set>(<key-predicate>) |org.apache.olingo.client.api.domain.ClientEntity for Out body (response)
 java.util.Map<String, Object> for In body (request)
 
-|Simple property |<entity-set>(<key-predicate>)/<simple-property> |Appropriate Java data type as described by Olingo EdmProperty
+|Simple property |<entity-set>(<key-predicate>)/<simple-property> |org.apache.olingo.client.api.domain.ClientPrimitiveValue
 
-|Simple property value |<entity-set>(<key-predicate>)/<simple-property>/$value |Appropriate Java data type as described by Olingo EdmProperty
+|Simple property value |<entity-set>(<key-predicate>)/<simple-property>/$value |org.apache.olingo.client.api.domain.ClientPrimitiveValue
 
-|Complex property |<entity-set>(<key-predicate>)/<complex-property> |java.util.Map<String, Object>
-
-|Zero or one association link |<entity-set>(<key-predicate>/$link/<one-to-one-entity-set-property> |String for response
-java.util.Map<String, Object> with key property names and values for request
-
-|Zero or many association links |<entity-set>(<key-predicate>/$link/<one-to-many-entity-set-property> |java.util.List<String> for response
-java.util.List<java.util.Map<String, Object>> containing list of key property names and values for request
+|Complex property |<entity-set>(<key-predicate>)/<complex-property> |org.apache.olingo.client.api.domain.ClientComplexValue
 
 |Count |<resource-uri>/$count |java.lang.Long
 |=======================================================================
@@ -180,13 +174,13 @@ setting the endpoint property *consumer.splitResult=false*.�
 ### Message Headers
 
 Any URI option can be provided in a message header for producer
-endpoints with a�*`CamelOlingo2.`*�prefix.
+endpoints with a�*`CamelOlingo4.`*�prefix.
 
 ### Message Body
 
 All result message bodies utilize objects provided by the underlying
-http://olingo.apache.org/javadoc/odata2/index.html[Apache Olingo 2.0
-API] used by the Olingo2Component. Producer endpoints can specify the
+http://olingo.apache.org/javadoc/odata4/index.html[Apache Olingo 4.0
+API] used by the Olingo4Component. Producer endpoints can specify the
 option name for incoming message body in the�*`inBody`*�endpoint URI
 parameter. For endpoints that return an array or collection, a consumer
 endpoint will map every element to distinct messages, unless
@@ -194,21 +188,21 @@ endpoint will map every element to distinct messages, unless
 
 ### Use cases
 
-The following route reads top 5 entries from the Manufacturer feed
-ordered by ascending Name property.�
+The following route reads top 5 entries from the People entity
+ordered by ascending FirstName property.�
 
 �
 
 [source,java]
 ------------------------------------------------------------
 from("direct:...")
-    .setHeader("CamelOlingo2.$top", "5");
-    .to("olingo2://read/Manufacturers?orderBy=Name%20asc");
+    .setHeader("CamelOlingo4.$top", "5");
+    .to("olingo4://read/People?orderBy=FirstName%20asc");
 ------------------------------------------------------------
 
 �
 
-The following route reads Manufacturer entry using the key property
+The following route reads Airports entity using the key property
 value in incoming�*id* header.�
 
 �
@@ -216,37 +210,21 @@ value in incoming�*id* header.�
 [source,java]
 ------------------------------------------------------------
 from("direct:...")
-    .setHeader("CamelOlingo2.keyPredicate", header("id"))
-    .to("olingo2://read/Manufacturers");
+    .setHeader("CamelOlingo4.keyPredicate", header("id"))
+    .to("olingo4://read/Airports");
 ------------------------------------------------------------
 
 �
 
-The following route creates Manufacturer entry using the
-*java.util.Map<String, Object>* in body message.�
+The following route creates People entity using the
+*ClientEntity* in body message.�
 
 �
 
 [source,java]
 ------------------------------------------------------------
 from("direct:...")
-    .to("olingo2://create/Manufacturers");
+    .to("olingo4://create/People");
 ------------------------------------------------------------
 
-�
-
-The following route polls Manufacturer
-http://olingo.apache.org/doc/tutorials/deltaClient.html[delta
-feed]�every 30 seconds. The bean *blah*�updates the bean�*paramsBean*�to
-add an updated�*!deltatoken* property with the value returned in the
-*ODataDeltaFeed* result. Since the initial delta token is not known, the
-consumer endpoint will produce an�*ODataFeed* value the first time, and
-*ODataDeltaFeed* on subsequent polls.�
-
-�
-
-[source,java]
----------------------------------------------------------------------------------------------------------
-from("olingo2://read/Manufacturers?queryParams=#paramsBean&consumer.timeUnit=SECONDS&consumer.delay=30")
-    .to("bean:blah");
 ---------------------------------------------------------------------------------------------------------


[4/6] camel git commit: CAMEL-11056: Create new camel-olingo4 component for supporting OData 4.0

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/LICENSE.txt b/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/NOTICE.txt b/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/test/java/org/apache/camel/component/olingo4/Olingo4AppAPITest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..6cfe3e9
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/test/java/org/apache/camel/component/olingo4/Olingo4AppAPITest.java
@@ -0,0 +1,543 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.component.olingo4.api.Olingo4App;
+import org.apache.camel.component.olingo4.api.Olingo4ResponseHandler;
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchChangeRequest;
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchQueryRequest;
+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.HttpHost;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.domain.ClientCollectionValue;
+import org.apache.olingo.client.api.domain.ClientComplexValue;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.api.domain.ClientEnumValue;
+import org.apache.olingo.client.api.domain.ClientObjectFactory;
+import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
+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.core.ODataClientFactory;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration test for
+ * {@link org.apache.camel.component.olingo4.api.impl.Olingo4AppImpl} using the
+ * sample OData 4.0 remote TripPin service published on
+ * http://services.odata.org/TripPinRESTierService.
+ */
+public class Olingo4AppAPITest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Olingo4AppAPITest.class);
+    private static final long TIMEOUT = 10;
+
+    private static final String PEOPLE = "People";
+    private static final String TEST_PEOPLE = "People('russellwhyte')";
+    private static final String TEST_AIRLINE = "Airlines('FM')";
+    private static final String TRIPS = "Trips";
+    private static final String TEST_CREATE_RESOURCE_CONTENT_ID = "1";
+    private static final String TEST_UPDATE_RESOURCE_CONTENT_ID = "2";
+    private static final String TEST_CREATE_KEY = "'lewisblack'";
+    private static final String TEST_CREATE_PEOPLE = PEOPLE + "(" + TEST_CREATE_KEY + ")";
+    private static final String TEST_AIRPORT = "Airports('KSFO')";
+    private static final String TEST_AIRPORTS_SIMPLE_PROPERTY = TEST_AIRPORT + "/Name";
+    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_SERVICE_BASE_URL = "http://services.odata.org/TripPinRESTierService";
+    private static final ContentType TEST_FORMAT = ContentType.APPLICATION_JSON;
+    private static final String TEST_FORMAT_STRING = TEST_FORMAT.toString();
+
+    private static Olingo4App olingoApp;
+    private static Edm edm;
+    private final ODataClient odataClient = ODataClientFactory.getClient();
+    private final ClientObjectFactory objFactory = odataClient.getObjectFactory();
+    private final ODataReader reader = odataClient.getReader();
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        setupClient();
+    }
+
+    @AfterClass
+    public static void afterClass() throws Exception {
+        if (olingoApp != null) {
+            olingoApp.close();
+        }
+    }
+
+    protected static void setupClient() throws Exception {
+        olingoApp = new Olingo4AppImpl(getRealServiceUrl(TEST_SERVICE_BASE_URL));
+        olingoApp.setContentType(TEST_FORMAT_STRING);
+
+        LOG.info("Read Edm ");
+        final TestOlingo4ResponseHandler<Edm> responseHandler = new TestOlingo4ResponseHandler<Edm>();
+
+        olingoApp.read(null, Constants.METADATA, null, responseHandler);
+
+        edm = responseHandler.await();
+        LOG.info("Read default EntityContainer:  {}", responseHandler.await().getEntityContainer().getName());
+    }
+
+    /*
+     * Every request to the demo OData 4.0
+     * (http://services.odata.org/TripPinRESTierService) generates unique
+     * service URL with postfix like (S(tuivu3up5ygvjzo5fszvnwfv)) for each
+     * session This method makes reuest to the base URL and return URL with
+     * generated postfix
+     */
+    @SuppressWarnings("deprecation")
+    protected static String getRealServiceUrl(String baseUrl) throws ClientProtocolException, IOException {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        HttpGet httpGet = new HttpGet(baseUrl);
+        HttpContext httpContext = new BasicHttpContext();
+        httpclient.execute(httpGet, httpContext);
+        HttpUriRequest currentReq = (HttpUriRequest)httpContext.getAttribute(ExecutionContext.HTTP_REQUEST);
+        HttpHost currentHost = (HttpHost)httpContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+        String currentUrl = (currentReq.getURI().isAbsolute()) ? currentReq.getURI().toString() : (currentHost.toURI() + currentReq.getURI());
+
+        return currentUrl;
+    }
+
+    @Test
+    public void testServiceDocument() throws Exception {
+        final TestOlingo4ResponseHandler<ClientServiceDocument> responseHandler = new TestOlingo4ResponseHandler<ClientServiceDocument>();
+
+        olingoApp.read(null, "", null, responseHandler);
+        final ClientServiceDocument serviceDocument = responseHandler.await();
+
+        final Map<String, URI> entitySets = serviceDocument.getEntitySets();
+        assertEquals("Service Entity Sets", 4, entitySets.size());
+        LOG.info("Service Document Entries:  {}", entitySets);
+    }
+
+    @Test
+    public void testReadEntitySet() throws Exception {
+        final TestOlingo4ResponseHandler<ClientEntitySet> responseHandler = new TestOlingo4ResponseHandler<ClientEntitySet>();
+
+        olingoApp.read(edm, PEOPLE, null, responseHandler);
+
+        final ClientEntitySet entitySet = responseHandler.await();
+        assertNotNull(entitySet);
+        assertEquals("Entity set count", 20, entitySet.getEntities().size());
+        LOG.info("Entities:  {}", prettyPrint(entitySet));
+    }
+
+    @Test
+    public void testReadUnparsedEntitySet() throws Exception {
+        final TestOlingo4ResponseHandler<InputStream> responseHandler = new TestOlingo4ResponseHandler<InputStream>();
+
+        olingoApp.uread(edm, PEOPLE, null, responseHandler);
+
+        final InputStream rawEntitySet = responseHandler.await();
+        assertNotNull("Data entity set", rawEntitySet);
+        final ClientEntitySet entitySet = reader.readEntitySet(rawEntitySet, TEST_FORMAT);
+        assertEquals("Entity set count", 20, entitySet.getEntities().size());
+        LOG.info("Entries:  {}", prettyPrint(entitySet));
+    }
+
+    @Test
+    public void testReadEntity() throws Exception {
+        final TestOlingo4ResponseHandler<ClientEntity> responseHandler = new TestOlingo4ResponseHandler<ClientEntity>();
+
+        olingoApp.read(edm, TEST_AIRLINE, null, responseHandler);
+        ClientEntity entity = responseHandler.await();
+        assertEquals("Shanghai Airline", entity.getProperty("Name").getValue().toString());
+        LOG.info("Single Entity:  {}", prettyPrint(entity));
+
+        responseHandler.reset();
+
+        olingoApp.read(edm, TEST_PEOPLE, null, responseHandler);
+        entity = responseHandler.await();
+        assertEquals("Russell", entity.getProperty("FirstName").getValue().toString());
+        LOG.info("Single Entry:  {}", prettyPrint(entity));
+
+        responseHandler.reset();
+        final Map<String, String> queryParams = new HashMap<String, String>();
+        queryParams.put(SystemQueryOptionKind.EXPAND.toString(), TRIPS);
+
+        olingoApp.read(edm, TEST_PEOPLE, queryParams, responseHandler);
+        ClientEntity entityExpanded = responseHandler.await();
+        LOG.info("Single People Entiry with expanded Trips relation:  {}", prettyPrint(entityExpanded));
+    }
+
+    @Test
+    public void testReadUnparsedEntity() throws Exception {
+        final TestOlingo4ResponseHandler<InputStream> responseHandler = new TestOlingo4ResponseHandler<InputStream>();
+
+        olingoApp.uread(edm, TEST_AIRLINE, null, responseHandler);
+        InputStream rawEntity = responseHandler.await();
+        assertNotNull("Data entity", rawEntity);
+        ClientEntity entity = reader.readEntity(rawEntity, TEST_FORMAT);
+        assertEquals("Shanghai Airline", entity.getProperty("Name").getValue().toString());
+        LOG.info("Single Entity:  {}", prettyPrint(entity));
+
+        responseHandler.reset();
+
+        olingoApp.uread(edm, TEST_PEOPLE, null, responseHandler);
+        rawEntity = responseHandler.await();
+        entity = reader.readEntity(rawEntity, TEST_FORMAT);
+        assertEquals("Russell", entity.getProperty("FirstName").getValue().toString());
+        LOG.info("Single Entity:  {}", prettyPrint(entity));
+
+        responseHandler.reset();
+        final Map<String, String> queryParams = new HashMap<String, String>();
+        queryParams.put(SystemQueryOptionKind.EXPAND.toString(), TRIPS);
+
+        olingoApp.uread(edm, TEST_PEOPLE, queryParams, responseHandler);
+
+        rawEntity = responseHandler.await();
+        entity = reader.readEntity(rawEntity, TEST_FORMAT);
+        LOG.info("Single People Entiry with expanded Trips relation:  {}", prettyPrint(entity));
+    }
+
+    @Test
+    public void testReadUpdateProperties() throws Exception {
+        // test simple property Airports.Name
+        final TestOlingo4ResponseHandler<ClientPrimitiveValue> propertyHandler = new TestOlingo4ResponseHandler<ClientPrimitiveValue>();
+
+        olingoApp.read(edm, TEST_AIRPORTS_SIMPLE_PROPERTY, null, propertyHandler);
+
+        ClientPrimitiveValue name = (ClientPrimitiveValue)propertyHandler.await();
+        assertEquals("San Francisco International Airport", name.toString());
+        LOG.info("Airport name property value {}", name.asPrimitive().toString());
+
+        final TestOlingo4ResponseHandler<ClientPrimitiveValue> valueHandler = new TestOlingo4ResponseHandler<ClientPrimitiveValue>();
+
+        olingoApp.read(edm, TEST_AIRPORTS_SIMPLE_PROPERTY_VALUE, null, valueHandler);
+        ClientPrimitiveValue nameValue = valueHandler.await();
+        assertEquals("San Francisco International Airport", name.toString());
+        LOG.info("Airport name property value {}", nameValue.toString());
+
+        TestOlingo4ResponseHandler<HttpStatusCode> statusHandler = new TestOlingo4ResponseHandler<HttpStatusCode>();
+        // All properties updates (simple and complex) are performing through
+        // ClientEntity object
+        ClientEntity clientEntity = objFactory.newEntity(null);
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("MiddleName", objFactory.newPrimitiveValueBuilder().buildString("Middle")));
+        olingoApp.update(edm, TEST_PEOPLE, clientEntity, statusHandler);
+        HttpStatusCode statusCode = statusHandler.await();
+        assertEquals(HttpStatusCode.NO_CONTENT, statusCode);
+        LOG.info("Name property updated with status {}", statusCode.getStatusCode());
+
+        // Check for updated property by reading entire entity
+        final TestOlingo4ResponseHandler<ClientEntity> responseHandler = new TestOlingo4ResponseHandler<ClientEntity>();
+
+        olingoApp.read(edm, TEST_PEOPLE, null, responseHandler);
+        ClientEntity entity = responseHandler.await();
+        assertEquals("Middle", entity.getProperty("MiddleName").getValue().toString());
+        LOG.info("Updated Single Entity:  {}", prettyPrint(entity));
+    }
+
+    @Test
+    public void testReadCount() throws Exception {
+        final TestOlingo4ResponseHandler<Long> countHandler = new TestOlingo4ResponseHandler<Long>();
+
+        olingoApp.read(edm, PEOPLE + COUNT_OPTION, null, countHandler);
+        Long count = countHandler.await();
+        assertEquals(20, count.intValue());
+        LOG.info("People count: {}", count);
+    }
+
+    @Test
+    public void testCreateUpdateDeleteEntity() throws Exception {
+
+        // create an entity to update
+        final TestOlingo4ResponseHandler<ClientEntity> entryHandler = new TestOlingo4ResponseHandler<ClientEntity>();
+
+        olingoApp.create(edm, PEOPLE, createEntity(), entryHandler);
+
+        ClientEntity createdEntity = entryHandler.await();
+        LOG.info("Created Entity:  {}", prettyPrint(createdEntity));
+
+        final TestOlingo4ResponseHandler<HttpStatusCode> statusHandler = new TestOlingo4ResponseHandler<HttpStatusCode>();
+        ClientEntity updateEntity = createEntity();
+        updateEntity.getProperties().add(objFactory.newPrimitiveProperty("MiddleName", objFactory.newPrimitiveValueBuilder().buildString("Middle")));
+        olingoApp.update(edm, TEST_CREATE_PEOPLE, updateEntity, statusHandler);
+        statusHandler.await();
+
+        statusHandler.reset();
+        updateEntity = createEntity();
+        updateEntity.getProperties().add(objFactory.newPrimitiveProperty("MiddleName", objFactory.newPrimitiveValueBuilder().buildString("Middle Patched")));
+        olingoApp.patch(edm, TEST_CREATE_PEOPLE, updateEntity, statusHandler);
+        statusHandler.await();
+
+        entryHandler.reset();
+        olingoApp.read(edm, TEST_CREATE_PEOPLE, null, entryHandler);
+        ClientEntity updatedEntity = entryHandler.await();
+        LOG.info("Updated Entity successfully:  {}", prettyPrint(updatedEntity));
+
+        statusHandler.reset();
+        olingoApp.delete(TEST_CREATE_PEOPLE, statusHandler);
+        HttpStatusCode statusCode = statusHandler.await();
+        LOG.info("Deletion of Entity was successful:  {}: {}", statusCode.getStatusCode(), statusCode.getInfo());
+
+        try {
+            LOG.info("Verify Delete Entity");
+
+            entryHandler.reset();
+            olingoApp.read(edm, TEST_CREATE_PEOPLE, null, entryHandler);
+
+            entryHandler.await();
+            fail("Entity not deleted!");
+        } catch (Exception e) {
+            LOG.info("Deleted entity not found: {}", e.getMessage());
+        }
+    }
+
+    @Test
+    public void testBatchRequest() throws Exception {
+
+        final List<Olingo4BatchRequest> batchParts = new ArrayList<Olingo4BatchRequest>();
+
+        // 1. Edm query
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(Constants.METADATA).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 2. Query entity set
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 3. Read entity
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(TEST_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 4. Read with expand
+        final HashMap<String, String> queryParams = new HashMap<String, String>();
+        queryParams.put(SystemQueryOptionKind.EXPAND.toString(), TRIPS);
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(TEST_PEOPLE).queryParams(queryParams).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 5. Create entity
+        final ClientEntity clientEntity = createEntity();
+        batchParts.add(Olingo4BatchChangeRequest.resourcePath(PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).contentId(TEST_CREATE_RESOURCE_CONTENT_ID).operation(Operation.CREATE)
+            .body(clientEntity).build());
+
+        // 6. Update entity
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("MiddleName", objFactory.newPrimitiveValueBuilder().buildString("Lewis")));
+        batchParts.add(Olingo4BatchChangeRequest.resourcePath(TEST_CREATE_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).contentId(TEST_UPDATE_RESOURCE_CONTENT_ID)
+            .operation(Operation.UPDATE).body(clientEntity).build());
+
+        // 7. Delete entity
+        batchParts.add(Olingo4BatchChangeRequest.resourcePath(TEST_CREATE_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).operation(Operation.DELETE).build());
+
+        // 8. Read to verify entity delete
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(TEST_CREATE_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        final TestOlingo4ResponseHandler<List<Olingo4BatchResponse>> responseHandler = new TestOlingo4ResponseHandler<List<Olingo4BatchResponse>>();
+        olingoApp.batch(edm, batchParts, responseHandler);
+
+        final List<Olingo4BatchResponse> responseParts = responseHandler.await(15, TimeUnit.MINUTES);
+        assertEquals("Batch responses expected", 8, responseParts.size());
+
+        assertNotNull(responseParts.get(0).getBody());
+
+        final ClientEntitySet clientEntitySet = (ClientEntitySet)responseParts.get(1).getBody();
+        assertNotNull(clientEntitySet);
+        LOG.info("Batch entity set:  {}", prettyPrint(clientEntitySet));
+
+        ClientEntity returnClientEntity = (ClientEntity)responseParts.get(2).getBody();
+        assertNotNull(returnClientEntity);
+        LOG.info("Batch read entity:  {}", prettyPrint(returnClientEntity));
+
+        returnClientEntity = (ClientEntity)responseParts.get(3).getBody();
+        assertNotNull(returnClientEntity);
+        LOG.info("Batch read entity with expand:  {}", prettyPrint(returnClientEntity));
+
+        ClientEntity createdClientEntity = (ClientEntity)responseParts.get(4).getBody();
+        assertNotNull(createdClientEntity);
+        assertEquals(TEST_CREATE_RESOURCE_CONTENT_ID, responseParts.get(4).getContentId());
+        LOG.info("Batch created entity:  {}", prettyPrint(returnClientEntity));
+
+        assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), responseParts.get(5).getStatusCode());
+        assertEquals(TEST_UPDATE_RESOURCE_CONTENT_ID, responseParts.get(5).getContentId());
+        assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), responseParts.get(6).getStatusCode());
+        assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), responseParts.get(7).getStatusCode());
+    }
+
+    private ClientEntity createEntity() {
+        ClientEntity clientEntity = objFactory.newEntity(null);
+
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("UserName", objFactory.newPrimitiveValueBuilder().buildString("lewisblack")));
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("FirstName", objFactory.newPrimitiveValueBuilder().buildString("Lewis")));
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("LastName", objFactory.newPrimitiveValueBuilder().buildString("Black")));
+
+        return clientEntity;
+    }
+
+    private static String prettyPrint(ClientEntitySet entitySet) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[\n");
+        for (ClientEntity entity : entitySet.getEntities()) {
+            builder.append(prettyPrint(entity.getProperties(), 1)).append('\n');
+        }
+        builder.append("]\n");
+        return builder.toString();
+    }
+
+    private static String prettyPrint(ClientEntity entity) {
+        return prettyPrint(entity.getProperties(), 0);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static String prettyPrint(Map<String, Object> properties, int level) {
+        StringBuilder b = new StringBuilder();
+        Set<Entry<String, Object>> entries = properties.entrySet();
+
+        for (Entry<String, Object> entry : entries) {
+            intend(b, level);
+            b.append(entry.getKey()).append(": ");
+            Object value = entry.getValue();
+            if (value instanceof Map) {
+                value = prettyPrint((Map<String, Object>)value, level + 1);
+            } else if (value instanceof Calendar) {
+                Calendar cal = (Calendar)value;
+                value = SimpleDateFormat.getInstance().format(cal.getTime());
+            }
+            b.append(value).append("\n");
+        }
+        // remove last line break
+        b.deleteCharAt(b.length() - 1);
+        return b.toString();
+    }
+
+    private static String prettyPrint(Collection<ClientProperty> properties, int level) {
+        StringBuilder b = new StringBuilder();
+
+        for (Object property : properties) {
+            intend(b, level);
+            if (property instanceof ClientProperty) {
+                ClientProperty entry = (ClientProperty)property;
+                ClientValue value = entry.getValue();
+                if (value.isCollection()) {
+                    ClientCollectionValue cclvalue = value.asCollection();
+                    b.append(entry.getName()).append(": ");
+                    b.append(prettyPrint(cclvalue.asJavaCollection(), level + 1));
+                } else if (value.isComplex()) {
+                    ClientComplexValue cpxvalue = value.asComplex();
+                    b.append(prettyPrint(cpxvalue.asJavaMap(), level + 1));
+                } else if (value.isEnum()) {
+                    ClientEnumValue cnmvalue = value.asEnum();
+                    b.append(entry.getName()).append(": ");
+                    b.append(cnmvalue.getValue()).append("\n");
+                } else if (value.isPrimitive()) {
+                    b.append(entry.getName()).append(": ");
+                    b.append(entry.getValue()).append("\n");
+                }
+            } else {
+                b.append(property.toString()).append("\n");
+            }
+
+        }
+        return b.toString();
+    }
+
+    private static void intend(StringBuilder builder, int intendLevel) {
+        for (int i = 0; i < intendLevel; i++) {
+            builder.append("  ");
+        }
+    }
+
+    private static final class TestOlingo4ResponseHandler<T> implements Olingo4ResponseHandler<T> {
+        private T response;
+        private Exception error;
+        private CountDownLatch latch = new CountDownLatch(1);
+
+        @Override
+        public void onResponse(T response) {
+            this.response = response;
+            if (LOG.isDebugEnabled()) {
+                if (response instanceof ClientEntitySet) {
+                    LOG.debug("Received response: {}", prettyPrint((ClientEntitySet)response));
+                } else if (response instanceof ClientEntity) {
+                    LOG.debug("Received response: {}", prettyPrint((ClientEntity)response));
+                } else {
+                    LOG.debug("Received response: {}", response);
+                }
+            }
+            latch.countDown();
+        }
+
+        @Override
+        public void onException(Exception ex) {
+            error = ex;
+            latch.countDown();
+        }
+
+        @Override
+        public void onCanceled() {
+            error = new IllegalStateException("Request Canceled");
+            latch.countDown();
+        }
+
+        public T await() throws Exception {
+            return await(TIMEOUT, TimeUnit.SECONDS);
+        }
+
+        public T await(long timeout, TimeUnit unit) throws Exception {
+            assertTrue("Timeout waiting for response", latch.await(timeout, unit));
+            if (error != null) {
+                throw error;
+            }
+            assertNotNull("Response", response);
+            return response;
+        }
+
+        public void reset() {
+            latch.countDown();
+            latch = new CountDownLatch(1);
+            response = null;
+            error = null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/test/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/test/resources/log4j2.properties b/components/camel-olingo4/camel-olingo4-api/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..46bf0df
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-olingo4-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/pom.xml b/components/camel-olingo4/camel-olingo4-component/pom.xml
new file mode 100644
index 0000000..6c9c988
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/pom.xml
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-olingo4-parent</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>camel-olingo4</artifactId>
+  <name>Camel :: Olingo4 :: Component</name>
+  <description>Camel Olingo4 component</description>
+  <properties>
+    <componentName>Olingo4</componentName>
+    <schemeName>olingo4</schemeName>
+    <maven.exe.file.extension></maven.exe.file.extension>
+    <camel.osgi.export.pkg>${componentPackage}</camel.osgi.export.pkg>
+    <componentPackage>org.apache.camel.component.olingo4</componentPackage>
+    <outPackage>org.apache.camel.component.olingo4.internal</outPackage>
+    <camel.osgi.private.pkg>${outPackage}</camel.osgi.private.pkg>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-olingo4-api</artifactId>
+       <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-client-api</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-client-core</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-commons-api</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>${commons-lang-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>spi-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-olingo4-api</artifactId>
+      <classifier>javadoc</classifier>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <repositories>
+    <repository>
+      <id>redhat-ga-repository</id>
+      <url>https://maven.repository.redhat.com/ga</url>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <id>redhat-ga-repository</id>
+      <url>https://maven.repository.redhat.com/ga</url>
+    </pluginRepository>
+  </pluginRepositories>
+  <build>
+    <defaultGoal>install</defaultGoal>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.camel</groupId>
+          <artifactId>camel-api-component-maven-plugin</artifactId>
+          <configuration>
+            <scheme>${schemeName}</scheme>
+            <componentName>${componentName}</componentName>
+            <componentPackage>${componentPackage}</componentPackage>
+            <outPackage>${outPackage}</outPackage>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-api-component-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-test-component-classes</id>
+            <goals>
+              <goal>fromApis</goal>
+            </goals>
+            <configuration>
+              <apis>
+                <api>
+                  <apiName />
+                  <proxyClass>org.apache.camel.component.olingo4.api.Olingo4App</proxyClass>
+                  <fromSignatureFile>src/signatures/olingo-api-signature.txt</fromSignatureFile>
+                  <excludeConfigNames>edm|responseHandler</excludeConfigNames>
+                  <extraOptions>
+                    <extraOption>
+                      <name>keyPredicate</name>
+                      <type>java.lang.String</type>
+                    </extraOption>
+                  </extraOptions>
+                  <nullableOptions>
+                    <nullableOption>queryParams</nullableOption>
+                  </nullableOptions>
+                </api>
+              </apis>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-generated-sources</id>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources/camel-component</source>
+              </sources>
+            </configuration>
+          </execution>
+          <execution>
+            <id>add-generated-test-sources</id>
+            <goals>
+              <goal>add-test-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-test-sources/camel-component</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-api-component-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <scheme>${schemeName}</scheme>
+          <componentName>${componentName}</componentName>
+          <componentPackage>${componentPackage}</componentPackage>
+          <outPackage>${outPackage}</outPackage>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
new file mode 100644
index 0000000..e9cfb97
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
@@ -0,0 +1,252 @@
+## Olingo4 Component
+
+*Available as of Camel version 2.19.0*
+
+The Olingo2 component utilizes�http://olingo.apache.org/[Apache Olingo]
+version 2.0�APIs to interact with OData 2.0 and 3.0 compliant services.
+A number of popular commercial and enterprise vendors and products
+support the OData protocol. A sample list of supporting products can be
+found on the OData http://www.odata.org/ecosystem/[website].
+
+The Olingo2 component supports reading feeds, delta feeds, entities,
+simple and complex properties, links, counts, using custom and OData
+system query parameters. It supports updating entities, properties, and
+association links. It also supports submitting queries and change
+requests as a single OData batch operation.�
+
+The component supports configuring HTTP connection parameters and
+headers for OData service connection. This allows configuring�use of
+SSL, OAuth2.0, etc. as required by the target OData service.�
+
+Maven users will need to add the following dependency to their pom.xml
+for this component:
+
+[source,java]
+----------------------------------------------
+    <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-olingo2</artifactId>
+        <version>${camel-version}</version>
+    </dependency>
+----------------------------------------------
+
+### URI format
+
+[source,java]
+------------------------------------------------
+    olingo2://endpoint/<resource-path>?[options]
+------------------------------------------------
+
+### Olingo2 Options
+
+
+
+
+// component options: START
+The Olingo4 component supports 1 options which are listed below.
+
+
+
+{% raw %}
+[width="100%",cols="2,1,1m,1m,5",options="header"]
+|=======================================================================
+| Name | Group | Default | Java Type | Description
+| configuration | common |  | Olingo4Configuration | To use the shared configuration
+|=======================================================================
+{% endraw %}
+// component options: END
+
+
+
+
+
+
+// endpoint options: START
+The Olingo4 component supports 16 endpoint options which are listed below:
+
+{% raw %}
+[width="100%",cols="2,1,1m,1m,5",options="header"]
+|=======================================================================
+| Name | Group | Default | Java Type | Description
+| apiName | common |  | Olingo4ApiName | *Required* What kind of operation to perform
+| methodName | common |  | String | *Required* What sub operation to use for the selected operation
+| connectTimeout | common | 30000 | int | HTTP connection creation timeout in milliseconds defaults to 30000 (30 seconds)
+| contentType | common | application/json;charset=utf-8 | String | Content-Type header value can be used to specify JSON or XML message format defaults to application/json;charset=utf-8
+| httpAsyncClientBuilder | common |  | HttpAsyncClientBuilder | Custom HTTP async client builder for more complex HTTP client configuration overrides connectionTimeout socketTimeout proxy and sslContext. Note that a socketTimeout MUST be specified in the builder otherwise OData requests could block indefinitely
+| httpClientBuilder | common |  | HttpClientBuilder | Custom HTTP client builder for more complex HTTP client configuration overrides connectionTimeout socketTimeout proxy and sslContext. Note that a socketTimeout MUST be specified in the builder otherwise OData requests could block indefinitely
+| httpHeaders | common |  | Map | Custom HTTP headers to inject into every request this could include OAuth tokens etc.
+| inBody | common |  | String | Sets the name of a parameter to be passed in the exchange In Body
+| proxy | common |  | HttpHost | HTTP proxy server configuration
+| serviceUri | common |  | String | Target OData service base URI e.g. http://services.odata.org/OData/OData.svc
+| socketTimeout | common | 30000 | int | HTTP request timeout in milliseconds defaults to 30000 (30 seconds)
+| sslContextParameters | common |  | SSLContextParameters | To configure security using SSLContextParameters
+| bridgeErrorHandler | consumer | false | boolean | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored.
+| exceptionHandler | consumer (advanced) |  | ExceptionHandler | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN or ERROR level and ignored.
+| exchangePattern | consumer (advanced) |  | ExchangePattern | Sets the exchange pattern when the consumer creates an exchange.
+| synchronous | advanced | false | boolean | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported).
+|=======================================================================
+{% endraw %}
+// endpoint options: END
+
+
+### Producer Endpoints
+
+Producer endpoints can use endpoint names and options listed
+next.�Producer endpoints can also use a special option�*`inBody`*�that
+in turn should contain the name of the endpoint option whose value will
+be contained in the Camel Exchange In message. The *inBody*�option
+defaults to *data*�for endpoints that take that�option.�
+
+Any of the endpoint options can be provided in either the endpoint URI,
+or dynamically in a message header. The message header name must be of
+the format�*`CamelOlingo2.<option>`*. Note that the�*`inBody`*�option
+overrides message header, i.e. the endpoint
+option�*`inBody=option`*�would override
+a�*`CamelOlingo2.option`*�header. In addition, query parameters can be
+specified�
+
+Note that the resourcePath option can either in specified in the URI as
+a part of the URI path, as an endpoint option
+?resourcePath=<resource-path> or as a header value
+CamelOlingo2.resourcePath. The OData entity key predicate can either be
+a part of the resource path, e.g. _Manufacturers('1')_, where _'__1'_�is
+the key predicate, or be specified separately with resource path
+_Manufacturers_�and keyPredicate option _'1'_.�
+
+[width="100%",cols="10%,10%,10%,70%",options="header",]
+|=======================================================================
+|Endpoint |Options |HTTP Method |Result Body Type
+
+|batch |data |POST with multipart/mixed batch request |java.util.List<org.apache.camel.component.olingo2.api.batch.Olingo2BatchResponse>
+
+|create |data, resourcePath |POST |org.apache.olingo.odata2.api.ep.entry.ODataEntry for new entries
+org.apache.olingo.odata2.api.commons.HttpStatusCodes for other OData resources
+
+|delete |resourcePath |DELETE |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+
+|merge |data, resourcePath |MERGE |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+
+|patch |data, resourcePath |PATCH |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+
+|read |queryParams, resourcePath |GET |Depends on OData resource being queried as described next
+
+|update |data, resourcePath |PUT |org.apache.olingo.odata2.api.commons.HttpStatusCodes
+|=======================================================================
+
+### OData Resource Type Mapping
+
+The result of *read* endpoint and data type of *data* option depends on
+the OData resource being queried, created or modified.�
+
+[width="100%",cols="10%,10%,80%",options="header",]
+|=======================================================================
+|OData Resource Type |Resource URI from resourcePath and keyPredicate |In or Out Body Type
+
+|Entity data model |$metadata |org.apache.olingo.odata2.api.edm.Edm
+
+|Service document |/ |org.apache.olingo.odata2.api.servicedocument.ServiceDocument
+
+|OData feed |<entity-set> |org.apache.olingo.odata2.api.ep.feed.ODataFeed
+
+|OData entry |<entity-set>(<key-predicate>) |org.apache.olingo.odata2.api.ep.entry.ODataEntry for Out body (response)
+java.util.Map<String, Object> for In body (request)
+
+|Simple property |<entity-set>(<key-predicate>)/<simple-property> |Appropriate Java data type as described by Olingo EdmProperty
+
+|Simple property value |<entity-set>(<key-predicate>)/<simple-property>/$value |Appropriate Java data type as described by Olingo EdmProperty
+
+|Complex property |<entity-set>(<key-predicate>)/<complex-property> |java.util.Map<String, Object>
+
+|Zero or one association link |<entity-set>(<key-predicate>/$link/<one-to-one-entity-set-property> |String for response
+java.util.Map<String, Object> with key property names and values for request
+
+|Zero or many association links |<entity-set>(<key-predicate>/$link/<one-to-many-entity-set-property> |java.util.List<String> for response
+java.util.List<java.util.Map<String, Object>> containing list of key property names and values for request
+
+|Count |<resource-uri>/$count |java.lang.Long
+|=======================================================================
+
+### Consumer Endpoints
+
+Only the *read* endpoint can be used as a consumer endpoint. Consumer
+endpoints can
+use�http://camel.apache.org/polling-consumer.html#PollingConsumer-ScheduledPollConsumerOptions[Scheduled
+Poll Consumer Options]�with a�*`consumer.`*�prefix to schedule endpoint
+invocation. By default consumer endpoints that return an array or
+collection will generate one exchange per element, and their routes will
+be executed once for each exchange. This behavior can be disabled by
+setting the endpoint property *consumer.splitResult=false*.�
+
+### Message Headers
+
+Any URI option can be provided in a message header for producer
+endpoints with a�*`CamelOlingo2.`*�prefix.
+
+### Message Body
+
+All result message bodies utilize objects provided by the underlying
+http://olingo.apache.org/javadoc/odata2/index.html[Apache Olingo 2.0
+API] used by the Olingo2Component. Producer endpoints can specify the
+option name for incoming message body in the�*`inBody`*�endpoint URI
+parameter. For endpoints that return an array or collection, a consumer
+endpoint will map every element to distinct messages, unless
+*consumer.splitResult* is set to *false*.
+
+### Use cases
+
+The following route reads top 5 entries from the Manufacturer feed
+ordered by ascending Name property.�
+
+�
+
+[source,java]
+------------------------------------------------------------
+from("direct:...")
+    .setHeader("CamelOlingo2.$top", "5");
+    .to("olingo2://read/Manufacturers?orderBy=Name%20asc");
+------------------------------------------------------------
+
+�
+
+The following route reads Manufacturer entry using the key property
+value in incoming�*id* header.�
+
+�
+
+[source,java]
+------------------------------------------------------------
+from("direct:...")
+    .setHeader("CamelOlingo2.keyPredicate", header("id"))
+    .to("olingo2://read/Manufacturers");
+------------------------------------------------------------
+
+�
+
+The following route creates Manufacturer entry using the
+*java.util.Map<String, Object>* in body message.�
+
+�
+
+[source,java]
+------------------------------------------------------------
+from("direct:...")
+    .to("olingo2://create/Manufacturers");
+------------------------------------------------------------
+
+�
+
+The following route polls Manufacturer
+http://olingo.apache.org/doc/tutorials/deltaClient.html[delta
+feed]�every 30 seconds. The bean *blah*�updates the bean�*paramsBean*�to
+add an updated�*!deltatoken* property with the value returned in the
+*ODataDeltaFeed* result. Since the initial delta token is not known, the
+consumer endpoint will produce an�*ODataFeed* value the first time, and
+*ODataDeltaFeed* on subsequent polls.�
+
+�
+
+[source,java]
+---------------------------------------------------------------------------------------------------------
+from("olingo2://read/Manufacturers?queryParams=#paramsBean&consumer.timeUnit=SECONDS&consumer.delay=30")
+    .to("bean:blah");
+---------------------------------------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/META-INF/MANIFEST.MF b/components/camel-olingo4/camel-olingo4-component/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4AppWrapper.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4AppWrapper.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4AppWrapper.java
new file mode 100644
index 0000000..1ed09a1
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4AppWrapper.java
@@ -0,0 +1,108 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.olingo4.api.Olingo4App;
+import org.apache.camel.component.olingo4.api.Olingo4ResponseHandler;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.edm.Edm;
+
+/**
+ * Holder class for {@link org.apache.camel.component.olingo4.api.Olingo4App}
+ * and its lazily read {@link org.apache.olingo.commons.api.edm.Edm}.
+ */
+public class Olingo4AppWrapper {
+
+    private final Olingo4App olingo4App;
+    private volatile Edm edm;
+
+    public Olingo4AppWrapper(Olingo4App olingo4App) {
+        ObjectHelper.notNull(olingo4App, "olingo4App");
+        this.olingo4App = olingo4App;
+    }
+
+    public Olingo4App getOlingo4App() {
+        return olingo4App;
+    }
+
+    public void close() {
+        olingo4App.close();
+    }
+
+    // double checked locking based singleton Edm reader
+    public Edm getEdm() throws RuntimeCamelException {
+        Edm localEdm = edm;
+        if (localEdm == null) {
+
+            synchronized (this) {
+
+                localEdm = edm;
+                if (localEdm == null) {
+
+                    final CountDownLatch latch = new CountDownLatch(1);
+                    final Exception[] error = new Exception[1];
+                    olingo4App.read(null, Constants.METADATA, null, new Olingo4ResponseHandler<Edm>() {
+
+                        @Override
+                        public void onResponse(Edm response) {
+                            edm = response;
+                            latch.countDown();
+                        }
+
+                        @Override
+                        public void onException(Exception ex) {
+                            error[0] = ex;
+                            latch.countDown();
+                        }
+
+                        @Override
+                        public void onCanceled() {
+                            error[0] = new RuntimeCamelException("OData HTTP request cancelled!");
+                            latch.countDown();
+                        }
+                    });
+
+                    try {
+                        // wait until response or timeout
+                        latch.await();
+
+                        final Exception ex = error[0];
+                        if (ex != null) {
+                            if (ex instanceof RuntimeCamelException) {
+                                throw (RuntimeCamelException)ex;
+                            } else {
+                                final String message = ex.getMessage() != null ? ex.getMessage() : ex.getClass().getName();
+                                throw new RuntimeCamelException("Error reading EDM: " + message, ex);
+                            }
+                        }
+
+                    } catch (InterruptedException e) {
+                        throw new RuntimeCamelException(e.getMessage(), e);
+                    }
+
+                    localEdm = edm;
+                }
+            }
+        }
+
+        return localEdm;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Component.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Component.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Component.java
new file mode 100644
index 0000000..ee5fd2c
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Component.java
@@ -0,0 +1,184 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.olingo4.api.impl.Olingo4AppImpl;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiCollection;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiName;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.AbstractApiComponent;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.http.HttpHost;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+
+/**
+ * Represents the component that manages {@link Olingo4Endpoint}.
+ */
+public class Olingo4Component extends AbstractApiComponent<Olingo4ApiName, Olingo4Configuration, Olingo4ApiCollection> {
+
+    // component level shared proxy
+    private Olingo4AppWrapper apiProxy;
+
+    public Olingo4Component() {
+        super(Olingo4Endpoint.class, Olingo4ApiName.class, Olingo4ApiCollection.getCollection());
+    }
+
+    public Olingo4Component(CamelContext context) {
+        super(context, Olingo4Endpoint.class, Olingo4ApiName.class, Olingo4ApiCollection.getCollection());
+    }
+
+    @Override
+    protected Olingo4ApiName getApiName(String apiNameStr) throws IllegalArgumentException {
+        return Olingo4ApiName.fromValue(apiNameStr);
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        // parse remaining to extract resourcePath and queryParams
+        final String[] pathSegments = remaining.split("/", -1);
+        final String methodName = pathSegments[0];
+
+        if (pathSegments.length > 1) {
+            final StringBuilder resourcePath = new StringBuilder();
+            for (int i = 1; i < pathSegments.length; i++) {
+                resourcePath.append(pathSegments[i]);
+                if (i < (pathSegments.length - 1)) {
+                    resourcePath.append('/');
+                }
+            }
+            // This will override any URI supplied ?resourcePath=... param
+            parameters.put(Olingo4Endpoint.RESOURCE_PATH_PROPERTY, resourcePath.toString());
+        }
+
+        final Olingo4Configuration endpointConfiguration = createEndpointConfiguration(Olingo4ApiName.DEFAULT);
+        final Endpoint endpoint = createEndpoint(uri, methodName, Olingo4ApiName.DEFAULT, endpointConfiguration);
+
+        // set endpoint property inBody
+        setProperties(endpoint, parameters);
+
+        // configure endpoint properties and initialize state
+        endpoint.configureProperties(parameters);
+
+        return endpoint;
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String methodName, Olingo4ApiName apiName, Olingo4Configuration endpointConfiguration) {
+        endpointConfiguration.setApiName(apiName);
+        endpointConfiguration.setMethodName(methodName);
+        return new Olingo4Endpoint(uri, this, apiName, methodName, endpointConfiguration);
+    }
+
+    /**
+     * To use the shared configuration
+     */
+    @Override
+    public void setConfiguration(Olingo4Configuration configuration) {
+        super.setConfiguration(configuration);
+    }
+
+    /**
+     * To use the shared configuration
+     */
+    @Override
+    public Olingo4Configuration getConfiguration() {
+        return super.getConfiguration();
+    }
+
+    public Olingo4AppWrapper createApiProxy(Olingo4Configuration endpointConfiguration) {
+        final Olingo4AppWrapper result;
+        if (endpointConfiguration.equals(this.configuration)) {
+            synchronized (this) {
+                if (apiProxy == null) {
+                    apiProxy = createOlingo4App(this.configuration);
+                }
+            }
+            result = apiProxy;
+        } else {
+            result = createOlingo4App(endpointConfiguration);
+        }
+        return result;
+    }
+
+    private Olingo4AppWrapper createOlingo4App(Olingo4Configuration configuration) {
+
+        Object clientBuilder = configuration.getHttpAsyncClientBuilder();
+        if (clientBuilder == null) {
+            HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
+
+            // apply simple configuration properties
+            final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
+            requestConfigBuilder.setConnectTimeout(configuration.getConnectTimeout());
+            requestConfigBuilder.setSocketTimeout(configuration.getSocketTimeout());
+
+            final HttpHost proxy = configuration.getProxy();
+            if (proxy != null) {
+                requestConfigBuilder.setProxy(proxy);
+            }
+
+            // set default request config
+            asyncClientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
+
+            SSLContextParameters sslContextParameters = configuration.getSslContextParameters();
+            if (sslContextParameters == null) {
+                // use defaults if not specified
+                sslContextParameters = new SSLContextParameters();
+            }
+            try {
+                asyncClientBuilder.setSSLContext(sslContextParameters.createSSLContext(getCamelContext()));
+            } catch (GeneralSecurityException e) {
+                throw ObjectHelper.wrapRuntimeCamelException(e);
+            } catch (IOException e) {
+                throw ObjectHelper.wrapRuntimeCamelException(e);
+            }
+        }
+
+        Olingo4AppImpl olingo4App;
+        if (clientBuilder == null || clientBuilder instanceof HttpAsyncClientBuilder) {
+            olingo4App = new Olingo4AppImpl(configuration.getServiceUri(), (HttpAsyncClientBuilder)clientBuilder);
+        } else {
+            olingo4App = new Olingo4AppImpl(configuration.getServiceUri(), (HttpClientBuilder)clientBuilder);
+        }
+        apiProxy = new Olingo4AppWrapper(olingo4App);
+        apiProxy.getOlingo4App().setContentType(configuration.getContentType());
+        apiProxy.getOlingo4App().setHttpHeaders(configuration.getHttpHeaders());
+
+        return apiProxy;
+    }
+
+    public void closeApiProxy(Olingo4AppWrapper apiProxy) {
+        if (this.apiProxy != apiProxy) {
+            // not a shared proxy
+            apiProxy.close();
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (apiProxy != null) {
+            apiProxy.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Configuration.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Configuration.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Configuration.java
new file mode 100644
index 0000000..68672ba
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Configuration.java
@@ -0,0 +1,221 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.util.Map;
+
+import org.apache.camel.component.olingo4.internal.Olingo4ApiName;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.http.HttpHost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+
+/**
+ * Component configuration for Olingo4 component.
+ */
+@UriParams
+public class Olingo4Configuration {
+
+    private static final String DEFAULT_CONTENT_TYPE = ContentType.APPLICATION_JSON.toString();
+    private static final int DEFAULT_TIMEOUT = 30 * 1000;
+
+    @UriPath
+    @Metadata(required = "true")
+    private Olingo4ApiName apiName;
+    @UriPath @Metadata(required = "true")
+    private String methodName;
+    @UriParam
+    private String serviceUri;
+    @UriParam(defaultValue = "application/json;charset=utf-8")
+    private String contentType = DEFAULT_CONTENT_TYPE;
+    @UriParam
+    private Map<String, String> httpHeaders;
+    @UriParam(defaultValue = "" + DEFAULT_TIMEOUT)
+    private int connectTimeout = DEFAULT_TIMEOUT;
+    @UriParam(defaultValue = "" + DEFAULT_TIMEOUT)
+    private int socketTimeout = DEFAULT_TIMEOUT;
+    @UriParam
+    private HttpHost proxy;
+    @UriParam
+    private SSLContextParameters sslContextParameters;
+    @UriParam
+    private HttpAsyncClientBuilder httpAsyncClientBuilder;
+    @UriParam
+    private HttpClientBuilder httpClientBuilder;
+
+    public Olingo4ApiName getApiName() {
+        return apiName;
+    }
+
+    /**
+     * What kind of operation to perform
+     */
+    public void setApiName(Olingo4ApiName apiName) {
+        this.apiName = apiName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * What sub operation to use for the selected operation
+     */
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public String getServiceUri() {
+        return serviceUri;
+    }
+
+    /**
+     * Target OData service base URI, e.g. http://services.odata.org/OData/OData.svc
+     */
+    public void setServiceUri(String serviceUri) {
+        this.serviceUri = serviceUri;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    /**
+     * Content-Type header value can be used to specify JSON or XML message format, defaults to application/json;charset=utf-8
+     */
+    public void setContentType(String contentType) {
+        this.contentType = contentType;
+    }
+
+    public Map<String, String> getHttpHeaders() {
+        return httpHeaders;
+    }
+
+    /**
+     * Custom HTTP headers to inject into every request, this could include OAuth tokens, etc.
+     */
+    public void setHttpHeaders(Map<String, String> httpHeaders) {
+        this.httpHeaders = httpHeaders;
+    }
+
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    /**
+     * HTTP connection creation timeout in milliseconds, defaults to 30,000 (30 seconds)
+     */
+    public void setConnectTimeout(int connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public int getSocketTimeout() {
+        return socketTimeout;
+    }
+
+    /**
+     * HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds)
+     */
+    public void setSocketTimeout(int socketTimeout) {
+        this.socketTimeout = socketTimeout;
+    }
+
+    public HttpHost getProxy() {
+        return proxy;
+    }
+
+    /**
+     * HTTP proxy server configuration
+     */
+    public void setProxy(HttpHost proxy) {
+        this.proxy = proxy;
+    }
+
+    public SSLContextParameters getSslContextParameters() {
+        return sslContextParameters;
+    }
+
+    /**
+     * To configure security using SSLContextParameters
+     */
+    public void setSslContextParameters(SSLContextParameters sslContextParameters) {
+        this.sslContextParameters = sslContextParameters;
+    }
+
+    public HttpAsyncClientBuilder getHttpAsyncClientBuilder() {
+        return httpAsyncClientBuilder;
+    }
+
+    /**
+     * Custom HTTP async client builder for more complex HTTP client configuration, overrides connectionTimeout, socketTimeout, proxy and sslContext.
+     * Note that a socketTimeout MUST be specified in the builder, otherwise OData requests could block indefinitely
+     */
+    public void setHttpAsyncClientBuilder(HttpAsyncClientBuilder httpAsyncClientBuilder) {
+        this.httpAsyncClientBuilder = httpAsyncClientBuilder;
+    }
+
+    public HttpClientBuilder getHttpClientBuilder() {
+        return httpClientBuilder;
+    }
+
+    /**
+     * Custom HTTP client builder for more complex HTTP client configuration, overrides connectionTimeout, socketTimeout, proxy and sslContext.
+     * Note that a socketTimeout MUST be specified in the builder, otherwise OData requests could block indefinitely
+     */
+    public void setHttpClientBuilder(HttpClientBuilder httpClientBuilder) {
+        this.httpClientBuilder = httpClientBuilder;
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder()
+            .append(serviceUri)
+            .append(contentType)
+            .append(httpHeaders)
+            .append(connectTimeout)
+            .append(socketTimeout)
+            .append(proxy)
+            .append(sslContextParameters)
+            .append(httpAsyncClientBuilder)
+            .append(httpClientBuilder)
+            .hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Olingo4Configuration) {
+            Olingo4Configuration other = (Olingo4Configuration) obj;
+            return serviceUri == null ? other.serviceUri == null : serviceUri.equals(other.serviceUri)
+                && contentType == null ? other.contentType == null : contentType.equals(other.contentType)
+                && httpHeaders == null ? other.httpHeaders == null : httpHeaders.equals(other.httpHeaders)
+                && connectTimeout == other.connectTimeout
+                && socketTimeout == other.socketTimeout
+                && proxy == null ? other.proxy == null : proxy.equals(other.proxy)
+                && sslContextParameters == null ? other.sslContextParameters == null : sslContextParameters.equals(other.sslContextParameters)
+                && httpAsyncClientBuilder == null ? other.httpAsyncClientBuilder == null
+                : httpAsyncClientBuilder.equals(other.httpAsyncClientBuilder)
+                && httpClientBuilder == null ? other.httpClientBuilder == null : httpClientBuilder.equals(other.httpClientBuilder);
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Consumer.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Consumer.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Consumer.java
new file mode 100644
index 0000000..02465c5
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Consumer.java
@@ -0,0 +1,92 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.olingo4.api.Olingo4ResponseHandler;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiName;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.AbstractApiConsumer;
+import org.apache.camel.util.component.ApiConsumerHelper;
+
+/**
+ * The Olingo4 consumer.
+ */
+public class Olingo4Consumer extends AbstractApiConsumer<Olingo4ApiName, Olingo4Configuration> {
+
+    public Olingo4Consumer(Olingo4Endpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+
+    @Override
+    protected int poll() throws Exception {
+        // invoke the consumer method
+        final Map<String, Object> args = new HashMap<String, Object>();
+        args.putAll(endpoint.getEndpointProperties());
+
+        // let the endpoint and the Consumer intercept properties
+        endpoint.interceptProperties(args);
+        interceptProperties(args);
+
+        try {
+            // create responseHandler
+            final CountDownLatch latch = new CountDownLatch(1);
+            final Object[] result = new Object[1];
+            final Exception[] error = new Exception[1];
+
+            args.put(Olingo4Endpoint.RESPONSE_HANDLER_PROPERTY, new Olingo4ResponseHandler<Object>() {
+                @Override
+                public void onResponse(Object response) {
+                    result[0] = response;
+                    latch.countDown();
+                }
+
+                @Override
+                public void onException(Exception ex) {
+                    error[0] = ex;
+                    latch.countDown();
+                }
+
+                @Override
+                public void onCanceled() {
+                    error[0] = new RuntimeCamelException("OData HTTP Request cancelled");
+                    latch.countDown();
+                }
+            });
+
+            doInvokeMethod(args);
+
+            // guaranteed to return, since an exception on timeout is
+            // expected!!!
+            latch.await();
+
+            if (error[0] != null) {
+                throw error[0];
+            }
+
+            return ApiConsumerHelper.getResultsProcessed(this, result[0], isSplitResult());
+
+        } catch (Throwable t) {
+            throw ObjectHelper.wrapRuntimeCamelException(t);
+        }
+    }
+}


[6/6] camel git commit: Build new Camel Olingo4 component

Posted by ac...@apache.org.
Build new Camel Olingo4 component


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/ea11a624
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/ea11a624
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/ea11a624

Branch: refs/heads/master
Commit: ea11a62418d0d9e86daa41bf4d43119f755b6135
Parents: 71c8bdd
Author: Andrea Cosentino <an...@gmail.com>
Authored: Fri Mar 24 09:58:05 2017 +0100
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Fri Mar 24 09:58:05 2017 +0100

----------------------------------------------------------------------
 .../src/main/docs/olingo4-component.adoc        | 66 +++++++++++---------
 .../Olingo4ComponentConfiguration.java          | 19 +++++-
 2 files changed, 55 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/ea11a624/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
index cab1e53..980372c 100644
--- a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
@@ -1,6 +1,6 @@
 ## Olingo4 Component
 
-*Available as of Camel version 2.19.0*
+*Available as of Camel version 2.19*
 
 The Olingo4 component utilizes�http://olingo.apache.org/[Apache Olingo]
 version 4.0�APIs to interact with OData 4.0 compliant service.
@@ -43,17 +43,16 @@ for this component:
 
 
 // component options: START
-The Olingo4 component supports 1 options which are listed below.
+The Olingo4 component supports 2 options which are listed below.
 
 
 
-{% raw %}
-[width="100%",cols="2,1,1m,1m,5",options="header"]
+[width="100%",cols="2,5,^1,2",options="header"]
 |=======================================================================
-| Name | Group | Default | Java Type | Description
-| configuration | common |  | Olingo4Configuration | To use the shared configuration
+| Name | Description | Default | Type
+| **configuration** (common) | To use the shared configuration |  | Olingo4Configuration
+| **resolveProperty Placeholders** (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
 |=======================================================================
-{% endraw %}
 // component options: END
 
 
@@ -62,30 +61,41 @@ The Olingo4 component supports 1 options which are listed below.
 
 
 // endpoint options: START
-The Olingo4 component supports 16 endpoint options which are listed below:
+The Olingo4 endpoint is configured using URI syntax:
 
-{% raw %}
-[width="100%",cols="2,1,1m,1m,5",options="header"]
+    olingo4:apiName/methodName
+
+with the following path and query parameters:
+
+#### Path Parameters (2 parameters):
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **apiName** | *Required* What kind of operation to perform |  | Olingo4ApiName
+| **methodName** | *Required* What sub operation to use for the selected operation |  | String
+|=======================================================================
+
+#### Query Parameters (14 parameters):
+
+[width="100%",cols="2,5,^1,2",options="header"]
 |=======================================================================
-| Name | Group | Default | Java Type | Description
-| apiName | common |  | Olingo4ApiName | *Required* What kind of operation to perform
-| methodName | common |  | String | *Required* What sub operation to use for the selected operation
-| connectTimeout | common | 30000 | int | HTTP connection creation timeout in milliseconds defaults to 30000 (30 seconds)
-| contentType | common | application/json;charset=utf-8 | String | Content-Type header value can be used to specify JSON or XML message format defaults to application/json;charset=utf-8
-| httpAsyncClientBuilder | common |  | HttpAsyncClientBuilder | Custom HTTP async client builder for more complex HTTP client configuration overrides connectionTimeout socketTimeout proxy and sslContext. Note that a socketTimeout MUST be specified in the builder otherwise OData requests could block indefinitely
-| httpClientBuilder | common |  | HttpClientBuilder | Custom HTTP client builder for more complex HTTP client configuration overrides connectionTimeout socketTimeout proxy and sslContext. Note that a socketTimeout MUST be specified in the builder otherwise OData requests could block indefinitely
-| httpHeaders | common |  | Map | Custom HTTP headers to inject into every request this could include OAuth tokens etc.
-| inBody | common |  | String | Sets the name of a parameter to be passed in the exchange In Body
-| proxy | common |  | HttpHost | HTTP proxy server configuration
-| serviceUri | common |  | String | Target OData service base URI e.g. http://services.odata.org/TripPinRESTierService/
-| socketTimeout | common | 30000 | int | HTTP request timeout in milliseconds defaults to 30000 (30 seconds)
-| sslContextParameters | common |  | SSLContextParameters | To configure security using SSLContextParameters
-| bridgeErrorHandler | consumer | false | boolean | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored.
-| exceptionHandler | consumer (advanced) |  | ExceptionHandler | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN or ERROR level and ignored.
-| exchangePattern | consumer (advanced) |  | ExchangePattern | Sets the exchange pattern when the consumer creates an exchange.
-| synchronous | advanced | false | boolean | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported).
+| Name | Description | Default | Type
+| **connectTimeout** (common) | HTTP connection creation timeout in milliseconds defaults to 30000 (30 seconds) | 30000 | int
+| **contentType** (common) | Content-Type header value can be used to specify JSON or XML message format defaults to application/json;charset=utf-8 | application/json;charset=utf-8 | String
+| **httpAsyncClientBuilder** (common) | Custom HTTP async client builder for more complex HTTP client configuration overrides connectionTimeout socketTimeout proxy and sslContext. Note that a socketTimeout MUST be specified in the builder otherwise OData requests could block indefinitely |  | HttpAsyncClientBuilder
+| **httpClientBuilder** (common) | Custom HTTP client builder for more complex HTTP client configuration overrides connectionTimeout socketTimeout proxy and sslContext. Note that a socketTimeout MUST be specified in the builder otherwise OData requests could block indefinitely |  | HttpClientBuilder
+| **httpHeaders** (common) | Custom HTTP headers to inject into every request this could include OAuth tokens etc. |  | Map
+| **inBody** (common) | Sets the name of a parameter to be passed in the exchange In Body |  | String
+| **proxy** (common) | HTTP proxy server configuration |  | HttpHost
+| **serviceUri** (common) | Target OData service base URI e.g. http://services.odata.org/OData/OData.svc |  | String
+| **socketTimeout** (common) | HTTP request timeout in milliseconds defaults to 30000 (30 seconds) | 30000 | int
+| **sslContextParameters** (common) | To configure security using SSLContextParameters |  | SSLContextParameters
+| **bridgeErrorHandler** (consumer) | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored. | false | boolean
+| **exceptionHandler** (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| **exchangePattern** (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
+| **synchronous** (advanced) | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported). | false | boolean
 |=======================================================================
-{% endraw %}
 // endpoint options: END
 
 

http://git-wip-us.apache.org/repos/asf/camel/blob/ea11a624/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
index 35da6ed..ef18577 100644
--- a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
@@ -37,6 +37,12 @@ public class Olingo4ComponentConfiguration {
      * To use the shared configuration
      */
     private Olingo4ConfigurationNestedConfiguration configuration;
+    /**
+     * Whether the component should resolve property placeholders on itself when
+     * starting. Only properties which are of String type can use property
+     * placeholders.
+     */
+    private Boolean resolvePropertyPlaceholders = true;
 
     public Olingo4ConfigurationNestedConfiguration getConfiguration() {
         return configuration;
@@ -47,6 +53,15 @@ public class Olingo4ComponentConfiguration {
         this.configuration = configuration;
     }
 
+    public Boolean getResolvePropertyPlaceholders() {
+        return resolvePropertyPlaceholders;
+    }
+
+    public void setResolvePropertyPlaceholders(
+            Boolean resolvePropertyPlaceholders) {
+        this.resolvePropertyPlaceholders = resolvePropertyPlaceholders;
+    }
+
     public static class Olingo4ConfigurationNestedConfiguration {
         public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.olingo4.Olingo4Configuration.class;
         /**
@@ -76,11 +91,11 @@ public class Olingo4ComponentConfiguration {
          * HTTP connection creation timeout in milliseconds, defaults to 30,000
          * (30 seconds)
          */
-        private Integer connectTimeout;
+        private Integer connectTimeout = 30000;
         /**
          * HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds)
          */
-        private Integer socketTimeout;
+        private Integer socketTimeout = 30000;
         /**
          * HTTP proxy server configuration
          */


[2/6] camel git commit: CAMEL-11056: Create new camel-olingo4 component for supporting OData 4.0

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/NOTICE.txt b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 0000000..97f7472
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,10 @@
+{
+  "properties": [
+    {
+      "defaultValue": true,
+      "name": "camel.component.olingo4.enabled",
+      "description": "Enable olingo4 component",
+      "type": "java.lang.Boolean"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.factories
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.factories b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..536ce17
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.camel.component.olingo4.springboot.Olingo4ComponentAutoConfiguration

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.provides
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.provides b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.provides
new file mode 100644
index 0000000..e2dd530
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/spring.provides
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+provides: camel-olingo4
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/pom.xml b/platforms/spring-boot/components-starter/pom.xml
index 11ea61d..a7dd309 100644
--- a/platforms/spring-boot/components-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/pom.xml
@@ -223,6 +223,7 @@
     <module>camel-netty4-starter</module>
     <module>camel-ognl-starter</module>
     <module>camel-olingo2-starter</module>
+    <module>camel-olingo4-starter</module>
     <module>camel-openshift-starter</module>
     <module>camel-openstack-starter</module>
     <module>camel-opentracing-starter</module>


[3/6] camel git commit: CAMEL-11056: Create new camel-olingo4 component for supporting OData 4.0

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Endpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Endpoint.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Endpoint.java
new file mode 100644
index 0000000..482f733
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Endpoint.java
@@ -0,0 +1,222 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiCollection;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiName;
+import org.apache.camel.component.olingo4.internal.Olingo4Constants;
+import org.apache.camel.component.olingo4.internal.Olingo4PropertiesHelper;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.util.component.AbstractApiEndpoint;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+/**
+ * Communicates with OData 4.0 services using Apache Olingo OData API.
+ */
+@UriEndpoint(firstVersion = "2.19.0", scheme = "olingo4", title = "Olingo4", syntax = "olingo4:apiName/methodName", consumerClass = Olingo4Consumer.class, label = "cloud")
+public class Olingo4Endpoint extends AbstractApiEndpoint<Olingo4ApiName, Olingo4Configuration> {
+
+    protected static final String RESOURCE_PATH_PROPERTY = "resourcePath";
+    protected static final String RESPONSE_HANDLER_PROPERTY = "responseHandler";
+
+    private static final String KEY_PREDICATE_PROPERTY = "keyPredicate";
+    private static final String QUERY_PARAMS_PROPERTY = "queryParams";
+
+    private static final String READ_METHOD = "read";
+    private static final String EDM_PROPERTY = "edm";
+    private static final String DATA_PROPERTY = "data";
+    private static final String DELETE_METHOD = "delete";
+
+    // unparsed variants
+    private static final String UREAD_METHOD = "uread";
+
+    private final Set<String> endpointPropertyNames;
+
+    @UriParam
+    private Olingo4Configuration configuration;
+
+    private Olingo4AppWrapper apiProxy;
+
+    public Olingo4Endpoint(String uri, Olingo4Component component, Olingo4ApiName apiName, String methodName, Olingo4Configuration endpointConfiguration) {
+        super(uri, component, apiName, methodName, Olingo4ApiCollection.getCollection().getHelper(apiName), endpointConfiguration);
+
+        this.configuration = endpointConfiguration;
+
+        // get all endpoint property names
+        endpointPropertyNames = new HashSet<String>(getPropertiesHelper().getValidEndpointProperties(configuration));
+        // avoid adding edm as queryParam
+        endpointPropertyNames.add(EDM_PROPERTY);
+    }
+
+    public Producer createProducer() throws Exception {
+        return new Olingo4Producer(this);
+    }
+
+    public Consumer createConsumer(Processor processor) throws Exception {
+        // make sure inBody is not set for consumers
+        if (inBody != null) {
+            throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint");
+        }
+        // only read method is supported
+        if (!READ_METHOD.equals(methodName) && !UREAD_METHOD.equals(methodName)) {
+            throw new IllegalArgumentException("Only read method is supported for consumer endpoints");
+        }
+        final Olingo4Consumer consumer = new Olingo4Consumer(this, processor);
+        // also set consumer.* properties
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    @Override
+    protected ApiMethodPropertiesHelper<Olingo4Configuration> getPropertiesHelper() {
+        return Olingo4PropertiesHelper.getHelper();
+    }
+
+    protected String getThreadProfileName() {
+        return Olingo4Constants.THREAD_PROFILE_NAME;
+    }
+
+    @Override
+    public void configureProperties(Map<String, Object> options) {
+        // handle individual query params
+        parseQueryParams(options);
+
+        super.configureProperties(options);
+    }
+
+    @Override
+    protected void afterConfigureProperties() {
+        // set default inBody
+        if (!(READ_METHOD.equals(methodName) || DELETE_METHOD.equals(methodName) || UREAD_METHOD.equals(methodName)) && inBody == null) {
+            inBody = DATA_PROPERTY;
+        }
+        createProxy();
+    }
+
+    @Override
+    public synchronized Object getApiProxy(ApiMethod method, Map<String, Object> args) {
+        return apiProxy.getOlingo4App();
+    }
+
+    @Override
+    public Olingo4Component getComponent() {
+        return (Olingo4Component)super.getComponent();
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        if (apiProxy == null) {
+            createProxy();
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (apiProxy != null) {
+            // close the apiProxy
+            getComponent().closeApiProxy(apiProxy);
+            apiProxy = null;
+        }
+    }
+
+    @Override
+    public void interceptPropertyNames(Set<String> propertyNames) {
+        // add edm, and responseHandler property names
+        // edm is computed on first call to getApiProxy(), and responseHandler
+        // is provided by consumer and producer
+        if (!DELETE_METHOD.equals(methodName)) {
+            propertyNames.add(EDM_PROPERTY);
+        }
+        propertyNames.add(RESPONSE_HANDLER_PROPERTY);
+    }
+
+    @Override
+    public void interceptProperties(Map<String, Object> properties) {
+
+        // read Edm if not set yet
+        properties.put(EDM_PROPERTY, apiProxy.getEdm());
+
+        // handle keyPredicate
+        final String keyPredicate = (String)properties.get(KEY_PREDICATE_PROPERTY);
+        if (keyPredicate != null) {
+
+            // make sure a resource path is provided
+            final String resourcePath = (String)properties.get(RESOURCE_PATH_PROPERTY);
+            if (resourcePath == null) {
+                throw new IllegalArgumentException("Resource path must be provided in endpoint URI, or URI parameter '" + RESOURCE_PATH_PROPERTY + "', or exchange header '"
+                                                   + Olingo4Constants.PROPERTY_PREFIX + RESOURCE_PATH_PROPERTY + "'");
+            }
+
+            // append keyPredicate to dynamically create resource path
+            properties.put(RESOURCE_PATH_PROPERTY, resourcePath + '(' + keyPredicate + ')');
+        }
+
+        // handle individual queryParams
+        parseQueryParams(properties);
+    }
+
+    private void createProxy() {
+        apiProxy = getComponent().createApiProxy(getConfiguration());
+    }
+
+    private void parseQueryParams(Map<String, Object> options) {
+        // extract non-endpoint properties as query params
+        final Map<String, String> queryParams = new HashMap<String, String>();
+        for (Iterator<Map.Entry<String, Object>> it = options.entrySet().iterator(); it.hasNext();) {
+
+            final Map.Entry<String, Object> entry = it.next();
+            final String paramName = entry.getKey();
+
+            if (!endpointPropertyNames.contains(paramName)) {
+
+                // add to query params
+                final Object value = entry.getValue();
+                if (value == null) {
+                    throw new IllegalArgumentException("Null value for query parameter " + paramName);
+                }
+                queryParams.put(paramName, value.toString());
+
+                // remove entry from supplied options
+                it.remove();
+            }
+        }
+        if (!queryParams.isEmpty()) {
+
+            @SuppressWarnings("unchecked")
+            final Map<String, String> oldParams = (Map<String, String>)options.get(QUERY_PARAMS_PROPERTY);
+            if (oldParams == null) {
+                // set queryParams property
+                options.put(QUERY_PARAMS_PROPERTY, queryParams);
+            } else {
+                // overwrite old params in supplied map
+                oldParams.putAll(queryParams);
+            }
+
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Producer.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Producer.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Producer.java
new file mode 100644
index 0000000..da09d79
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Producer.java
@@ -0,0 +1,106 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.olingo4.api.Olingo4ResponseHandler;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiName;
+import org.apache.camel.component.olingo4.internal.Olingo4PropertiesHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.AbstractApiProducer;
+import org.apache.camel.util.component.ApiMethod;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Olingo4 producer.
+ */
+public class Olingo4Producer extends AbstractApiProducer<Olingo4ApiName, Olingo4Configuration> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Olingo4Producer.class);
+
+    public Olingo4Producer(Olingo4Endpoint endpoint) {
+        super(endpoint, Olingo4PropertiesHelper.getHelper());
+    }
+
+    @Override
+    public boolean process(final Exchange exchange, final AsyncCallback callback) {
+        // properties for method arguments
+        final Map<String, Object> properties = new HashMap<String, Object>();
+        properties.putAll(endpoint.getEndpointProperties());
+        propertiesHelper.getExchangeProperties(exchange, properties);
+
+        // let the endpoint and the Producer intercept properties
+        endpoint.interceptProperties(properties);
+        interceptProperties(properties);
+
+        // create response handler
+        properties.put(Olingo4Endpoint.RESPONSE_HANDLER_PROPERTY, new Olingo4ResponseHandler<Object>() {
+            @Override
+            public void onResponse(Object response) {
+                // producer returns a single response, even for methods with
+                // List return types
+                exchange.getOut().setBody(response);
+                // copy headers
+                exchange.getOut().setHeaders(exchange.getIn().getHeaders());
+
+                interceptResult(response, exchange);
+
+                callback.done(false);
+            }
+
+            @Override
+            public void onException(Exception ex) {
+                exchange.setException(ex);
+                callback.done(false);
+            }
+
+            @Override
+            public void onCanceled() {
+                exchange.setException(new RuntimeCamelException("OData HTTP Request cancelled!"));
+                callback.done(false);
+            }
+        });
+
+        // decide which method to invoke
+        final ApiMethod method = findMethod(exchange, properties);
+        if (method == null) {
+            // synchronous failure
+            callback.done(true);
+            return true;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Invoking operation {} with {}", method.getName(), properties.keySet());
+        }
+
+        try {
+            doInvokeMethod(method, properties);
+        } catch (Throwable t) {
+            exchange.setException(ObjectHelper.wrapRuntimeCamelException(t));
+            callback.done(true);
+            return true;
+        }
+        return false;
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4Constants.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4Constants.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4Constants.java
new file mode 100644
index 0000000..2261771
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4Constants.java
@@ -0,0 +1,29 @@
+/**
+ * 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.camel.component.olingo4.internal;
+
+/**
+ * Constants for Olingo4 component.
+ */
+public interface Olingo4Constants {
+
+    // prefix for parameters when passed as exchange header properties
+    String PROPERTY_PREFIX = "CamelOlingo4.";
+
+    // thread profile name for this component
+    String THREAD_PROFILE_NAME = "CamelOlingo4";
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4PropertiesHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4PropertiesHelper.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4PropertiesHelper.java
new file mode 100644
index 0000000..4c5b619
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/internal/Olingo4PropertiesHelper.java
@@ -0,0 +1,39 @@
+/**
+ * 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.camel.component.olingo4.internal;
+
+import org.apache.camel.component.olingo4.Olingo4Configuration;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+/**
+ * Singleton {@link ApiMethodPropertiesHelper} for Olingo4 component.
+ */
+public final class Olingo4PropertiesHelper extends ApiMethodPropertiesHelper<Olingo4Configuration> {
+
+    private static Olingo4PropertiesHelper helper;
+
+    private Olingo4PropertiesHelper() {
+        super(Olingo4Configuration.class, Olingo4Constants.PROPERTY_PREFIX);
+    }
+
+    public static synchronized Olingo4PropertiesHelper getHelper() {
+        if (helper == null) {
+            helper = new Olingo4PropertiesHelper();
+        }
+        return helper;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/LICENSE.txt b/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/NOTICE.txt b/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/services/org/apache/camel/component/olingo4
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/services/org/apache/camel/component/olingo4 b/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/services/org/apache/camel/component/olingo4
new file mode 100644
index 0000000..ed49a08
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/resources/META-INF/services/org/apache/camel/component/olingo4
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.olingo4.Olingo4Component

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/signatures/olingo-api-signature.txt
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..27257f7
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/signatures/olingo-api-signature.txt
@@ -0,0 +1,8 @@
+void read(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, java.util.Map<String, String> queryParams, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void uread(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, java.util.Map<String, String> queryParams, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void delete(String resourcePath, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void create(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void update(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void patch(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void merge(org.apache.olingo.commons.api.edm.Edm edm, String resourcePath, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);
+void batch(org.apache.olingo.commons.api.edm.Edm edm, Object data, org.apache.camel.component.olingo4.api.Olingo4ResponseHandler responseHandler);

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/AbstractOlingo4TestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/AbstractOlingo4TestSupport.java b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/AbstractOlingo4TestSupport.java
new file mode 100644
index 0000000..48b5d66
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/AbstractOlingo4TestSupport.java
@@ -0,0 +1,104 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.http.HttpHost;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.domain.ClientObjectFactory;
+import org.apache.olingo.client.core.ODataClientFactory;
+
+/**
+ * Abstract base class for Olingo Integration tests generated by Camel API
+ * component maven plugin.
+ */
+public class AbstractOlingo4TestSupport extends CamelTestSupport {
+    protected static final String TEST_SERVICE_BASE_URL = "http://services.odata.org/TripPinRESTierService";
+    protected final ODataClient odataClient = ODataClientFactory.getClient();
+    protected final ClientObjectFactory objFactory = odataClient.getObjectFactory();
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+
+        final CamelContext context = super.createCamelContext();
+
+        Map<String, Object> options = new HashMap<String, Object>();
+        options.put("serviceUri", getRealServiceUrl(TEST_SERVICE_BASE_URL));
+        options.put("contentType", "application/json;charset=utf-8");
+
+        final Olingo4Configuration configuration = new Olingo4Configuration();
+        IntrospectionSupport.setProperties(configuration, options);
+
+        // add OlingoComponent to Camel context
+        final Olingo4Component component = new Olingo4Component(context);
+        component.setConfiguration(configuration);
+        context.addComponent("olingo4", component);
+
+        return context;
+    }
+
+    /*
+     * Every request to the demo OData 4.0
+     * (http://services.odata.org/TripPinRESTierService) generates unique
+     * service URL with postfix like (S(tuivu3up5ygvjzo5fszvnwfv)) for each
+     * session This method makes reuest to the base URL and return URL with
+     * generated postfix
+     */
+    @SuppressWarnings("deprecation")
+    protected String getRealServiceUrl(String baseUrl) throws ClientProtocolException, IOException {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        HttpGet httpGet = new HttpGet(baseUrl);
+        HttpContext httpContext = new BasicHttpContext();
+        httpclient.execute(httpGet, httpContext);
+        HttpUriRequest currentReq = (HttpUriRequest)httpContext.getAttribute(ExecutionContext.HTTP_REQUEST);
+        HttpHost currentHost = (HttpHost)httpContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+        String currentUrl = (currentReq.getURI().isAbsolute()) ? currentReq.getURI().toString() : (currentHost.toURI() + currentReq.getURI());
+
+        return currentUrl;
+    }
+
+    @Override
+    public boolean isCreateCamelContextPerClass() {
+        // only create the context once for this class
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws CamelExecutionException {
+        return (T)template().requestBodyAndHeaders(endpointUri, body, headers);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T requestBody(String endpoint, Object body) throws CamelExecutionException {
+        return (T)template().requestBody(endpoint, body);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java
new file mode 100644
index 0000000..e9435e6
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java
@@ -0,0 +1,264 @@
+/**
+ * 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.camel.component.olingo4;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchChangeRequest;
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchQueryRequest;
+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.olingo.client.api.domain.ClientComplexValue;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
+import org.apache.olingo.client.api.domain.ClientServiceDocument;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.ex.ODataError;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test class for {@link org.apache.camel.component.olingo4.api.Olingo4App}
+ * APIs.
+ * <p>
+ * The integration test runs against using the sample OData 4.0 remote TripPin
+ * service published on http://services.odata.org/TripPinRESTierService.
+ * </p>
+ */
+public class Olingo4ComponentTest extends AbstractOlingo4TestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Olingo4ComponentTest.class);
+
+    private static final String PEOPLE = "People";
+    private static final String TEST_PEOPLE = "People('russellwhyte')";
+    private static final String TEST_CREATE_KEY = "'lewisblack'";
+    private static final String TEST_CREATE_PEOPLE = PEOPLE + "(" + TEST_CREATE_KEY + ")";
+    private static final String TEST_CREATE_RESOURCE_CONTENT_ID = "1";
+    private static final String TEST_UPDATE_RESOURCE_CONTENT_ID = "2";
+
+    @Test
+    public void testRead() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+
+        // Read metadata ($metadata) object
+        final Edm metadata = (Edm)requestBodyAndHeaders("direct://readmetadata", null, headers);
+        assertNotNull(metadata);
+        assertEquals(1, metadata.getSchemas().size());
+
+        // Read service document object
+        final ClientServiceDocument document = (ClientServiceDocument)requestBodyAndHeaders("direct://readdocument", null, headers);
+
+        assertNotNull(document);
+        assertTrue(document.getEntitySets().size() > 1);
+        LOG.info("Service document has {} entity sets", document.getEntitySets().size());
+
+        // Read entity set of the People object
+        final ClientEntitySet entities = (ClientEntitySet)requestBodyAndHeaders("direct://readentities", null, headers);
+        assertNotNull(entities);
+        assertEquals(5, entities.getEntities().size());
+
+        // Read object count with query options passed through header
+        final Long count = (Long)requestBodyAndHeaders("direct://readcount", null, headers);
+        assertEquals(20, count.intValue());
+
+        final ClientPrimitiveValue value = (ClientPrimitiveValue)requestBodyAndHeaders("direct://readvalue", null, headers);
+        LOG.info("Client value \"{}\" has type {}", value.toString(), value.getTypeName());
+        assertEquals("Male", value.asPrimitive().toString());
+
+        final ClientPrimitiveValue singleProperty = (ClientPrimitiveValue)requestBodyAndHeaders("direct://readsingleprop", null, headers);
+        assertTrue(singleProperty.isPrimitive());
+        assertEquals("San Francisco International Airport", singleProperty.toString());
+
+        final ClientComplexValue complexProperty = (ClientComplexValue)requestBodyAndHeaders("direct://readcomplexprop", null, headers);
+        assertTrue(complexProperty.isComplex());
+        assertEquals("San Francisco", complexProperty.get("City").getComplexValue().get("Name").getValue().toString());
+
+        final ClientEntity entity = (ClientEntity)requestBodyAndHeaders("direct://readentitybyid", null, headers);
+        assertNotNull(entity);
+        assertEquals("Russell", entity.getProperty("FirstName").getValue().toString());
+
+        final ClientEntity unbFuncReturn = (ClientEntity)requestBodyAndHeaders("direct://callunboundfunction", null, headers);
+        assertNotNull(unbFuncReturn);
+    }
+
+    @Test
+    public void testCreateUpdateDelete() throws Exception {
+        final ClientEntity clientEntity = createEntity();
+
+        ClientEntity entity = requestBody("direct://create-entity", clientEntity);
+        assertNotNull(entity);
+        assertEquals("Lewis", entity.getProperty("FirstName").getValue().toString());
+        assertEquals("", entity.getProperty("MiddleName").getValue().toString());
+
+        // update
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("MiddleName", objFactory.newPrimitiveValueBuilder().buildString("Lewis")));
+
+        HttpStatusCode status = requestBody("direct://update-entity", clientEntity);
+        assertNotNull("Update status", status);
+        assertEquals("Update status", HttpStatusCode.NO_CONTENT.getStatusCode(), status.getStatusCode());
+        LOG.info("Update entity status: {}", status);
+
+        // delete
+        status = requestBody("direct://delete-entity", null);
+        assertNotNull("Delete status", status);
+        assertEquals("Delete status", HttpStatusCode.NO_CONTENT.getStatusCode(), status.getStatusCode());
+        LOG.info("Delete status: {}", status);
+
+        // check for delete
+        try {
+            requestBody("direct://read-deleted-entity", null);
+        } catch (CamelExecutionException e) {
+            assertEquals("Resource Not Found [HTTP/1.1 404 Not Found]", e.getCause().getMessage());
+        }
+    }
+
+    private ClientEntity createEntity() {
+        ClientEntity clientEntity = objFactory.newEntity(null);
+
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("UserName", objFactory.newPrimitiveValueBuilder().buildString("lewisblack")));
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("FirstName", objFactory.newPrimitiveValueBuilder().buildString("Lewis")));
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("LastName", objFactory.newPrimitiveValueBuilder().buildString("Black")));
+
+        return clientEntity;
+    }
+
+    @Test
+    public void testBatch() throws Exception {
+        final List<Olingo4BatchRequest> batchParts = new ArrayList<Olingo4BatchRequest>();
+
+        // 1. Edm query
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(Constants.METADATA).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 2. Read entities
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 3. Read entity
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(TEST_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // 4. Read with $top
+        final HashMap<String, String> queryParams = new HashMap<String, String>();
+        queryParams.put(SystemQueryOptionKind.TOP.toString(), "5");
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).queryParams(queryParams).build());
+
+        // 5. Create entity
+        ClientEntity clientEntity = createEntity();
+        batchParts.add(Olingo4BatchChangeRequest.resourcePath(PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).contentId(TEST_CREATE_RESOURCE_CONTENT_ID).operation(Operation.CREATE)
+            .body(clientEntity).build());
+
+        // 6. Update middle name in created entry
+        clientEntity.getProperties().add(objFactory.newPrimitiveProperty("MiddleName", objFactory.newPrimitiveValueBuilder().buildString("Lewis")));
+        batchParts.add(Olingo4BatchChangeRequest.resourcePath(TEST_CREATE_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).contentId(TEST_UPDATE_RESOURCE_CONTENT_ID)
+            .operation(Operation.UPDATE).body(clientEntity).build());
+
+        // 7. Delete entity
+        batchParts.add(Olingo4BatchChangeRequest.resourcePath(TEST_CREATE_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).operation(Operation.DELETE).build());
+
+        // 8. Read deleted entity to verify delete
+        batchParts.add(Olingo4BatchQueryRequest.resourcePath(TEST_CREATE_PEOPLE).resourceUri(TEST_SERVICE_BASE_URL).build());
+
+        // execute batch request
+        final List<Olingo4BatchResponse> responseParts = requestBody("direct://batch", batchParts);
+        assertNotNull("Batch response", responseParts);
+        assertEquals("Batch responses expected", 8, responseParts.size());
+
+        final Edm edm = (Edm)responseParts.get(0).getBody();
+        assertNotNull(edm);
+        LOG.info("Edm entity sets: {}", edm.getEntityContainer().getEntitySets());
+
+        ClientEntitySet entitySet = (ClientEntitySet)responseParts.get(1).getBody();
+        assertNotNull(entitySet);
+        LOG.info("Read entities: {}", entitySet.getEntities());
+
+        clientEntity = (ClientEntity)responseParts.get(2).getBody();
+        assertNotNull(clientEntity);
+        LOG.info("Read entiry properties: {}", clientEntity.getProperties());
+
+        ClientEntitySet entitySetWithTop = (ClientEntitySet)responseParts.get(3).getBody();
+        assertNotNull(entitySetWithTop);
+        assertEquals(5, entitySetWithTop.getEntities().size());
+        LOG.info("Read entities with $top=5: {}", entitySet.getEntities());
+
+        clientEntity = (ClientEntity)responseParts.get(4).getBody();
+        assertNotNull(clientEntity);
+        LOG.info("Created entity: {}", clientEntity.getProperties());
+
+        int statusCode = responseParts.get(5).getStatusCode();
+        assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), statusCode);
+        LOG.info("Update MdiddleName status: {}", statusCode);
+
+        statusCode = responseParts.get(6).getStatusCode();
+        assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), statusCode);
+        LOG.info("Delete entity status: {}", statusCode);
+
+        assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), responseParts.get(7).getStatusCode());
+        final ODataError error = (ODataError)responseParts.get(7).getBody();
+        assertNotNull(error);
+        LOG.info("Read deleted entity error: {}", error.getMessage());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test routes for read
+                from("direct://readmetadata").to("olingo4://read/$metadata");
+
+                from("direct://readdocument").to("olingo4://read/");
+
+                from("direct://readentities").to("olingo4://read/People?$top=5&$orderby=FirstName asc");
+
+                from("direct://readcount").to("olingo4://read/People/$count");
+
+                from("direct://readvalue").to("olingo4://read/People('russellwhyte')/Gender/$value");
+
+                from("direct://readsingleprop").to("olingo4://read/Airports('KSFO')/Name");
+
+                from("direct://readcomplexprop").to("olingo4://read/Airports('KSFO')/Location");
+
+                from("direct://readentitybyid").to("olingo4://read/People('russellwhyte')");
+
+                from("direct://callunboundfunction").to("olingo4://read/GetNearestAirport(lat=33,lon=-118)");
+
+                // test route for create individual entity
+                from("direct://create-entity").to("olingo4://create/People");
+
+                // test route for update
+                from("direct://update-entity").to("olingo4://update/People('lewisblack')");
+
+                // test route for delete
+                from("direct://delete-entity").to("olingo4://delete/People('lewisblack')");
+
+                // test route for delete
+                from("direct://read-deleted-entity").to("olingo4://delete/People('lewisblack')");
+
+                // test route for batch
+                from("direct://batch").to("olingo4://batch");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-component/src/test/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-component/src/test/resources/log4j2.properties b/components/camel-olingo4/camel-olingo4-component/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..46bf0df
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-olingo4-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/pom.xml b/components/camel-olingo4/pom.xml
new file mode 100644
index 0000000..b648e66
--- /dev/null
+++ b/components/camel-olingo4/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>components</artifactId>
+    <groupId>org.apache.camel</groupId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-olingo4-parent</artifactId>
+  <packaging>pom</packaging>
+  <name>Camel :: Olingo4 :: Parent</name>
+  <description>Camel Olingo4 parent</description>
+
+  <modules>
+    <module>camel-olingo4-api</module>
+    <module>camel-olingo4-component</module>
+  </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 1d8a1cd..f160c8e 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -206,6 +206,7 @@
     <module>camel-netty4-http</module>
     <module>camel-ognl</module>
     <module>camel-olingo2</module>
+    <module>camel-olingo4</module>
     <module>camel-openshift</module>
     <module>camel-openstack</module>
     <module>camel-opentracing</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index d969f80..6c27006 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -481,6 +481,7 @@
     <olingo2-version>2.0.8</olingo2-version>
     <olingo-odata2-core-bundle-version>2.0.8_1</olingo-odata2-core-bundle-version>
     <olingo2-gson-version>2.4</olingo2-gson-version>
+    <olingo4-version>4.3.0</olingo4-version>
     <ognl-version>3.1.12</ognl-version>
     <ognl-bundle-version>3.1.12_1</ognl-bundle-version>
     <oncrpc-version>1.1.3</oncrpc-version>

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/pom.xml b/platforms/spring-boot/components-starter/camel-olingo4-starter/pom.xml
new file mode 100644
index 0000000..cd14a04
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components-starter</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>camel-olingo4-starter</artifactId>
+  <packaging>jar</packaging>
+  <name>Spring-Boot Starter :: Camel :: Olingo4 :: Component</name>
+  <description>Spring-Boot Starter for Camel Olingo4 component</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+      <version>${spring-boot-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-olingo4</artifactId>
+      <version>${project.version}</version>
+      <!--START OF GENERATED CODE-->
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+      <!--END OF GENERATED CODE-->
+    </dependency>
+    <!--START OF GENERATED CODE-->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring-boot-starter</artifactId>
+    </dependency>
+    <!--END OF GENERATED CODE-->
+  </dependencies>
+  <!--START OF GENERATED CODE-->
+  <repositories>
+    <repository>
+      <id>redhat-ga-repository</id>
+      <url>https://maven.repository.redhat.com/ga</url>
+    </repository>
+  </repositories>
+  <!--END OF GENERATED CODE-->
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentAutoConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentAutoConfiguration.java
new file mode 100644
index 0000000..f3e685d
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentAutoConfiguration.java
@@ -0,0 +1,111 @@
+/**
+ * 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.camel.component.olingo4.springboot;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.olingo4.Olingo4Component;
+import org.apache.camel.util.IntrospectionSupport;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionMessage;
+import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
+import org.springframework.boot.bind.RelaxedPropertyResolver;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Configuration
+@ConditionalOnBean(type = "org.apache.camel.spring.boot.CamelAutoConfiguration")
+@Conditional(Olingo4ComponentAutoConfiguration.Condition.class)
+@AutoConfigureAfter(name = "org.apache.camel.spring.boot.CamelAutoConfiguration")
+@EnableConfigurationProperties(Olingo4ComponentConfiguration.class)
+public class Olingo4ComponentAutoConfiguration {
+
+    @Lazy
+    @Bean(name = "olingo4-component")
+    @ConditionalOnClass(CamelContext.class)
+    @ConditionalOnMissingBean(Olingo4Component.class)
+    public Olingo4Component configureOlingo4Component(
+            CamelContext camelContext,
+            Olingo4ComponentConfiguration configuration) throws Exception {
+        Olingo4Component component = new Olingo4Component();
+        component.setCamelContext(camelContext);
+        Map<String, Object> parameters = new HashMap<>();
+        IntrospectionSupport.getProperties(configuration, parameters, null,
+                false);
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            Object value = entry.getValue();
+            Class<?> paramClass = value.getClass();
+            if (paramClass.getName().endsWith("NestedConfiguration")) {
+                Class nestedClass = null;
+                try {
+                    nestedClass = (Class) paramClass.getDeclaredField(
+                            "CAMEL_NESTED_CLASS").get(null);
+                    HashMap<String, Object> nestedParameters = new HashMap<>();
+                    IntrospectionSupport.getProperties(value, nestedParameters,
+                            null, false);
+                    Object nestedProperty = nestedClass.newInstance();
+                    IntrospectionSupport.setProperties(camelContext,
+                            camelContext.getTypeConverter(), nestedProperty,
+                            nestedParameters);
+                    entry.setValue(nestedProperty);
+                } catch (NoSuchFieldException e) {
+                }
+            }
+        }
+        IntrospectionSupport.setProperties(camelContext,
+                camelContext.getTypeConverter(), component, parameters);
+        return component;
+    }
+
+    public static class Condition extends SpringBootCondition {
+        @Override
+        public ConditionOutcome getMatchOutcome(
+                ConditionContext conditionContext,
+                AnnotatedTypeMetadata annotatedTypeMetadata) {
+            boolean groupEnabled = isEnabled(conditionContext,
+                    "camel.component.", true);
+            ConditionMessage.Builder message = ConditionMessage
+                    .forCondition("camel.component.olingo4");
+            if (isEnabled(conditionContext, "camel.component.olingo4.",
+                    groupEnabled)) {
+                return ConditionOutcome.match(message.because("enabled"));
+            }
+            return ConditionOutcome.noMatch(message.because("not enabled"));
+        }
+
+        private boolean isEnabled(
+                org.springframework.context.annotation.ConditionContext context,
+                java.lang.String prefix, boolean defaultValue) {
+            RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
+                    context.getEnvironment(), prefix);
+            return resolver.getProperty("enabled", Boolean.class, defaultValue);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
new file mode 100644
index 0000000..35da6ed
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/java/org/apache/camel/component/olingo4/springboot/Olingo4ComponentConfiguration.java
@@ -0,0 +1,201 @@
+/**
+ * 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.camel.component.olingo4.springboot;
+
+import java.util.Map;
+import org.apache.camel.component.olingo4.internal.Olingo4ApiName;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
+
+/**
+ * Communicates with OData 4.0 services using Apache Olingo OData API.
+ * 
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@ConfigurationProperties(prefix = "camel.component.olingo4")
+public class Olingo4ComponentConfiguration {
+
+    /**
+     * To use the shared configuration
+     */
+    private Olingo4ConfigurationNestedConfiguration configuration;
+
+    public Olingo4ConfigurationNestedConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(
+            Olingo4ConfigurationNestedConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    public static class Olingo4ConfigurationNestedConfiguration {
+        public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.olingo4.Olingo4Configuration.class;
+        /**
+         * What kind of operation to perform
+         */
+        private Olingo4ApiName apiName;
+        /**
+         * What sub operation to use for the selected operation
+         */
+        private String methodName;
+        /**
+         * Target OData service base URI, e.g.
+         * http://services.odata.org/OData/OData.svc
+         */
+        private String serviceUri;
+        /**
+         * Content-Type header value can be used to specify JSON or XML message
+         * format, defaults to application/json;charset=utf-8
+         */
+        private String contentType = "application/json;charset=utf-8";
+        /**
+         * Custom HTTP headers to inject into every request, this could include
+         * OAuth tokens, etc.
+         */
+        private Map httpHeaders;
+        /**
+         * HTTP connection creation timeout in milliseconds, defaults to 30,000
+         * (30 seconds)
+         */
+        private Integer connectTimeout;
+        /**
+         * HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds)
+         */
+        private Integer socketTimeout;
+        /**
+         * HTTP proxy server configuration
+         */
+        @NestedConfigurationProperty
+        private HttpHost proxy;
+        /**
+         * To configure security using SSLContextParameters
+         */
+        @NestedConfigurationProperty
+        private SSLContextParameters sslContextParameters;
+        /**
+         * Custom HTTP async client builder for more complex HTTP client
+         * configuration, overrides connectionTimeout, socketTimeout, proxy and
+         * sslContext. Note that a socketTimeout MUST be specified in the
+         * builder, otherwise OData requests could block indefinitely
+         */
+        @NestedConfigurationProperty
+        private HttpAsyncClientBuilder httpAsyncClientBuilder;
+        /**
+         * Custom HTTP client builder for more complex HTTP client
+         * configuration, overrides connectionTimeout, socketTimeout, proxy and
+         * sslContext. Note that a socketTimeout MUST be specified in the
+         * builder, otherwise OData requests could block indefinitely
+         */
+        @NestedConfigurationProperty
+        private HttpClientBuilder httpClientBuilder;
+
+        public Olingo4ApiName getApiName() {
+            return apiName;
+        }
+
+        public void setApiName(Olingo4ApiName apiName) {
+            this.apiName = apiName;
+        }
+
+        public String getMethodName() {
+            return methodName;
+        }
+
+        public void setMethodName(String methodName) {
+            this.methodName = methodName;
+        }
+
+        public String getServiceUri() {
+            return serviceUri;
+        }
+
+        public void setServiceUri(String serviceUri) {
+            this.serviceUri = serviceUri;
+        }
+
+        public String getContentType() {
+            return contentType;
+        }
+
+        public void setContentType(String contentType) {
+            this.contentType = contentType;
+        }
+
+        public Map getHttpHeaders() {
+            return httpHeaders;
+        }
+
+        public void setHttpHeaders(Map httpHeaders) {
+            this.httpHeaders = httpHeaders;
+        }
+
+        public Integer getConnectTimeout() {
+            return connectTimeout;
+        }
+
+        public void setConnectTimeout(Integer connectTimeout) {
+            this.connectTimeout = connectTimeout;
+        }
+
+        public Integer getSocketTimeout() {
+            return socketTimeout;
+        }
+
+        public void setSocketTimeout(Integer socketTimeout) {
+            this.socketTimeout = socketTimeout;
+        }
+
+        public HttpHost getProxy() {
+            return proxy;
+        }
+
+        public void setProxy(HttpHost proxy) {
+            this.proxy = proxy;
+        }
+
+        public SSLContextParameters getSslContextParameters() {
+            return sslContextParameters;
+        }
+
+        public void setSslContextParameters(
+                SSLContextParameters sslContextParameters) {
+            this.sslContextParameters = sslContextParameters;
+        }
+
+        public HttpAsyncClientBuilder getHttpAsyncClientBuilder() {
+            return httpAsyncClientBuilder;
+        }
+
+        public void setHttpAsyncClientBuilder(
+                HttpAsyncClientBuilder httpAsyncClientBuilder) {
+            this.httpAsyncClientBuilder = httpAsyncClientBuilder;
+        }
+
+        public HttpClientBuilder getHttpClientBuilder() {
+            return httpClientBuilder;
+        }
+
+        public void setHttpClientBuilder(HttpClientBuilder httpClientBuilder) {
+            this.httpClientBuilder = httpClientBuilder;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/LICENSE.txt b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-olingo4-starter/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+


[5/6] camel git commit: CAMEL-11056: Create new camel-olingo4 component for supporting OData 4.0

Posted by ac...@apache.org.
CAMEL-11056: Create new camel-olingo4 component for supporting OData 4.0

Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e6eded4c
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e6eded4c
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e6eded4c

Branch: refs/heads/master
Commit: e6eded4c217b1734f36731396bff2f7fb9ee6f04
Parents: 46180b9
Author: Dmitry Volodin <dm...@gmail.com>
Authored: Thu Mar 23 15:48:32 2017 +0300
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Fri Mar 24 09:49:39 2017 +0100

----------------------------------------------------------------------
 .../camel-olingo4/camel-olingo4-api/pom.xml     | 141 ++++
 .../camel/component/olingo4/api/Olingo4App.java | 145 ++++
 .../olingo4/api/Olingo4ResponseHandler.java     |  43 +
 .../api/batch/Olingo4BatchChangeRequest.java    | 103 +++
 .../api/batch/Olingo4BatchQueryRequest.java     |  76 ++
 .../olingo4/api/batch/Olingo4BatchRequest.java  |  44 +
 .../olingo4/api/batch/Olingo4BatchResponse.java |  63 ++
 .../component/olingo4/api/batch/Operation.java  |  39 +
 .../api/impl/AbstractFutureCallback.java        | 111 +++
 .../olingo4/api/impl/Olingo4AppImpl.java        | 841 +++++++++++++++++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 +++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../component/olingo4/Olingo4AppAPITest.java    | 543 ++++++++++++
 .../src/test/resources/log4j2.properties        |  28 +
 .../camel-olingo4-component/pom.xml             | 191 +++++
 .../src/main/docs/olingo4-component.adoc        | 252 ++++++
 .../src/main/java/META-INF/MANIFEST.MF          |   3 +
 .../component/olingo4/Olingo4AppWrapper.java    | 108 +++
 .../component/olingo4/Olingo4Component.java     | 184 ++++
 .../component/olingo4/Olingo4Configuration.java | 221 +++++
 .../component/olingo4/Olingo4Consumer.java      |  92 ++
 .../component/olingo4/Olingo4Endpoint.java      | 222 +++++
 .../component/olingo4/Olingo4Producer.java      | 106 +++
 .../olingo4/internal/Olingo4Constants.java      |  29 +
 .../internal/Olingo4PropertiesHelper.java       |  39 +
 .../src/main/resources/META-INF/LICENSE.txt     | 203 +++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../services/org/apache/camel/component/olingo4 |  18 +
 .../src/signatures/olingo-api-signature.txt     |   8 +
 .../olingo4/AbstractOlingo4TestSupport.java     | 104 +++
 .../component/olingo4/Olingo4ComponentTest.java | 264 ++++++
 .../src/test/resources/log4j2.properties        |  28 +
 components/camel-olingo4/pom.xml                |  38 +
 components/pom.xml                              |   1 +
 parent/pom.xml                                  |   1 +
 .../camel-olingo4-starter/pom.xml               |  67 ++
 .../Olingo4ComponentAutoConfiguration.java      | 111 +++
 .../Olingo4ComponentConfiguration.java          | 201 +++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 +++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 ...dditional-spring-configuration-metadata.json |  10 +
 .../main/resources/META-INF/spring.factories    |  19 +
 .../src/main/resources/META-INF/spring.provides |  18 +
 .../spring-boot/components-starter/pom.xml      |   1 +
 44 files changed, 5155 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/pom.xml b/components/camel-olingo4/camel-olingo4-api/pom.xml
new file mode 100644
index 0000000..7f0495c
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/pom.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-olingo4-parent</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-olingo4-api</artifactId>
+  <name>Camel :: Olingo4 :: API</name>
+  <description>Camel Olingo4 API</description>
+  <packaging>jar</packaging>
+
+  <properties>
+    <camel.osgi.export.pkg>org.apache.camel.component.olingo4.api*</camel.osgi.export.pkg>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-commons-api</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-commons-core</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-client-core</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-server-core</artifactId>
+      <version>${olingo4-version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpasyncclient</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>net.sf.jsignature.io-tools</groupId>
+      <artifactId>easystream</artifactId>
+      <version>1.2.15</version>
+    </dependency>
+
+    <!-- logging -->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <!-- testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <defaultGoal>install</defaultGoal>
+
+    <plugins>
+
+      <!-- to generate API Javadoc -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-javadoc</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+            <configuration>
+              <attach>true</attach>
+              <source>${jdk.version}</source>
+              <quiet>true</quiet>
+              <detectOfflineLinks>false</detectOfflineLinks>
+              <javadocVersion>${jdk.version}</javadocVersion>
+              <encoding>UTF-8</encoding>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+
+  <!-- Disable Java 8 doclint checks to avoid Javadoc plugin failures -->
+  <profiles>
+    <profile>
+      <id>doclint-java8-disable</id>
+      <activation>
+        <jdk>[1.8,</jdk>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <configuration>
+              <additionalparam>-Xdoclint:none</additionalparam>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4App.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..95d42c2
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4App.java
@@ -0,0 +1,145 @@
+/**
+ * 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.camel.component.olingo4.api;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchResponse;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+
+/**
+ * Olingo4 Client Api Interface.
+ */
+public interface Olingo4App {
+
+    /**
+     * Sets Service base URI.
+     * @param serviceUri
+     */
+    void setServiceUri(String serviceUri);
+
+    /**
+     * Returns Service base URI.
+     * @return service base URI.
+     */
+    String getServiceUri();
+
+    /**
+     * Sets custom Http headers to add to every service request.
+     * @param httpHeaders custom Http headers.
+     */
+    void setHttpHeaders(Map<String, String> httpHeaders);
+
+    /**
+     * Returns custom Http headers.
+     * @return custom Http headers.
+     */
+    Map<String, String> getHttpHeaders();
+
+    /**
+     * Returns content type for service calls. Defaults to <code>application/json;charset=utf-8</code>.
+     * @return content type.
+     */
+    String getContentType();
+
+    /**
+     * Set default service call content type.
+     * @param contentType content type.
+     */
+    void setContentType(String contentType);
+
+    /**
+     * Closes resources.
+     */
+    void close();
+
+    /**
+     * Reads an OData resource and invokes callback with appropriate result.
+     * @param edm Service Edm, read from calling <code>read(null, "$metdata", null, responseHandler)</code>
+     * @param resourcePath OData Resource path
+     * @param queryParams OData query params
+     *                    http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part1-protocol.html#_Toc453752288
+     * @param responseHandler callback handler
+     */
+    <T> void read(Edm edm, String resourcePath, Map<String, String> queryParams, Olingo4ResponseHandler<T> responseHandler);
+
+    /**
+     * Reads an OData resource and invokes callback with the unparsed input stream.
+     * @param edm Service Edm, read from calling <code>read(null, "$metdata", null, responseHandler)</code>
+     * @param resourcePath OData Resource path
+     * @param queryParams OData query params
+     *                    http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part1-protocol.html#_Toc453752288
+     * @param responseHandler callback handler
+     */
+    void uread(Edm edm, String resourcePath, Map<String, String> queryParams,
+               Olingo4ResponseHandler<InputStream> responseHandler);
+
+    /**
+     * Deletes an OData resource and invokes callback
+     * with {@link org.apache.olingo.commons.api.http.HttpStatusCode} on success, or with exception on failure.
+     * @param resourcePath resource path for Entry
+     * @param responseHandler {@link org.apache.olingo.commons.api.http.HttpStatusCode} callback handler
+     */
+    void delete(String resourcePath, Olingo4ResponseHandler<HttpStatusCode> responseHandler);
+
+    /**
+     * Creates a new OData resource.
+     * @param edm service Edm
+     * @param resourcePath resource path to create
+     * @param data request data
+     * @param responseHandler callback handler
+     */
+    <T> void create(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler);
+
+    /**
+     * Updates an OData resource.
+     * @param edm service Edm
+     * @param resourcePath resource path to update
+     * @param data updated data
+     * @param responseHandler {@link org.apache.olingo.client.api.domain.ClientEntity} callback handler
+     */
+    <T> void update(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler);
+
+    /**
+     * Patches/merges an OData resource using HTTP PATCH.
+     * @param edm service Edm
+     * @param resourcePath resource path to update
+     * @param data patch/merge data
+     * @param responseHandler {@link org.apache.olingo.client.api.domain.ClientEntity} callback handler
+     */
+    <T> void patch(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler);
+
+    /**
+     * Patches/merges an OData resource using HTTP MERGE.
+     * @param edm service Edm
+     * @param resourcePath resource path to update
+     * @param data patch/merge data
+     * @param responseHandler {@link org.apache.olingo.client.api.domain.ClientEntity} callback handler
+     */
+    <T> void merge(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler);
+
+    /**
+     * Executes a batch request.
+     * @param edm service Edm
+     * @param data ordered {@link org.apache.camel.component.olingo4.api.batch.Olingo4BatchRequest} list
+     * @param responseHandler callback handler
+     */
+    void batch(Edm edm, Object data, Olingo4ResponseHandler<List<Olingo4BatchResponse>> responseHandler);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4ResponseHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4ResponseHandler.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4ResponseHandler.java
new file mode 100644
index 0000000..13438ba
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/Olingo4ResponseHandler.java
@@ -0,0 +1,43 @@
+/**
+ * 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.camel.component.olingo4.api;
+
+/**
+ * Callback interface to asynchronously process Olingo4 response.
+ */
+public interface Olingo4ResponseHandler<T> {
+
+    /**
+     * Handle response data on successful completion of Olingo4 request.
+     * @param response response data from Olingo4, may be NULL for Olingo4 operations with no response data.
+     */
+    void onResponse(T response);
+
+    /**
+     * Handle exception raised from Olingo4 request.
+     * @param ex exception from Olingo4 request.
+     * May be an instance of {@link org.apache.olingo.commons.api.ex.ODataException} or
+     * some other exception, such as {@link java.io.IOException}
+     */
+    void onException(Exception ex);
+
+    /**
+     * Handle Olingo4 request cancellation.
+     * May be caused by the underlying HTTP connection being shutdown asynchronously.
+     */
+    void onCanceled();
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchChangeRequest.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchChangeRequest.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchChangeRequest.java
new file mode 100644
index 0000000..5b4e1eb
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchChangeRequest.java
@@ -0,0 +1,103 @@
+/**
+ * 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.camel.component.olingo4.api.batch;
+
+import java.util.Map;
+
+/**
+ * Batch Change part.
+ */
+public class Olingo4BatchChangeRequest extends Olingo4BatchRequest {
+
+    protected String contentId;
+    protected Operation operation;
+    protected Object body;
+
+    public Operation getOperation() {
+        return operation;
+    }
+
+    public Object getBody() {
+        return body;
+    }
+
+    public String getContentId() {
+        return contentId;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("Batch Change Request{ ").append(resourceUri).append("/").append(resourcePath).append(", headers=").append(headers).append(", contentId=")
+            .append(contentId).append(", operation=").append(operation).append(", body=").append(body).append('}').toString();
+    }
+
+    public static Olingo4BatchChangeRequestBuilder resourcePath(String resourcePath) {
+        if (resourcePath == null) {
+            throw new IllegalArgumentException("resourcePath");
+        }
+        return new Olingo4BatchChangeRequestBuilder().resourcePath(resourcePath);
+    }
+
+    public static class Olingo4BatchChangeRequestBuilder {
+
+        private Olingo4BatchChangeRequest request = new Olingo4BatchChangeRequest();
+
+        public Olingo4BatchChangeRequestBuilder resourcePath(String resourcePath) {
+            request.resourcePath = resourcePath;
+            return this;
+        }
+
+        public Olingo4BatchChangeRequestBuilder resourceUri(String resourceUri) {
+            request.resourceUri = resourceUri;
+            return this;
+        }
+
+        public Olingo4BatchChangeRequestBuilder headers(Map<String, String> headers) {
+            request.headers = headers;
+            return this;
+        }
+
+        public Olingo4BatchChangeRequestBuilder contentId(String contentId) {
+            request.contentId = contentId;
+            return this;
+        }
+
+        public Olingo4BatchChangeRequestBuilder operation(Operation operation) {
+            request.operation = operation;
+            return this;
+        }
+
+        public Olingo4BatchChangeRequestBuilder body(Object body) {
+            request.body = body;
+            return this;
+        }
+
+        public Olingo4BatchChangeRequest build() {
+            // avoid later NPEs
+            if (request.resourcePath == null) {
+                throw new IllegalArgumentException("Null resourcePath");
+            }
+            if (request.operation == null) {
+                throw new IllegalArgumentException("Null operation");
+            }
+            if (request.operation != Operation.DELETE && request.body == null) {
+                throw new IllegalArgumentException("Null body");
+            }
+            return request;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchQueryRequest.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchQueryRequest.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchQueryRequest.java
new file mode 100644
index 0000000..127a3ef
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchQueryRequest.java
@@ -0,0 +1,76 @@
+/**
+ * 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.camel.component.olingo4.api.batch;
+
+import java.util.Map;
+
+/**
+ * Batch Query part.
+ */
+public class Olingo4BatchQueryRequest extends Olingo4BatchRequest {
+
+    private Map<String, String> queryParams;
+
+    public Map<String, String> getQueryParams() {
+        return queryParams;
+    }
+
+    public static Olingo4BatchQueryRequestBuilder resourcePath(String resourcePath) {
+        if (resourcePath == null) {
+            throw new IllegalArgumentException("resourcePath");
+        }
+        return new Olingo4BatchQueryRequestBuilder().resourcePath(resourcePath);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("Batch Query Request{ ").append(resourceUri).append("/").append(resourcePath).append(", headers=").append(headers).append(", queryParams=")
+            .append(queryParams).append('}').toString();
+    }
+
+    public static class Olingo4BatchQueryRequestBuilder {
+        private Olingo4BatchQueryRequest request = new Olingo4BatchQueryRequest();
+
+        public Olingo4BatchQueryRequest build() {
+            // avoid later NPEs
+            if (request.resourcePath == null) {
+                throw new IllegalArgumentException("Null resourcePath");
+            }
+            return request;
+        }
+
+        public Olingo4BatchQueryRequestBuilder resourceUri(String resourceUri) {
+            request.resourceUri = resourceUri;
+            return this;
+        }
+
+        public Olingo4BatchQueryRequestBuilder resourcePath(String resourcePath) {
+            request.resourcePath = resourcePath;
+            return this;
+        }
+
+        public Olingo4BatchQueryRequestBuilder headers(Map<String, String> headers) {
+            request.headers = headers;
+            return this;
+        }
+
+        public Olingo4BatchQueryRequestBuilder queryParams(Map<String, String> queryParams) {
+            request.queryParams = queryParams;
+            return this;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchRequest.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchRequest.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchRequest.java
new file mode 100644
index 0000000..8ad9568
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchRequest.java
@@ -0,0 +1,44 @@
+/**
+ * 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.camel.component.olingo4.api.batch;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base part in a multipart Batch request.
+ */
+public abstract class Olingo4BatchRequest {
+
+    protected String resourceUri;
+    protected String resourcePath;
+    protected Map<String, String> headers = new HashMap<String, String>();
+
+    public String getResourceUri() {
+        return resourceUri;
+    }
+    
+    public String getResourcePath() {
+        return resourcePath;
+    }
+
+    public Map<String, String> getHeaders() {
+        return headers;
+    }
+
+    public abstract String toString();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchResponse.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchResponse.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchResponse.java
new file mode 100644
index 0000000..9d4ce91
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Olingo4BatchResponse.java
@@ -0,0 +1,63 @@
+/**
+ * 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.camel.component.olingo4.api.batch;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Batch Response part.
+ */
+public class Olingo4BatchResponse {
+
+    private final int statusCode;
+    private final String statusInfo;
+
+    private final String contentId;
+
+    private final Map<String, String> headers;
+    private final Object body;
+
+    public Olingo4BatchResponse(int statusCode, String statusInfo, String contentId, Map<String, String> headers, Object body) {
+        this.statusCode = statusCode;
+        this.statusInfo = statusInfo;
+        this.contentId = contentId;
+        this.headers = Collections.unmodifiableMap(new HashMap<String, String>(headers));
+        this.body = body;
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    public String getStatusInfo() {
+        return statusInfo;
+    }
+
+    public String getContentId() {
+        return contentId;
+    }
+
+    public Map<String, String> getHeaders() {
+        return headers;
+    }
+
+    public Object getBody() {
+        return body;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Operation.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Operation.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Operation.java
new file mode 100644
index 0000000..5785cae
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/batch/Operation.java
@@ -0,0 +1,39 @@
+/**
+ * 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.camel.component.olingo4.api.batch;
+
+/**
+* OData operation used by {@link org.apache.camel.component.olingo4.api.batch.Olingo4BatchChangeRequest}.
+*/
+public enum Operation {
+
+    CREATE("POST"),
+    UPDATE("PUT"),
+    PATCH("PATCH"),
+    MERGE("MERGE"),
+    DELETE("DELETE");
+
+    private final String httpMethod;
+
+    Operation(String httpMethod) {
+        this.httpMethod = httpMethod;
+    }
+
+    public String getHttpMethod() {
+        return httpMethod;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/AbstractFutureCallback.java
----------------------------------------------------------------------
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/AbstractFutureCallback.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/AbstractFutureCallback.java
new file mode 100644
index 0000000..1a206fa
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/AbstractFutureCallback.java
@@ -0,0 +1,111 @@
+/**
+ * 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.camel.component.olingo4.api.impl;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.regex.Pattern;
+
+import org.apache.camel.component.olingo4.api.Olingo4ResponseHandler;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.communication.ODataClientErrorException;
+import org.apache.olingo.client.api.serialization.ODataReader;
+import org.apache.olingo.client.core.ODataClientFactory;
+import org.apache.olingo.client.core.serialization.ODataReaderImpl;
+import org.apache.olingo.commons.api.ex.ODataError;
+import org.apache.olingo.commons.api.ex.ODataException;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+
+/**
+* Helper implementation of {@link org.apache.http.concurrent.FutureCallback}
+ * for {@link org.apache.camel.component.olingo4.api.impl.Olingo4AppImpl}
+*/
+public abstract class AbstractFutureCallback<T> implements FutureCallback<HttpResponse> {
+
+    public static final Pattern ODATA_MIME_TYPE_PATTERN = Pattern.compile("application/((atom)|(json)|(xml)).*");
+    public static final int NETWORK_CONNECT_TIMEOUT_ERROR = 599;
+    
+    private final Olingo4ResponseHandler<T> responseHandler;
+
+    AbstractFutureCallback(Olingo4ResponseHandler<T> responseHandler) {
+        this.responseHandler = responseHandler;
+    }
+
+    public static HttpStatusCode checkStatus(HttpResponse response) throws ODataException, ODataClientErrorException {
+        final StatusLine statusLine = response.getStatusLine();
+        HttpStatusCode httpStatusCode = HttpStatusCode.fromStatusCode(statusLine.getStatusCode());
+        if (HttpStatusCode.BAD_REQUEST.getStatusCode() <= httpStatusCode.getStatusCode() && httpStatusCode.getStatusCode() <= NETWORK_CONNECT_TIMEOUT_ERROR) {
+            if (response.getEntity() != null) {
+                try {
+                    final ContentType responseContentType = ContentType.parse(
+                        response.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+                              
+                    if (ODATA_MIME_TYPE_PATTERN.matcher(responseContentType.toContentTypeString()).matches()) {
+                        final ODataReader reader = ODataClientFactory.getClient().getReader();
+                        final ODataError error = reader.readError(response.getEntity().getContent(), responseContentType);
+                        
+                        throw new ODataClientErrorException(statusLine, error);
+                    }
+                } catch (IOException e) {
+                    throw new ODataException(e.getMessage(), e);
+                }
+            }
+
+            throw new ODataException(statusLine.getReasonPhrase());
+        }
+
+        return httpStatusCode;
+    }
+
+    @Override
+    public final void completed(HttpResponse result) {
+        try {
+            // check response status
+            checkStatus(result);
+
+            onCompleted(result);
+        } catch (Exception e) {
+            failed(e);
+        } finally {
+            if (result instanceof Closeable) {
+                try {
+                    ((Closeable) result).close();
+                } catch (final IOException ignore) {
+                }
+            }
+        }
+    }
+
+    protected abstract void onCompleted(HttpResponse result) throws ODataException, IOException;
+
+    @Override
+    public final void failed(Exception ex) {
+        responseHandler.onException(ex);
+    }
+
+    @Override
+    public final void cancelled() {
+        responseHandler.onCanceled();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6eded4c/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..7dffd1c
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java
@@ -0,0 +1,841 @@
+/**
+ * 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.camel.component.olingo4.api.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.camel.component.olingo4.api.Olingo4App;
+import org.apache.camel.component.olingo4.api.Olingo4ResponseHandler;
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchChangeRequest;
+import org.apache.camel.component.olingo4.api.batch.Olingo4BatchQueryRequest;
+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.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.client.entity.DecompressingEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPatch;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+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.ByteArrayEntity;
+import org.apache.http.impl.DefaultHttpResponseFactory;
+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.impl.conn.DefaultHttpResponseParser;
+import org.apache.http.impl.io.HttpTransportMetricsImpl;
+import org.apache.http.impl.io.SessionInputBufferImpl;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.apache.http.message.BasicLineParser;
+import org.apache.olingo.client.api.ODataBatchConstants;
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.communication.request.ODataStreamer;
+import org.apache.olingo.client.api.communication.request.batch.ODataBatchLineIterator;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
+import org.apache.olingo.client.api.domain.ClientProperty;
+import org.apache.olingo.client.api.serialization.ODataReader;
+import org.apache.olingo.client.api.serialization.ODataWriter;
+import org.apache.olingo.client.api.uri.SegmentType;
+import org.apache.olingo.client.core.ODataClientFactory;
+import org.apache.olingo.client.core.communication.request.batch.ODataBatchController;
+import org.apache.olingo.client.core.communication.request.batch.ODataBatchLineIteratorImpl;
+import org.apache.olingo.client.core.communication.request.batch.ODataBatchUtilities;
+import org.apache.olingo.client.core.http.HttpMerge;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.ex.ODataException;
+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.OData;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceKind;
+import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
+import org.apache.olingo.server.core.uri.parser.Parser;
+import org.apache.olingo.server.core.uri.parser.UriParserException;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+/**
+ * Application API used by Olingo4 Component.
+ */
+public final class Olingo4AppImpl implements Olingo4App {
+
+    private static final String SEPARATOR = "/";
+    private static final String BOUNDARY_PREFIX = "batch_";
+    private static final String BOUNDARY_PARAMETER = "; boundary=";
+    private static final String BOUNDARY_DOUBLE_DASH = "--";
+    private static final String MULTIPART_MIME_TYPE = "multipart/";
+    private static final String CONTENT_ID_HEADER = "Content-ID";
+    private static final String CLIENT_ENTITY_FAKE_MARKER = "('X')";
+
+    private static final ContentType DEFAULT_CONTENT_TYPE = ContentType.create(ContentType.APPLICATION_JSON, ContentType.PARAMETER_CHARSET, Constants.UTF8);
+    private static final ContentType METADATA_CONTENT_TYPE = ContentType.create(ContentType.APPLICATION_XML, ContentType.PARAMETER_CHARSET, Constants.UTF8);
+    private static final ContentType TEXT_PLAIN_WITH_CS_UTF_8 = ContentType.create(ContentType.TEXT_PLAIN, ContentType.PARAMETER_CHARSET, Constants.UTF8);
+    private static final ContentType SERVICE_DOCUMENT_CONTENT_TYPE = ContentType.APPLICATION_JSON;
+    private static final ContentType BATCH_CONTENT_TYPE = ContentType.MULTIPART_MIXED;
+
+    /**
+     * Reference to CloseableHttpAsyncClient (default) or CloseableHttpClient
+     */
+    private final Closeable client;
+
+    /**
+     * Reference to ODataClient reader and writer
+     */
+    private final ODataClient odataClient = ODataClientFactory.getClient();
+    private final ODataReader odataReader = odataClient.getReader();
+    private final ODataWriter odataWriter = odataClient.getWriter();
+
+    private String serviceUri;
+    private ContentType contentType;
+    private Map<String, String> httpHeaders;
+
+    /**
+     * Create Olingo4 Application with default HTTP configuration.
+     */
+    public Olingo4AppImpl(String serviceUri) {
+        // By default create HTTP asynchronous client
+        this(serviceUri, (HttpClientBuilder)null);
+    }
+
+    /**
+     * Create Olingo4 Application with custom HTTP Asynchronous client builder.
+     *
+     * @param serviceUri Service Application base URI.
+     * @param builder custom HTTP client builder.
+     */
+    public Olingo4AppImpl(String serviceUri, HttpAsyncClientBuilder builder) {
+        setServiceUri(serviceUri);
+
+        CloseableHttpAsyncClient asyncClient;
+        if (builder == null) {
+            asyncClient = HttpAsyncClients.createDefault();
+        } else {
+            asyncClient = builder.build();
+        }
+        asyncClient.start();
+        this.client = asyncClient;
+        this.contentType = DEFAULT_CONTENT_TYPE;
+    }
+
+    /**
+     * Create Olingo4 Application with custom HTTP Synchronous client builder.
+     *
+     * @param serviceUri Service Application base URI.
+     * @param builder Custom HTTP Synchronous client builder.
+     */
+    public Olingo4AppImpl(String serviceUri, HttpClientBuilder builder) {
+        setServiceUri(serviceUri);
+
+        if (builder == null) {
+            this.client = HttpClients.createDefault();
+        } else {
+            this.client = builder.build();
+        }
+        this.contentType = DEFAULT_CONTENT_TYPE;
+    }
+
+    @Override
+    public void setServiceUri(String serviceUri) {
+        if (serviceUri == null || serviceUri.isEmpty()) {
+            throw new IllegalArgumentException("serviceUri");
+        }
+        this.serviceUri = serviceUri.endsWith(SEPARATOR) ? serviceUri.substring(0, serviceUri.length() - 1) : serviceUri;
+    }
+
+    @Override
+    public String getServiceUri() {
+        return serviceUri;
+    }
+
+    @Override
+    public Map<String, String> getHttpHeaders() {
+        return httpHeaders;
+    }
+
+    @Override
+    public void setHttpHeaders(Map<String, String> httpHeaders) {
+        this.httpHeaders = httpHeaders;
+    }
+
+    @Override
+    public String getContentType() {
+        return contentType.toContentTypeString();
+    }
+
+    @Override
+    public void setContentType(String contentType) {
+        this.contentType = ContentType.parse(contentType);
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public <T> void read(final Edm edm, final String resourcePath, final Map<String, String> queryParams, final Olingo4ResponseHandler<T> responseHandler) {
+        final String queryOptions = concatQueryParams(queryParams);
+        final UriInfo uriInfo = parseUri(edm, resourcePath, queryOptions);
+
+        execute(new HttpGet(createUri(resourcePath, queryOptions)), getResourceContentType(uriInfo), new AbstractFutureCallback<T>(responseHandler) {
+
+            @Override
+            public void onCompleted(HttpResponse result) throws IOException {
+                readContent(uriInfo, result.getEntity() != null ? result.getEntity().getContent() : null, responseHandler);
+            }
+
+        });
+    }
+
+    @Override
+    public void uread(final Edm edm, final String resourcePath, final Map<String, String> queryParams, final Olingo4ResponseHandler<InputStream> responseHandler) {
+        final String queryOptions = concatQueryParams(queryParams);
+        final UriInfo uriInfo = parseUri(edm, resourcePath, queryOptions);
+
+        execute(new HttpGet(createUri(resourcePath, queryOptions)), getResourceContentType(uriInfo), new AbstractFutureCallback<InputStream>(responseHandler) {
+
+            @Override
+            public void onCompleted(HttpResponse result) throws IOException {
+                InputStream responseStream = result.getEntity() != null ? result.getEntity().getContent() : null;
+                if (responseStream != null && result.getEntity() instanceof DecompressingEntity) {
+                    // In case of GZIP compression it's necessary to create
+                    // InputStream from the source byte array
+                    responseHandler.onResponse(new ByteArrayInputStream(IOUtils.toByteArray(responseStream)));
+                } else {
+                    responseHandler.onResponse(responseStream);
+                }
+            }
+        });
+    }
+
+    @Override
+    public <T> void create(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler) {
+        final UriInfo uriInfo = parseUri(edm, resourcePath, null);
+
+        writeContent(edm, new HttpPost(createUri(resourcePath, null)), uriInfo, data, responseHandler);
+    }
+
+    @Override
+    public <T> void update(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler) {
+        final UriInfo uriInfo = parseUri(edm, resourcePath, null);
+
+        writeContent(edm, new HttpPut(createUri(resourcePath, null)), uriInfo, data, responseHandler);
+    }
+
+    @Override
+    public void delete(String resourcePath, final Olingo4ResponseHandler<HttpStatusCode> responseHandler) {
+        execute(new HttpDelete(createUri(resourcePath)), contentType, new AbstractFutureCallback<HttpStatusCode>(responseHandler) {
+            @Override
+            public void onCompleted(HttpResponse result) {
+                final StatusLine statusLine = result.getStatusLine();
+                responseHandler.onResponse(HttpStatusCode.fromStatusCode(statusLine.getStatusCode()));
+            }
+        });
+    }
+
+    @Override
+    public <T> void patch(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler) {
+        final UriInfo uriInfo = parseUri(edm, resourcePath, null);
+
+        writeContent(edm, new HttpPatch(createUri(resourcePath, null)), uriInfo, data, responseHandler);
+    }
+
+    @Override
+    public <T> void merge(Edm edm, String resourcePath, Object data, Olingo4ResponseHandler<T> responseHandler) {
+        final UriInfo uriInfo = parseUri(edm, resourcePath, null);
+
+        writeContent(edm, new HttpMerge(createUri(resourcePath, null)), uriInfo, data, responseHandler);
+    }
+
+    @Override
+    public void batch(Edm edm, Object data, Olingo4ResponseHandler<List<Olingo4BatchResponse>> responseHandler) {
+        final UriInfo uriInfo = parseUri(edm, SegmentType.BATCH.getValue(), null);
+
+        writeContent(edm, new HttpPost(createUri(SegmentType.BATCH.getValue(), null)), uriInfo, data, responseHandler);
+    }
+
+    private ContentType getResourceContentType(UriInfo uriInfo) {
+        ContentType resourceContentType;
+        switch (uriInfo.getKind()) {
+        case service:
+            // service document
+            resourceContentType = SERVICE_DOCUMENT_CONTENT_TYPE;
+            break;
+        case metadata:
+            // metadata
+            resourceContentType = METADATA_CONTENT_TYPE;
+            break;
+        case resource:
+            List<UriResource> listResource = uriInfo.getUriResourceParts();
+            UriResourceKind lastResourceKind = listResource.get(listResource.size() - 1).getKind();
+            // is it a $value or $count URI??
+            if (lastResourceKind == UriResourceKind.count || lastResourceKind == UriResourceKind.value) {
+                resourceContentType = TEXT_PLAIN_WITH_CS_UTF_8;
+            } else {
+                resourceContentType = contentType;
+            }
+            break;
+        default:
+            resourceContentType = contentType;
+        }
+        return resourceContentType;
+    }
+
+    private <T> void readContent(UriInfo uriInfo, InputStream content, Olingo4ResponseHandler<T> responseHandler) {
+        try {
+            responseHandler.onResponse(this.<T> readContent(uriInfo, content));
+        } catch (ODataException e) {
+            responseHandler.onException(e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T readContent(UriInfo uriInfo, InputStream content) throws ODataException {
+        T response = null;
+        switch (uriInfo.getKind()) {
+        case service:
+            // service document
+            response = (T)odataReader.readServiceDocument(content, SERVICE_DOCUMENT_CONTENT_TYPE);
+            break;
+
+        case metadata:
+            // $metadata
+            response = (T)odataReader.readMetadata(content);
+            break;
+        case resource:
+            // any resource entity
+            List<UriResource> listResource = uriInfo.getUriResourceParts();
+            UriResourceKind lastResourceKind = listResource.get(listResource.size() - 1).getKind();
+            switch (lastResourceKind) {
+            case entitySet:
+                UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet)listResource.get(listResource.size() - 1);
+                List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
+                // Check result type: single Entity or EntitySet based
+                // on key predicate detection
+                if (keyPredicates.size() == 1) {
+                    response = (T)odataReader.readEntity(content, getResourceContentType(uriInfo));
+                } else {
+                    response = (T)odataReader.readEntitySet(content, getResourceContentType(uriInfo));
+                }
+                break;
+            case count:
+                String stringCount = null;
+                try {
+                    stringCount = IOUtils.toString(content, Consts.UTF_8);
+                    response = (T)Long.valueOf(stringCount);
+                } catch (IOException e) {
+                    throw new ODataException("Error during $count value deserialization", e);
+                } catch (NumberFormatException e) {
+                    throw new ODataException("Error during $count value conversion: " + stringCount, e);
+                }
+                break;
+            case value:
+                try {
+                    ClientPrimitiveValue value = odataClient.getObjectFactory().newPrimitiveValueBuilder().setType(EdmPrimitiveTypeKind.String)
+                        .setValue(IOUtils.toString(content, Consts.UTF_8)).build();
+                    response = (T)value;
+                } catch (IOException e) {
+                    throw new ODataException("Error during $value deserialization", e);
+                }
+                break;
+            case primitiveProperty:
+            case complexProperty:
+                ClientProperty property = odataReader.readProperty(content, getResourceContentType(uriInfo));
+                if (property.hasPrimitiveValue()) {
+                    response = (T)property.getPrimitiveValue();
+                } else if (property.hasComplexValue()) {
+                    response = (T)property.getComplexValue();
+                } else {
+                    throw new ODataException("Unsupported property: " + property.getName());
+                }
+                break;
+            case function:
+                UriResourceFunctionImpl uriResourceFunction = (UriResourceFunctionImpl)listResource.get(listResource.size() - 1);
+                EdmReturnType functionReturnType = uriResourceFunction.getFunction().getReturnType();
+
+                switch (functionReturnType.getType().getKind()) {
+                case ENTITY:
+                    if (functionReturnType.isCollection()) {
+                        response = (T)odataReader.readEntitySet(content, getResourceContentType(uriInfo));
+                    } else {
+                        response = (T)odataReader.readEntity(content, getResourceContentType(uriInfo));
+                    }
+                    break;
+                case PRIMITIVE:
+                case COMPLEX:
+                    ClientProperty functionProperty = odataReader.readProperty(content, getResourceContentType(uriInfo));
+                    if (functionProperty.hasPrimitiveValue()) {
+                        response = (T)functionProperty.getPrimitiveValue();
+                    } else if (functionProperty.hasComplexValue()) {
+                        response = (T)functionProperty.getComplexValue();
+                    } else {
+                        throw new ODataException("Unsupported property: " + functionProperty.getName());
+                    }
+                    break;
+                default:
+                    throw new ODataException("Unsupported function return type " + uriInfo.getKind().name());
+                }
+                break;
+            default:
+                throw new ODataException("Unsupported resource type: " + lastResourceKind.name());
+            }
+            break;
+
+        default:
+            throw new ODataException("Unsupported resource type " + uriInfo.getKind().name());
+        }
+
+        return response;
+    }
+
+    private <T> void writeContent(final Edm edm, HttpEntityEnclosingRequestBase httpEntityRequest, final UriInfo uriInfo, final Object content,
+                                  final Olingo4ResponseHandler<T> responseHandler) {
+
+        try {
+            httpEntityRequest.setEntity(writeContent(edm, uriInfo, content));
+
+            final Header requestContentTypeHeader = httpEntityRequest.getEntity().getContentType();
+            final ContentType requestContentType = requestContentTypeHeader != null ? ContentType.parse(requestContentTypeHeader.getValue()) : contentType;
+
+            execute(httpEntityRequest, requestContentType, new AbstractFutureCallback<T>(responseHandler) {
+                @SuppressWarnings("unchecked")
+                @Override
+                public void onCompleted(HttpResponse result) throws IOException, ODataException {
+
+                    // if a entity is created (via POST request) the response
+                    // body contains the new created entity
+                    HttpStatusCode statusCode = HttpStatusCode.fromStatusCode(result.getStatusLine().getStatusCode());
+
+                    // look for no content, or no response body!!!
+                    final boolean noEntity = result.getEntity() == null || result.getEntity().getContentLength() == 0;
+                    if (statusCode == HttpStatusCode.NO_CONTENT || noEntity) {
+                        responseHandler.onResponse((T)HttpStatusCode.fromStatusCode(result.getStatusLine().getStatusCode()));
+                    } else {
+                        if (uriInfo.getKind() == UriInfoKind.resource) {
+                            List<UriResource> listResource = uriInfo.getUriResourceParts();
+                            UriResourceKind lastResourceKind = listResource.get(listResource.size() - 1).getKind();
+                            switch (lastResourceKind) {
+                            case entitySet:
+                                if (content instanceof ClientEntity) {
+                                    ClientEntity entity = odataReader.readEntity(result.getEntity().getContent(),
+                                                                                 ContentType.parse(result.getEntity().getContentType().getValue()));
+                                    responseHandler.onResponse((T)entity);
+                                } else {
+                                    throw new ODataException("Unsupported content type: " + content);
+                                }
+                                break;
+                            default:
+                                break;
+                            }
+                        } else if (uriInfo.getKind() == UriInfoKind.batch) {
+                            List<Olingo4BatchResponse> batchResponse = parseBatchResponse(edm, result, (List<Olingo4BatchRequest>)content);
+                            responseHandler.onResponse((T)batchResponse);
+                        } else {
+                            throw new ODataException("Unsupported resource type: " + uriInfo.getKind().name());
+                        }
+                    }
+                }
+            });
+
+        } catch (ODataException e) {
+            responseHandler.onException(e);
+        }
+    }
+
+    private AbstractHttpEntity writeContent(final Edm edm, final UriInfo uriInfo, final Object content) throws ODataException {
+        InputStream requestStream = null;
+        AbstractHttpEntity httpEntity = null;
+        if (uriInfo.getKind() == UriInfoKind.resource) {
+            // any resource entity
+            List<UriResource> listResource = uriInfo.getUriResourceParts();
+            UriResourceKind lastResourceKind = listResource.get(listResource.size() - 1).getKind();
+            switch (lastResourceKind) {
+            case entitySet:
+                if (content instanceof ClientEntity) {
+                    requestStream = odataWriter.writeEntity((ClientEntity)content, getResourceContentType(uriInfo));
+                } else {
+                    throw new ODataException("Unsupported content type: " + content);
+                }
+                break;
+            default:
+                throw new ODataException("Unsupported resource type: " + lastResourceKind);
+            }
+            try {
+                httpEntity = new ByteArrayEntity(IOUtils.toByteArray(requestStream));
+            } catch (IOException e) {
+                throw new ODataException("Error during converting input stream to byte array", e);
+            }
+            httpEntity.setChunked(false);
+
+        } else if (uriInfo.getKind() == UriInfoKind.batch) {
+            final String boundary = BOUNDARY_PREFIX + UUID.randomUUID();
+            final String contentHeader = BATCH_CONTENT_TYPE + BOUNDARY_PARAMETER + boundary;
+            final List<Olingo4BatchRequest> batchParts = (List<Olingo4BatchRequest>)content;
+
+            requestStream = serializeBatchRequest(edm, batchParts, BOUNDARY_DOUBLE_DASH + boundary);
+            try {
+                httpEntity = new ByteArrayEntity(IOUtils.toByteArray(requestStream));
+            } catch (IOException e) {
+                throw new ODataException("Error during converting input stream to byte array", e);
+            }
+            httpEntity.setChunked(false);
+            httpEntity.setContentType(contentHeader);
+        } else {
+            throw new ODataException("Unsupported resource type: " + uriInfo.getKind().name());
+        }
+
+        return httpEntity;
+    }
+
+    private InputStream serializeBatchRequest(final Edm edm, final List<Olingo4BatchRequest> batchParts, String boundary) throws ODataException {
+        final ByteArrayOutputStream batchRequestHeaderOutputStream = new ByteArrayOutputStream();
+
+        try {
+            batchRequestHeaderOutputStream.write(boundary.getBytes(Constants.UTF8));
+            batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+
+            for (Olingo4BatchRequest batchPart : batchParts) {
+                writeHttpHeader(batchRequestHeaderOutputStream, HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_HTTP.toContentTypeString());
+                writeHttpHeader(batchRequestHeaderOutputStream, ODataBatchConstants.ITEM_TRANSFER_ENCODING_LINE, null);
+
+                if (batchPart instanceof Olingo4BatchQueryRequest) {
+                    final Olingo4BatchQueryRequest batchQueryPart = (Olingo4BatchQueryRequest)batchPart;
+                    final String batchQueryUri = createUri(StringUtils.isBlank(batchQueryPart.getResourceUri()) ? serviceUri : batchQueryPart.getResourceUri(),
+                                                           batchQueryPart.getResourcePath(), concatQueryParams(batchQueryPart.getQueryParams()));
+                    final UriInfo uriInfo = parseUri(edm, batchQueryPart.getResourcePath(), concatQueryParams(batchQueryPart.getQueryParams()));
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+
+                    batchRequestHeaderOutputStream.write((HttpGet.METHOD_NAME + " " + batchQueryUri + " " + HttpVersion.HTTP_1_1).getBytes(Constants.UTF8));
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                    writeHttpHeader(batchRequestHeaderOutputStream, HttpHeaders.ACCEPT, getResourceContentType(uriInfo).toContentTypeString());
+
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                    batchRequestHeaderOutputStream.write(boundary.getBytes(Constants.UTF8));
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                } else if (batchPart instanceof Olingo4BatchChangeRequest) {
+                    final Olingo4BatchChangeRequest batchChangePart = (Olingo4BatchChangeRequest)batchPart;
+                    final String batchChangeUri = createUri(StringUtils.isBlank(batchChangePart.getResourceUri()) ? serviceUri : batchChangePart.getResourceUri(),
+                                                            batchChangePart.getResourcePath(), null);
+                    final UriInfo uriInfo = parseUri(edm, batchChangePart.getResourcePath(), null);
+
+                    if (batchChangePart.getOperation() != Operation.DELETE) {
+                        writeHttpHeader(batchRequestHeaderOutputStream, CONTENT_ID_HEADER, batchChangePart.getContentId());
+                    }
+
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                    batchRequestHeaderOutputStream
+                        .write((batchChangePart.getOperation().getHttpMethod() + " " + batchChangeUri + " " + HttpVersion.HTTP_1_1).getBytes(Constants.UTF8));
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                    writeHttpHeader(batchRequestHeaderOutputStream, HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
+                    writeHttpHeader(batchRequestHeaderOutputStream, HttpHeaders.ACCEPT, getResourceContentType(uriInfo).toContentTypeString());
+                    writeHttpHeader(batchRequestHeaderOutputStream, HttpHeaders.CONTENT_TYPE, getResourceContentType(uriInfo).toContentTypeString());
+
+                    if (batchChangePart.getOperation() != Operation.DELETE) {
+                        batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                        AbstractHttpEntity httpEnity = writeContent(edm, uriInfo, batchChangePart.getBody());
+
+                        batchRequestHeaderOutputStream.write(IOUtils.toByteArray(httpEnity.getContent()));
+                        batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                        batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                    } else {
+                        batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                    }
+
+                    batchRequestHeaderOutputStream.write(boundary.getBytes(Constants.UTF8));
+                    batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
+                } else {
+                    throw new ODataException("Unsupported batch part request object type: " + batchPart);
+                }
+            }
+        } catch (Exception e) {
+            throw new ODataException("Error during batch request serialization", e);
+        }
+        return new ByteArrayInputStream(batchRequestHeaderOutputStream.toByteArray());
+    }
+
+    private void writeHttpHeader(ByteArrayOutputStream headerOutputStream, String headerName, String headerValue) throws IOException {
+        headerOutputStream.write(createHttpHeader(headerName, headerValue).getBytes(Constants.UTF8));
+        headerOutputStream.write(ODataStreamer.CRLF);
+    }
+
+    private String createHttpHeader(String headerName, String headerValue) {
+        return headerName + (StringUtils.isBlank(headerValue) ? "" : (": " + headerValue));
+    }
+
+    private List<Olingo4BatchResponse> parseBatchResponse(final Edm edm, HttpResponse response, List<Olingo4BatchRequest> batchRequest) throws ODataException {
+        List<Olingo4BatchResponse> batchResponse = new <Olingo4BatchResponse> ArrayList();
+        try {
+            final Header[] contentHeaders = response.getHeaders(HttpHeader.CONTENT_TYPE);
+            final ODataBatchLineIterator batchLineIterator = new ODataBatchLineIteratorImpl(IOUtils.lineIterator(response.getEntity().getContent(), Constants.UTF8));
+            final String batchBoundary = ODataBatchUtilities.getBoundaryFromHeader(getHeadersCollection(contentHeaders));
+            final ODataBatchController batchController = new ODataBatchController(batchLineIterator, batchBoundary);
+
+            batchController.getBatchLineIterator().next();
+            int batchRequestIndex = 0;
+            while (batchController.getBatchLineIterator().hasNext()) {
+                OutputStream os = new ByteArrayOutputStream();
+                ODataBatchUtilities.readBatchPart(batchController, os, false);
+                Object content = null;
+                final Olingo4BatchRequest batchPartRequest = (Olingo4BatchRequest)batchRequest.get(batchRequestIndex);
+                final HttpResponse batchPartHttpResponse = constructBatchPartHttpResponse(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()));
+                final StatusLine batchPartStatusLine = batchPartHttpResponse.getStatusLine();
+                final int batchPartLineStatusCode = batchPartStatusLine.getStatusCode();
+                Map<String, String> batchPartHeaders = getHeadersValueMap(batchPartHttpResponse.getAllHeaders());
+                if (batchPartRequest instanceof Olingo4BatchQueryRequest) {
+                    Olingo4BatchQueryRequest batchPartQueryRequest = (Olingo4BatchQueryRequest)batchPartRequest;
+                    final UriInfo uriInfo = parseUri(edm, batchPartQueryRequest.getResourcePath(), null);
+
+                    if (HttpStatusCode.BAD_REQUEST.getStatusCode() <= batchPartLineStatusCode && batchPartLineStatusCode <= AbstractFutureCallback.NETWORK_CONNECT_TIMEOUT_ERROR) {
+                        final ContentType responseContentType = ContentType.parse(batchPartHttpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+                        content = odataReader.readError(batchPartHttpResponse.getEntity().getContent(), responseContentType);
+                    } else if (batchPartLineStatusCode == HttpStatusCode.NO_CONTENT.getStatusCode()) {
+                        // nothing to do if NO_CONTENT returning
+                    } else {
+                        content = readContent(uriInfo, batchPartHttpResponse.getEntity().getContent());
+                    }
+
+                    Olingo4BatchResponse batchPartResponse = new Olingo4BatchResponse(batchPartStatusLine.getStatusCode(), batchPartStatusLine.getReasonPhrase(), null,
+                                                                                      batchPartHeaders, content);
+                    batchResponse.add(batchPartResponse);
+                } else if (batchPartRequest instanceof Olingo4BatchChangeRequest) {
+                    Olingo4BatchChangeRequest batchPartChangeRequest = (Olingo4BatchChangeRequest)batchPartRequest;
+
+                    if (batchPartLineStatusCode != HttpStatusCode.NO_CONTENT.getStatusCode()) {
+                        if (HttpStatusCode.BAD_REQUEST.getStatusCode() <= batchPartLineStatusCode
+                            && batchPartLineStatusCode <= AbstractFutureCallback.NETWORK_CONNECT_TIMEOUT_ERROR) {
+                            final ContentType responseContentType = ContentType.parse(batchPartHttpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+                            content = odataReader.readError(response.getEntity().getContent(), responseContentType);
+                        } else {
+                            final UriInfo uriInfo = parseUri(edm, batchPartChangeRequest.getResourcePath()
+                                                                  + (batchPartChangeRequest.getOperation() == Operation.CREATE ? CLIENT_ENTITY_FAKE_MARKER : ""),
+                                                             null);
+                            content = readContent(uriInfo, batchPartHttpResponse.getEntity().getContent());
+                        }
+                    }
+                    Olingo4BatchResponse batchPartResponse = new Olingo4BatchResponse(batchPartStatusLine.getStatusCode(), batchPartStatusLine.getReasonPhrase(),
+                                                                                      batchPartChangeRequest.getContentId(), batchPartHeaders, content);
+                    batchResponse.add(batchPartResponse);
+                } else {
+                    throw new ODataException("Unsupported batch part request object type: " + batchPartRequest);
+                }
+                batchRequestIndex++;
+            }
+
+        } catch (IOException | HttpException e) {
+            throw new ODataException(e);
+        }
+        return batchResponse;
+    }
+
+    private HttpResponse constructBatchPartHttpResponse(InputStream batchPartStream) throws IOException, HttpException {
+        final LineIterator lines = IOUtils.lineIterator(batchPartStream, Constants.UTF8);
+        final ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream();
+        final ByteArrayOutputStream bodyOutputStream = new ByteArrayOutputStream();
+
+        boolean startBatchPartHeader = false;
+        boolean startBatchPartBody = false;
+
+        // Iterate through lines in the batch part
+        while (lines.hasNext()) {
+            String line = lines.nextLine().trim();
+            // Ignore all lines below HTTP/1.1 line
+            if (line.startsWith(HttpVersion.HTTP)) {
+                // This is the first header line
+                startBatchPartHeader = true;
+            }
+            // Body starts with empty string after header lines
+            if (startBatchPartHeader && StringUtils.isBlank(line)) {
+                startBatchPartHeader = false;
+                startBatchPartBody = true;
+            }
+            if (startBatchPartHeader) {
+                // Write header to the output stream
+                headerOutputStream.write(line.getBytes(Constants.UTF8));
+                headerOutputStream.write(ODataStreamer.CRLF);
+            } else if (startBatchPartBody && StringUtils.isNotBlank(line)) {
+                // Write body to the output stream
+                bodyOutputStream.write(line.getBytes(Constants.UTF8));
+                bodyOutputStream.write(ODataStreamer.CRLF);
+            }
+        }
+
+        // Prepare for parsing headers in to the HttpResponse object
+        HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
+        SessionInputBufferImpl sessionInputBuffer = new SessionInputBufferImpl(metrics, 2048);
+        HttpResponseFactory responseFactory = new DefaultHttpResponseFactory();
+
+        sessionInputBuffer.bind(new ByteArrayInputStream(headerOutputStream.toByteArray()));
+        DefaultHttpResponseParser responseParser = new DefaultHttpResponseParser(sessionInputBuffer, new BasicLineParser(), responseFactory, MessageConstraints.DEFAULT);
+
+        // Parse HTTP response and headers
+        HttpResponse response = responseParser.parse();
+        // Set body inside entity
+        response.setEntity(new ByteArrayEntity(bodyOutputStream.toByteArray()));
+
+        return response;
+    }
+
+    private Collection<String> getHeadersCollection(Header[] headers) {
+        Collection<String> headersCollection = new ArrayList();
+        for (Header header : Arrays.asList(headers)) {
+            headersCollection.add(header.getValue());
+        }
+        return headersCollection;
+    }
+
+    private Map<String, String> getHeadersValueMap(Header[] headers) {
+        Map<String, String> headersValueMap = new HashMap();
+        for (Header header : Arrays.asList(headers)) {
+            headersValueMap.put(header.getName(), header.getValue());
+        }
+        return headersValueMap;
+    }
+
+    private String createUri(String resourcePath) {
+        return createUri(serviceUri, resourcePath, null);
+    }
+
+    private String createUri(String resourcePath, String queryOptions) {
+        return createUri(serviceUri, resourcePath, queryOptions);
+    }
+
+    private String createUri(String resourceUri, String resourcePath, String queryOptions) {
+
+        final StringBuilder absolutUri = new StringBuilder(resourceUri).append(SEPARATOR).append(resourcePath);
+        if (queryOptions != null && !queryOptions.isEmpty()) {
+            absolutUri.append("/?" + queryOptions);
+        }
+        return absolutUri.toString();
+
+    }
+
+    private String concatQueryParams(final Map<String, String> queryParams) {
+        final StringBuilder concatQuery = new StringBuilder("");
+        if (queryParams != null && !queryParams.isEmpty()) {
+            int nParams = queryParams.size();
+            int index = 0;
+            for (Map.Entry<String, String> entry : queryParams.entrySet()) {
+                concatQuery.append(entry.getKey()).append('=').append(entry.getValue());
+                if (++index < nParams) {
+                    concatQuery.append('&');
+                }
+            }
+        }
+        return concatQuery.toString().replaceAll("  *", "%20");
+    }
+
+    private static UriInfo parseUri(Edm edm, String resourcePath, String queryOptions) {
+        Parser parser = new Parser(edm, OData.newInstance());
+        UriInfo result;
+
+        try {
+            result = parser.parseUri(resourcePath, queryOptions, null);
+        } catch (UriParserException | UriValidationException e) {
+            throw new IllegalArgumentException("parseUri (" + resourcePath + "," + queryOptions + "): " + e.getMessage(), e);
+        }
+        return result;
+    }
+
+    public void execute(HttpUriRequest httpUriRequest, ContentType contentType, FutureCallback<HttpResponse> callback) {
+        // add accept header when its not a form or multipart
+        final String contentTypeString = contentType.toString();
+        if (!ContentType.APPLICATION_FORM_URLENCODED.equals(contentType) && !contentType.toContentTypeString().startsWith(MULTIPART_MIME_TYPE)) {
+            // otherwise accept what is being sent
+            httpUriRequest.addHeader(HttpHeaders.ACCEPT, contentTypeString);
+        }
+
+        // is something being sent?
+        if (httpUriRequest instanceof HttpEntityEnclosingRequestBase && httpUriRequest.getFirstHeader(HttpHeaders.CONTENT_TYPE) == null) {
+            httpUriRequest.addHeader(HttpHeaders.CONTENT_TYPE, contentTypeString);
+        }
+
+        // set user specified custom headers
+        if (httpHeaders != null && !httpHeaders.isEmpty()) {
+            for (Map.Entry<String, String> entry : httpHeaders.entrySet()) {
+                httpUriRequest.setHeader(entry.getKey(), entry.getValue());
+            }
+        }
+
+        // add 'Accept-Charset' header to avoid BOM marker presents inside
+        // response stream
+        if (!httpUriRequest.containsHeader(HttpHeaders.ACCEPT_CHARSET)) {
+            httpUriRequest.addHeader(HttpHeaders.ACCEPT_CHARSET, Constants.UTF8);
+        }
+
+        // add client protocol version if not specified
+        if (!httpUriRequest.containsHeader(HttpHeader.ODATA_VERSION)) {
+            httpUriRequest.addHeader(HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
+        }
+        if (!httpUriRequest.containsHeader(HttpHeader.ODATA_MAX_VERSION)) {
+            httpUriRequest.addHeader(HttpHeader.ODATA_MAX_VERSION, ODataServiceVersion.V40.toString());
+        }
+
+        // execute request
+        if (client instanceof CloseableHttpAsyncClient) {
+            ((CloseableHttpAsyncClient)client).execute(httpUriRequest, callback);
+        } else {
+            // invoke the callback methods explicitly after executing the
+            // request synchronously
+            try {
+                CloseableHttpResponse result = ((CloseableHttpClient)client).execute(httpUriRequest);
+                callback.completed(result);
+            } catch (IOException e) {
+                callback.failed(e);
+            }
+        }
+    }
+}