org.apache.camel.impl.engine.CamelPostProcessorHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of camel-base-engine Show documentation
Show all versions of camel-base-engine Show documentation
The Base Engine Camel Framework
The newest version!
/*
* 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.impl.engine;
import java.io.Closeable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.camel.BeanConfigInject;
import org.apache.camel.BeanInject;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.Consume;
import org.apache.camel.Consumer;
import org.apache.camel.ConsumerTemplate;
import org.apache.camel.DelegateEndpoint;
import org.apache.camel.Endpoint;
import org.apache.camel.FluentProducerTemplate;
import org.apache.camel.IsSingleton;
import org.apache.camel.MultipleConsumersSupport;
import org.apache.camel.NoSuchBeanTypeException;
import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.PollingConsumer;
import org.apache.camel.Producer;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.PropertyInject;
import org.apache.camel.ProxyInstantiationException;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.Service;
import org.apache.camel.TypeConverter;
import org.apache.camel.spi.BeanProxyFactory;
import org.apache.camel.spi.PropertiesComponent;
import org.apache.camel.spi.PropertyConfigurer;
import org.apache.camel.spi.Registry;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.PluginHelper;
import org.apache.camel.support.PropertyBindingSupport;
import org.apache.camel.support.service.ServiceHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.camel.support.ObjectHelper.invokeMethod;
/**
* A helper class for Camel based injector or bean post-processing hooks.
*/
public class CamelPostProcessorHelper implements CamelContextAware {
private static final Logger LOG = LoggerFactory.getLogger(CamelPostProcessorHelper.class);
private CamelContext camelContext;
public CamelPostProcessorHelper() {
}
public CamelPostProcessorHelper(CamelContext camelContext) {
this.setCamelContext(camelContext);
}
@Override
public CamelContext getCamelContext() {
return camelContext;
}
@Override
public void setCamelContext(CamelContext camelContext) {
this.camelContext = camelContext;
}
public void consumerInjection(Method method, Object bean, String beanName) {
Consume consume = method.getAnnotation(Consume.class);
if (consume != null) {
LOG.debug("Creating a consumer for: {}", consume);
subscribeMethod(method, bean, beanName, consume.value(), consume.property(), consume.predicate());
}
}
public void subscribeMethod(
Method method, Object bean, String beanName, String endpointUri, String endpointProperty, String predicate) {
// lets bind this method to a listener
String injectionPointName = method.getName();
Endpoint endpoint = getEndpointInjection(bean, endpointUri, endpointProperty, injectionPointName, true);
if (endpoint != null) {
boolean multipleConsumer = false;
if (endpoint instanceof MultipleConsumersSupport consumersSupport) {
multipleConsumer = consumersSupport.isMultipleConsumersSupported();
}
try {
SubscribeMethodProcessor processor = getConsumerProcessor(endpoint);
// if multiple consumer then create a new consumer per subscribed method
if (multipleConsumer || processor == null) {
// create new processor and new consumer which happens the first time
processor = new SubscribeMethodProcessor(endpoint);
// make sure processor is registered in registry so we can reuse it (eg we can look it up)
endpoint.getCamelContext().addService(processor, true);
processor.addMethod(bean, method, endpoint, predicate);
Consumer consumer = endpoint.createConsumer(processor);
startService(consumer, endpoint.getCamelContext(), bean, beanName);
} else {
// add method to existing processor
processor.addMethod(bean, method, endpoint, predicate);
}
if (predicate != null) {
LOG.debug("Subscribed method: {} to consume from endpoint: {} with predicate: {}", method, endpoint,
predicate);
} else {
LOG.debug("Subscribed method: {} to consume from endpoint: {}", method, endpoint);
}
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
}
/**
* Stats the given service
*/
protected void startService(Service service, CamelContext camelContext, Object bean, String beanName) throws Exception {
// defer starting the service until CamelContext has started all its initial services
if (camelContext != null) {
camelContext.deferStartService(service, true);
} else {
// mo CamelContext then start service manually
ServiceHelper.startService(service);
}
boolean singleton = isSingleton(bean, beanName);
if (!singleton) {
LOG.debug("Service is not singleton so you must remember to stop it manually {}", service);
}
}
protected SubscribeMethodProcessor getConsumerProcessor(Endpoint endpoint) {
Set processors = endpoint.getCamelContext().hasServices(SubscribeMethodProcessor.class);
return processors.stream().filter(s -> s.getEndpoint() == endpoint).findFirst().orElse(null);
}
public Endpoint getEndpointInjection(
Object bean, String uri, String propertyName,
String injectionPointName, boolean mandatory) {
Endpoint answer;
if (ObjectHelper.isEmpty(uri)) {
// if no uri then fallback and try the endpoint property
answer = doGetEndpointInjection(bean, propertyName, injectionPointName);
} else {
answer = doGetEndpointInjection(uri, injectionPointName, mandatory);
}
// it may be a delegate endpoint via ref component
if (answer instanceof DelegateEndpoint delegateEndpoint) {
answer = delegateEndpoint.getEndpoint();
}
return answer;
}
private Endpoint doGetEndpointInjection(String uri, String injectionPointName, boolean mandatory) {
return CamelContextHelper.getEndpointInjection(getCamelContext(), uri, injectionPointName, mandatory);
}
/**
* Gets the injection endpoint from a bean property.
*
* @param bean the bean
* @param propertyName the property name on the bean
*/
private Endpoint doGetEndpointInjection(Object bean, String propertyName, String injectionPointName) {
// fall back and use the method name if no explicit property name was given
if (ObjectHelper.isEmpty(propertyName)) {
propertyName = injectionPointName;
}
// we have a property name, try to lookup a getter method on the bean with that name using this strategy
// 1. first the getter with the name as given
// 2. then the getter with Endpoint as postfix
// 3. then if start with on then try step 1 and 2 again, but omit the on prefix
try {
Object value = PluginHelper.getBeanIntrospection(getCamelContext()).getOrElseProperty(bean,
propertyName, null, false);
if (value == null) {
// try endpoint as postfix
value = PluginHelper.getBeanIntrospection(getCamelContext()).getOrElseProperty(bean,
propertyName + "Endpoint", null, false);
}
if (value == null && propertyName.startsWith("on")) {
// retry but without the on as prefix
propertyName = propertyName.substring(2);
return doGetEndpointInjection(bean, propertyName, injectionPointName);
}
if (value == null) {
return null;
} else if (value instanceof Endpoint endpoint) {
return endpoint;
} else {
String uriOrRef = getCamelContext().getTypeConverter().mandatoryConvertTo(String.class, value);
return getCamelContext().getEndpoint(uriOrRef);
}
} catch (Exception e) {
throw new IllegalArgumentException(
"Error getting property " + propertyName + " from bean " + bean + " due " + e.getMessage(), e);
}
}
/**
* Creates the object to be injected for an {@link org.apache.camel.EndpointInject} or
* {@link org.apache.camel.Produce} injection point
*/
public Object getInjectionValue(
Class> type, String endpointUri, String endpointProperty,
String injectionPointName, Object bean, String beanName) {
return getInjectionValue(type, endpointUri, endpointProperty, injectionPointName, bean, beanName, true);
}
/**
* Creates the object to be injected for an {@link org.apache.camel.EndpointInject} or
* {@link org.apache.camel.Produce} injection point
*/
@SuppressWarnings("unchecked")
public Object getInjectionValue(
Class> type, String endpointUri, String endpointProperty,
String injectionPointName, Object bean, String beanName, boolean binding) {
if (type.isAssignableFrom(ProducerTemplate.class)) {
return createInjectionProducerTemplate(endpointUri, endpointProperty, injectionPointName, bean);
} else if (type.isAssignableFrom(FluentProducerTemplate.class)) {
return createInjectionFluentProducerTemplate(endpointUri, endpointProperty, injectionPointName, bean);
} else if (type.isAssignableFrom(ConsumerTemplate.class)) {
return createInjectionConsumerTemplate(endpointUri, endpointProperty, injectionPointName);
} else {
Endpoint endpoint = getEndpointInjection(bean, endpointUri, endpointProperty, injectionPointName, true);
if (endpoint != null) {
if (type.isInstance(endpoint)) {
return endpoint;
} else if (type.isAssignableFrom(Producer.class)) {
return createInjectionProducer(endpoint, bean, beanName);
} else if (type.isAssignableFrom(PollingConsumer.class)) {
return createInjectionPollingConsumer(endpoint, bean, beanName);
} else if (type.isInterface()) {
// lets create a proxy
try {
// use proxy service
BeanProxyFactory factory = PluginHelper.getBeanProxyFactory(endpoint.getCamelContext());
return factory.createProxy(endpoint, binding, type);
} catch (Exception e) {
throw createProxyInstantiationRuntimeException(type, endpoint, e);
}
} else {
throw new IllegalArgumentException(
"Invalid type: " + type.getName()
+ " which cannot be injected via @EndpointInject/@Produce for: "
+ endpoint);
}
}
return null;
}
}
public Object getInjectionPropertyValue(
Class> type, Type genericType, String propertyName, String propertyDefaultValue, String separator) {
try {
String key;
String prefix = PropertiesComponent.PREFIX_TOKEN;
String suffix = PropertiesComponent.SUFFIX_TOKEN;
if (!propertyName.contains(prefix)) {
// must enclose the property name with prefix/suffix to have it resolved
key = prefix + propertyName + suffix;
} else {
// key has already prefix/suffix so use it as-is as it may be a compound key
key = propertyName;
}
String value = getCamelContext().resolvePropertyPlaceholders(key);
if (value != null) {
if (separator != null && !separator.isBlank()) {
Object values = convertValueUsingSeparator(camelContext, type, genericType, value, separator);
return getCamelContext().getTypeConverter().mandatoryConvertTo(type, values);
}
return getCamelContext().getTypeConverter().mandatoryConvertTo(type, value);
} else {
return null;
}
} catch (Exception e) {
if (ObjectHelper.isNotEmpty(propertyDefaultValue)) {
try {
if (separator != null && !separator.isBlank()) {
Object values
= convertValueUsingSeparator(camelContext, type, genericType, propertyDefaultValue, separator);
return getCamelContext().getTypeConverter().mandatoryConvertTo(type, values);
}
return getCamelContext().getTypeConverter().mandatoryConvertTo(type, propertyDefaultValue);
} catch (Exception e2) {
throw RuntimeCamelException.wrapRuntimeCamelException(e2);
}
}
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
private static Object convertValueUsingSeparator(
CamelContext camelContext, Class> type, Type genericType,
String value, String separator)
throws NoTypeConversionAvailableException {
if (type.isArray()) {
return convertArrayUsingSeparator(camelContext, type, value, separator);
} else if (Collection.class.isAssignableFrom(type)) {
return convertCollectionUsingSeparator(camelContext, type, genericType, value, separator);
} else if (Map.class.isAssignableFrom(type)) {
return convertMapUsingSeparator(camelContext, genericType, value, separator);
} else {
return null;
}
}
private static Map convertMapUsingSeparator(
CamelContext camelContext, Type genericType, String value, String separator)
throws NoTypeConversionAvailableException {
Class> ct = Object.class;
if (genericType != null) {
String name = StringHelper.between(genericType.getTypeName(), "<", ">");
name = StringHelper.afterLast(name, ",");
if (name != null) {
Class> clazz = camelContext.getClassResolver().resolveClass(name.trim());
if (clazz != null) {
ct = clazz;
}
}
}
Map values = new LinkedHashMap<>();
String[] arr = value.split(separator);
for (String s : arr) {
String v = s.trim(); // trim values as user may have whitespace noise
if (v.contains("=")) {
String k = StringHelper.before(v, "=").trim();
String e = StringHelper.after(v, "=").trim();
values.put(k, camelContext.getTypeConverter().mandatoryConvertTo(ct, e));
}
}
return values;
}
private static Collection> convertCollectionUsingSeparator(
CamelContext camelContext, Class> type, Type genericType, String value, String separator)
throws NoTypeConversionAvailableException {
Class> ct = Object.class;
if (genericType != null) {
String name = StringHelper.between(genericType.getTypeName(), "<", ">");
if (name != null) {
Class> clazz = camelContext.getClassResolver().resolveClass(name.trim());
if (clazz != null) {
ct = clazz;
}
}
}
boolean set = type.isAssignableFrom(Set.class);
Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy