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. +