org.apache.camel.component.bean.AbstractCamelInvocationHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of camel-core Show documentation
Show all versions of camel-core Show documentation
The Core Camel Java DSL based router
/**
* 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.bean;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.apache.camel.Body;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelExchangeException;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.ExchangeProperty;
import org.apache.camel.Header;
import org.apache.camel.Headers;
import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Producer;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.impl.DefaultExchange;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractCamelInvocationHandler implements InvocationHandler {
private static final Logger LOG = LoggerFactory.getLogger(CamelInvocationHandler.class);
private static final List EXCLUDED_METHODS = new ArrayList();
private static ExecutorService executorService;
protected final Endpoint endpoint;
protected final Producer producer;
static {
// exclude all java.lang.Object methods as we dont want to invoke them
EXCLUDED_METHODS.addAll(Arrays.asList(Object.class.getMethods()));
}
public AbstractCamelInvocationHandler(Endpoint endpoint, Producer producer) {
this.endpoint = endpoint;
this.producer = producer;
}
private static Object getBody(Exchange exchange, Class type) throws InvalidPayloadException {
// get the body from the Exchange from either OUT or IN
if (exchange.hasOut()) {
if (exchange.getOut().getBody() != null) {
return exchange.getOut().getMandatoryBody(type);
} else {
return null;
}
} else {
if (exchange.getIn().getBody() != null) {
return exchange.getIn().getMandatoryBody(type);
} else {
return null;
}
}
}
@Override
public final Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if (isValidMethod(method)) {
return doInvokeProxy(proxy, method, args);
} else {
// invalid method then invoke methods on this instead
if ("toString".equals(method.getName())) {
return this.toString();
} else if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else if ("equals".equals(method.getName())) {
return Boolean.FALSE;
}
return null;
}
}
public abstract Object doInvokeProxy(final Object proxy, final Method method, final Object[] args) throws Throwable;
@SuppressWarnings("unchecked")
protected Object invokeProxy(final Method method, final ExchangePattern pattern, Object[] args, boolean binding) throws Throwable {
final Exchange exchange = new DefaultExchange(endpoint, pattern);
if (binding) {
// in binding mode we bind the passed in arguments (args) to the created exchange
// using the existing Camel @Body, @Header, @Headers, @ExchangeProperty annotations
// if no annotation then its bound as the message body
int index = 0;
for (Annotation[] row : method.getParameterAnnotations()) {
Object value = args[index];
if (row == null || row.length == 0) {
// assume its message body when there is no annotations
exchange.getIn().setBody(value);
} else {
for (Annotation ann : row) {
if (ann.annotationType().isAssignableFrom(Header.class)) {
Header header = (Header) ann;
String name = header.value();
exchange.getIn().setHeader(name, value);
} else if (ann.annotationType().isAssignableFrom(Headers.class)) {
Map map = exchange.getContext().getTypeConverter().tryConvertTo(Map.class, exchange, value);
if (map != null) {
exchange.getIn().getHeaders().putAll(map);
}
} else if (ann.annotationType().isAssignableFrom(ExchangeProperty.class)) {
ExchangeProperty ep = (ExchangeProperty) ann;
String name = ep.value();
exchange.setProperty(name, value);
} else if (ann.annotationType().isAssignableFrom(Body.class)) {
exchange.getIn().setBody(value);
} else {
// assume its message body when there is no annotations
exchange.getIn().setBody(value);
}
}
}
index++;
}
} else {
// no binding so use the old behavior with BeanInvocation as the body
BeanInvocation invocation = new BeanInvocation(method, args);
exchange.getIn().setBody(invocation);
}
if (binding) {
LOG.trace("Binding to service interface as @Body,@Header,@ExchangeProperty detected when calling proxy method: {}", method);
} else {
LOG.trace("No binding to service interface as @Body,@Header,@ExchangeProperty not detected. Using BeanInvocation as message body when calling proxy method: {}");
}
return doInvoke(method, exchange);
}
protected Object invokeWithBody(final Method method, Object body, final ExchangePattern pattern) throws Throwable {
final Exchange exchange = new DefaultExchange(endpoint, pattern);
exchange.getIn().setBody(body);
return doInvoke(method, exchange);
}
protected Object doInvoke(final Method method, final Exchange exchange) throws Throwable {
// is the return type a future
final boolean isFuture = method.getReturnType() == Future.class;
// create task to execute the proxy and gather the reply
FutureTask