org.apache.camel.component.olingo2.Olingo2Endpoint Maven / Gradle / Ivy
/*
* 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.olingo2;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.camel.Category;
import org.apache.camel.Consumer;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.component.olingo2.internal.Olingo2ApiCollection;
import org.apache.camel.component.olingo2.internal.Olingo2ApiName;
import org.apache.camel.component.olingo2.internal.Olingo2Constants;
import org.apache.camel.component.olingo2.internal.Olingo2PropertiesHelper;
import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
import org.apache.camel.spi.PropertyConfigurer;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.support.PropertyBindingSupport;
import org.apache.camel.support.component.AbstractApiEndpoint;
import org.apache.camel.support.component.ApiMethod;
import org.apache.camel.support.component.ApiMethodPropertiesHelper;
/**
* Communicate with OData 2.0 services using Apache Olingo.
*/
@UriEndpoint(firstVersion = "2.14.0", scheme = "olingo2", title = "Olingo2", syntax = "olingo2:apiName/methodName",
apiSyntax = "apiName/methodName",
category = { Category.CLOUD }, headersClass = Olingo2Constants.class)
public class Olingo2Endpoint extends AbstractApiEndpoint {
protected static final String RESOURCE_PATH_PROPERTY = "resourcePath";
protected static final String RESPONSE_HANDLER_PROPERTY = "responseHandler";
protected static final String SERVICE_URI_PROPERTY = "serviceUri";
protected static final String FILTER_ALREADY_SEEN = "filterAlreadySeen";
private static final String KEY_PREDICATE_PROPERTY = "keyPredicate";
private static final String QUERY_PARAMS_PROPERTY = "queryParams";
private static final String ENDPOINT_HTTP_HEADERS_PROPERTY = "endpointHttpHeaders";
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 Set olingo2endpointPropertyNames;
@UriParam
private Olingo2Configuration configuration;
private Olingo2AppWrapper apiProxy;
public Olingo2Endpoint(String uri, Olingo2Component component, Olingo2ApiName apiName, String methodName,
Olingo2Configuration endpointConfiguration) {
super(uri, component, apiName, methodName, Olingo2ApiCollection.getCollection().getHelper(apiName),
endpointConfiguration);
this.configuration = endpointConfiguration;
}
@Override
public Producer createProducer() throws Exception {
return new Olingo2Producer(this);
}
@Override
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 Olingo2Consumer consumer = new Olingo2Consumer(this, processor);
consumer.setSplitResult(configuration.isSplitResult());
configureConsumer(consumer);
return consumer;
}
@Override
protected ApiMethodPropertiesHelper getPropertiesHelper() {
return Olingo2PropertiesHelper.getHelper(getCamelContext());
}
@Override
protected String getThreadProfileName() {
return Olingo2Constants.THREAD_PROFILE_NAME;
}
@Override
public void configureProperties(Map options) {
// filter out options that are with $ as they are for query
Map query = new LinkedHashMap<>();
Map known = new LinkedHashMap<>();
options.forEach((k, v) -> {
if (k.startsWith("$")) {
query.put(k, v);
} else {
known.put(k, v);
}
});
options.keySet().removeIf(known::containsKey);
// configure endpoint first (from the known options) and then specialized configuration class afterwards
PropertyConfigurer configurer = getComponent().getEndpointPropertyConfigurer();
if (configurer instanceof ExtendedPropertyConfigurerGetter) {
ExtendedPropertyConfigurerGetter getter = (ExtendedPropertyConfigurerGetter) configurer;
for (String name : getter.getAllOptions(this).keySet()) {
if (known.containsKey(name)) {
Object value = known.get(name);
boolean hit = configurer.configure(getCamelContext(), this, name, value, true);
if (hit) {
known.remove(name);
}
}
}
}
// configure on configuration first to be reflection free
configurer = getCamelContext().adapt(ExtendedCamelContext.class).getConfigurerResolver()
.resolvePropertyConfigurer(configuration.getClass().getName(), getCamelContext());
if (configurer != null) {
PropertyBindingSupport.build()
.withConfigurer(configurer)
.withIgnoreCase(true)
.withTarget(configuration)
.withCamelContext(getCamelContext())
.withProperties(known)
.withRemoveParameters(true)
.bind();
}
super.configureProperties(known);
if (!known.isEmpty()) {
// handle individual query params
query.putAll(known);
}
// and remove from original options as it was used by query
options.keySet().removeIf(query::containsKey);
// this will parse query and expand these $ keys into the actual query keys
parseQueryParams(query);
// and restore back to options
options.putAll(query);
}
@Override
protected void afterConfigureProperties() {
olingo2endpointPropertyNames
= new HashSet<>(getPropertiesHelper().getValidEndpointProperties(getCamelContext(), configuration));
olingo2endpointPropertyNames.add(EDM_PROPERTY);
olingo2endpointPropertyNames.add(ENDPOINT_HTTP_HEADERS_PROPERTY);
olingo2endpointPropertyNames.add(SERVICE_URI_PROPERTY);
olingo2endpointPropertyNames.add(FILTER_ALREADY_SEEN);
// 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 args) {
return apiProxy.getOlingo2App();
}
@Override
public Olingo2Component getComponent() {
return (Olingo2Component) 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 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 properties) {
Map endpointHttpHeaders = (Map) properties.get(ENDPOINT_HTTP_HEADERS_PROPERTY);
// read Edm if not set yet
properties.put(EDM_PROPERTY, apiProxy.getEdm(endpointHttpHeaders));
// handle filterAlreadySeen property
properties.put(FILTER_ALREADY_SEEN, configuration.isFilterAlreadySeen());
// 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 '"
+ Olingo2Constants.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 options) {
// extract non-endpoint properties as query params
final Map queryParams = new HashMap<>();
for (Iterator> it = options.entrySet().iterator(); it.hasNext();) {
final Map.Entry entry = it.next();
final String paramName = entry.getKey();
// avoid swallowing consumer scheduler properties, which get processed in configureProperties()
if (paramName.startsWith("consumer.")) {
continue;
}
if (!olingo2endpointPropertyNames.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 oldParams = (Map) 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);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy