You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by cs...@apache.org on 2011/10/24 16:51:13 UTC
svn commit: r1188162 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/component/bean/
test/java/org/apache/camel/component/bean/pojomessage/
Author: cschneider
Date: Mon Oct 24 14:51:12 2011
New Revision: 1188162
URL: http://svn.apache.org/viewvc?rev=1188162&view=rev
Log:
CAMEL-4565 Code and tests for sending simple objects from a dynamic proxy
Added:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java (with props)
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java (with props)
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java (with props)
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java (with props)
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java (with props)
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java (with props)
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java?rev=1188162&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java Mon Oct 24 14:51:12 2011
@@ -0,0 +1,217 @@
+/**
+ * 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.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+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.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.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 transient Logger LOG = LoggerFactory.getLogger(CamelInvocationHandler.class);
+ private static ExecutorService executorService;
+ protected final Endpoint endpoint;
+ protected final Producer producer;
+
+ public AbstractCamelInvocationHandler(Endpoint endpoint, Producer producer) {
+ super();
+ 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;
+ }
+ }
+ }
+
+ protected Object invokeWithbody(final Method method, Object body, final ExchangePattern pattern) throws InterruptedException, Throwable {
+ final Exchange exchange = new DefaultExchange(endpoint, pattern);
+ exchange.getIn().setBody(body);
+
+ // is the return type a future
+ final boolean isFuture = method.getReturnType() == Future.class;
+
+ // create task to execute the proxy and gather the reply
+ FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
+ public Object call() throws Exception {
+ // process the exchange
+ LOG.trace("Proxied method call {} invoking producer: {}", method.getName(), producer);
+ producer.process(exchange);
+
+ Object answer = afterInvoke(method, exchange, pattern, isFuture);
+ LOG.trace("Proxied method call {} returning: {}", method.getName(), answer);
+ return answer;
+ }
+ });
+
+ if (isFuture) {
+ // submit task and return future
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Submitting task for exchange id {}", exchange.getExchangeId());
+ }
+ getExecutorService(exchange.getContext()).submit(task);
+ return task;
+ } else {
+ // execute task now
+ try {
+ task.run();
+ return task.get();
+ } catch (ExecutionException e) {
+ // we don't want the wrapped exception from JDK
+ throw e.getCause();
+ }
+ }
+ }
+
+ protected Object afterInvoke(Method method, Exchange exchange, ExchangePattern pattern, boolean isFuture) throws Exception {
+ // check if we had an exception
+ Throwable cause = exchange.getException();
+ if (cause != null) {
+ Throwable found = findSuitableException(cause, method);
+ if (found != null) {
+ if (found instanceof Exception) {
+ throw (Exception)found;
+ } else {
+ // wrap as exception
+ throw new CamelExchangeException("Error processing exchange", exchange, cause);
+ }
+ }
+ // special for runtime camel exceptions as they can be nested
+ if (cause instanceof RuntimeCamelException) {
+ // if the inner cause is a runtime exception we can throw it
+ // directly
+ if (cause.getCause() instanceof RuntimeException) {
+ throw (RuntimeException)((RuntimeCamelException)cause).getCause();
+ }
+ throw (RuntimeCamelException)cause;
+ }
+ // okay just throw the exception as is
+ if (cause instanceof Exception) {
+ throw (Exception)cause;
+ } else {
+ // wrap as exception
+ throw new CamelExchangeException("Error processing exchange", exchange, cause);
+ }
+ }
+
+ Class<?> to = isFuture ? getGenericType(exchange.getContext(), method.getGenericReturnType()) : method.getReturnType();
+
+ // do not return a reply if the method is VOID
+ if (to == Void.TYPE) {
+ return null;
+ }
+
+ return getBody(exchange, to);
+ }
+
+ protected static Class<?> getGenericType(CamelContext context, Type type) throws ClassNotFoundException {
+ if (type == null) {
+ // fallback and use object
+ return Object.class;
+ }
+
+ // unfortunately java dont provide a nice api for getting the generic
+ // type of the return type
+ // due type erasure, so we have to gather it based on a String
+ // representation
+ String name = ObjectHelper.between(type.toString(), "<", ">");
+ if (name != null) {
+ if (name.contains("<")) {
+ // we only need the outer type
+ name = ObjectHelper.before(name, "<");
+ }
+ return context.getClassResolver().resolveMandatoryClass(name);
+ } else {
+ // fallback and use object
+ return Object.class;
+ }
+ }
+
+ protected static synchronized ExecutorService getExecutorService(CamelContext context) {
+ // CamelContext will shutdown thread pool when it shutdown so we can
+ // lazy create it on demand
+ // but in case of hot-deploy or the likes we need to be able to
+ // re-create it (its a shared static instance)
+ if (executorService == null || executorService.isTerminated() || executorService.isShutdown()) {
+ // try to lookup a pool first based on id/profile
+ executorService = context.getExecutorServiceStrategy().lookup(CamelInvocationHandler.class, "CamelInvocationHandler", "CamelInvocationHandler");
+ if (executorService == null) {
+ executorService = context.getExecutorServiceStrategy().newDefaultThreadPool(CamelInvocationHandler.class, "CamelInvocationHandler");
+ }
+ }
+ return executorService;
+ }
+
+ /**
+ * Tries to find the best suited exception to throw.
+ * <p/>
+ * It looks in the exception hierarchy from the caused exception and matches
+ * this against the declared exceptions being thrown on the method.
+ *
+ * @param cause the caused exception
+ * @param method the method
+ * @return the exception to throw, or <tt>null</tt> if not possible to find
+ * a suitable exception
+ */
+ protected Throwable findSuitableException(Throwable cause, Method method) {
+ if (method.getExceptionTypes() == null || method.getExceptionTypes().length == 0) {
+ return null;
+ }
+
+ // see if there is any exception which matches the declared exception on
+ // the method
+ for (Class<?> type : method.getExceptionTypes()) {
+ Object fault = ObjectHelper.getException(type, cause);
+ if (fault != null) {
+ return Throwable.class.cast(fault);
+ }
+ }
+
+ return null;
+ }
+
+}
Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java?rev=1188162&r1=1188161&r2=1188162&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java Mon Oct 24 14:51:12 2011
@@ -18,213 +18,30 @@ package org.apache.camel.component.bean;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-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.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.InvalidPayloadException;
import org.apache.camel.Producer;
-import org.apache.camel.RuntimeCamelException;
-import org.apache.camel.util.ObjectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
- * An {@link java.lang.reflect.InvocationHandler} which invokes a
- * message exchange on a camel {@link Endpoint}
- *
- * @version
+ * An {@link java.lang.reflect.InvocationHandler} which invokes a message
+ * exchange on a camel {@link Endpoint}
+ *
+ * @version
*/
-public class CamelInvocationHandler implements InvocationHandler {
- private static final transient Logger LOG = LoggerFactory.getLogger(CamelInvocationHandler.class);
-
- // use a static thread pool to not create a new thread pool for each invocation
- private static ExecutorService executorService;
-
- private final Endpoint endpoint;
- private final Producer producer;
+public class CamelInvocationHandler extends AbstractCamelInvocationHandler implements InvocationHandler {
private final MethodInfoCache methodInfoCache;
public CamelInvocationHandler(Endpoint endpoint, Producer producer, MethodInfoCache methodInfoCache) {
- this.endpoint = endpoint;
- this.producer = producer;
+ super(endpoint, producer);
this.methodInfoCache = methodInfoCache;
}
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
BeanInvocation invocation = new BeanInvocation(method, args);
MethodInfo methodInfo = methodInfoCache.getMethodInfo(method);
-
final ExchangePattern pattern = methodInfo != null ? methodInfo.getPattern() : ExchangePattern.InOut;
- final Exchange exchange = endpoint.createExchange(pattern);
- exchange.getIn().setBody(invocation);
-
- // is the return type a future
- final boolean isFuture = method.getReturnType() == Future.class;
-
- // create task to execute the proxy and gather the reply
- FutureTask task = new FutureTask<Object>(new Callable<Object>() {
- public Object call() throws Exception {
- // process the exchange
- LOG.trace("Proxied method call {} invoking producer: {}", method.getName(), producer);
- producer.process(exchange);
-
- Object answer = afterInvoke(method, exchange, pattern, isFuture);
- LOG.trace("Proxied method call {} returning: {}", method.getName(), answer);
- return answer;
- }
- });
-
- if (isFuture) {
- // submit task and return future
- if (LOG.isTraceEnabled()) {
- LOG.trace("Submitting task for exchange id {}", exchange.getExchangeId());
- }
- getExecutorService(exchange.getContext()).submit(task);
- return task;
- } else {
- // execute task now
- try {
- task.run();
- return task.get();
- } catch (ExecutionException e) {
- // we don't want the wrapped exception from JDK
- throw e.getCause();
- }
- }
- }
-
- protected Object afterInvoke(Method method, Exchange exchange, ExchangePattern pattern, boolean isFuture) throws Exception {
- // check if we had an exception
- Throwable cause = exchange.getException();
- if (cause != null) {
- Throwable found = findSuitableException(cause, method);
- if (found != null) {
- if (found instanceof Exception) {
- throw (Exception) found;
- } else {
- // wrap as exception
- throw new CamelExchangeException("Error processing exchange", exchange, cause);
- }
- }
- // special for runtime camel exceptions as they can be nested
- if (cause instanceof RuntimeCamelException) {
- // if the inner cause is a runtime exception we can throw it directly
- if (cause.getCause() instanceof RuntimeException) {
- throw (RuntimeException) ((RuntimeCamelException) cause).getCause();
- }
- throw (RuntimeCamelException) cause;
- }
- // okay just throw the exception as is
- if (cause instanceof Exception) {
- throw (Exception) cause;
- } else {
- // wrap as exception
- throw new CamelExchangeException("Error processing exchange", exchange, cause);
- }
- }
-
- // do not return a reply if the method is VOID
- Class<?> to = method.getReturnType();
- if (to == Void.TYPE) {
- return null;
- }
-
- // use type converter so we can convert output in the desired type defined by the method
- // and let it be mandatory so we know wont return null if we cant convert it to the defined type
- Object answer;
- if (!isFuture) {
- answer = getBody(exchange, to);
- } else {
- // if its a Future then we need to extract the class from the future type so we know
- // which class to return the result as
- Class<?> returnTo = getGenericType(exchange.getContext(), method.getGenericReturnType());
- answer = getBody(exchange, returnTo);
- }
-
- return answer;
- }
-
- 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;
- }
- }
- }
-
- protected static Class getGenericType(CamelContext context, Type type) throws ClassNotFoundException {
- if (type == null) {
- // fallback and use object
- return Object.class;
- }
-
- // unfortunately java dont provide a nice api for getting the generic type of the return type
- // due type erasure, so we have to gather it based on a String representation
- String name = ObjectHelper.between(type.toString(), "<", ">");
- if (name != null) {
- if (name.contains("<")) {
- // we only need the outer type
- name = ObjectHelper.before(name, "<");
- }
- return context.getClassResolver().resolveMandatoryClass(name);
- } else {
- // fallback and use object
- return Object.class;
- }
- }
-
- /**
- * Tries to find the best suited exception to throw.
- * <p/>
- * It looks in the exception hierarchy from the caused exception and matches this against the declared exceptions
- * being thrown on the method.
- *
- * @param cause the caused exception
- * @param method the method
- * @return the exception to throw, or <tt>null</tt> if not possible to find a suitable exception
- */
- protected Throwable findSuitableException(Throwable cause, Method method) {
- if (method.getExceptionTypes() == null || method.getExceptionTypes().length == 0) {
- return null;
- }
-
- // see if there is any exception which matches the declared exception on the method
- for (Class<?> type : method.getExceptionTypes()) {
- Object fault = ObjectHelper.getException(type, cause);
- if (fault != null) {
- return Throwable.class.cast(fault);
- }
- }
-
- return null;
- }
-
- protected static synchronized ExecutorService getExecutorService(CamelContext context) {
- // CamelContext will shutdown thread pool when it shutdown so we can lazy create it on demand
- // but in case of hot-deploy or the likes we need to be able to re-create it (its a shared static instance)
- if (executorService == null || executorService.isTerminated() || executorService.isShutdown()) {
- executorService = context.getExecutorServiceManager().newDefaultThreadPool(CamelInvocationHandler.class, "CamelInvocationHandler");
- }
- return executorService;
+ return invokeWithbody(method, invocation, pattern);
}
}
-
Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java?rev=1188162&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java Mon Oct 24 14:51:12 2011
@@ -0,0 +1,48 @@
+/**
+ * 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.reflect.Method;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Producer;
+import org.apache.camel.RuntimeCamelException;
+
+/**
+ * Special InvocationHandler for methods that have only one parameter. This
+ * parameter is directly sent to as the body of the message. The idea is to use
+ * that as a very open message format especially when combined with e.g. JAXB
+ * serialization.
+ */
+public class PojoMessageInvocationHandler extends AbstractCamelInvocationHandler {
+ public PojoMessageInvocationHandler(Endpoint endpoint, Producer producer) {
+ super(endpoint, producer);
+ }
+
+ public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+ int argsLength = (args == null) ? 0 : args.length;
+ if (argsLength != 1) {
+ throw new RuntimeCamelException(String.format("Error creating proxy for %s.%s Number of arguments must be 1 but is %d",
+ method.getDeclaringClass().getName(),
+ method.getName(), argsLength));
+ }
+ final ExchangePattern pattern = method.getReturnType() != Void.TYPE ? ExchangePattern.InOut : ExchangePattern.InOnly;
+ return invokeWithbody(method, args[0], pattern);
+ }
+
+}
Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java?rev=1188162&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java Mon Oct 24 14:51:12 2011
@@ -0,0 +1,40 @@
+/**
+ * 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.reflect.Proxy;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Producer;
+import org.apache.camel.util.ServiceHelper;
+
+/**
+ * Create a dynamic proxy for a given interface and endpoint that sends the parameter object to the endpoint and optionally
+ * receives a reply. Unlike the ProxyHelper this works only with methods that have only one parameter.
+ */
+public final class PojoProxyHelper {
+ private PojoProxyHelper() {
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T createProxy(Endpoint endpoint, Class<?>... interfaceClasses) throws Exception {
+ Producer producer = endpoint.createProducer();
+ // ensure the producer is started
+ ServiceHelper.startService(producer);
+ return (T)Proxy.newProxyInstance(ProxyHelper.getClassLoader(interfaceClasses), interfaceClasses.clone(), new PojoMessageInvocationHandler(endpoint, producer));
+ }
+}
Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java?rev=1188162&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java Mon Oct 24 14:51:12 2011
@@ -0,0 +1,33 @@
+/**
+ * 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.pojomessage;
+
+public class Person {
+ String name;
+
+ public Person() {
+ }
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}
\ No newline at end of file
Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java?rev=1188162&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java Mon Oct 24 14:51:12 2011
@@ -0,0 +1,73 @@
+/**
+ * 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.pojomessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Endpoint;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.bean.PojoProxyHelper;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Test;
+
+public class PojoProxyHelperOneWayTest extends ContextTestSupport {
+
+ PersonReceiver receiver = new PersonReceiver();
+
+ @Test
+ public void testOneWay() throws Exception {
+ Endpoint personEndpoint = context.getEndpoint("direct:person");
+ MockEndpoint result = (MockEndpoint)context.getEndpoint("mock:result");
+ Person person = new Person("Chris");
+ result.expectedBodiesReceived(person);
+ PersonHandler sender = PojoProxyHelper.createProxy(personEndpoint, PersonHandler.class);
+
+ sender.onPerson(person);
+
+ result.assertIsSatisfied();
+ Assert.assertEquals(1, receiver.receivedPersons.size());
+ Assert.assertEquals(person.getName(), receiver.receivedPersons.get(0).getName());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+
+ @Override
+ public void configure() throws Exception {
+ from("direct:person").to("mock:result").bean(receiver);
+ }
+ };
+ }
+
+ public final class PersonReceiver implements PersonHandler {
+ public List<Person> receivedPersons = new ArrayList<Person>();
+
+ @Override
+ public void onPerson(Person person) {
+ receivedPersons.add(person);
+ }
+ }
+
+ public interface PersonHandler {
+ void onPerson(Person person);
+ }
+}
Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java?rev=1188162&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java Mon Oct 24 14:51:12 2011
@@ -0,0 +1,61 @@
+/**
+ * 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.pojomessage;
+
+import junit.framework.Assert;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Endpoint;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.bean.PojoProxyHelper;
+import org.junit.Test;
+
+public class PojoProxyHelperRequestReplyTest extends ContextTestSupport {
+
+ PersonReceiver receiver = new PersonReceiver();
+
+ @Test
+ public void testRequestReply() throws Exception {
+ Endpoint personEndpoint = context.getEndpoint("direct:person");
+ Person person = new Person("Chris");
+ PersonHandler sender = PojoProxyHelper.createProxy(personEndpoint, PersonHandler.class);
+
+ Person resultPerson = sender.onPerson(person);
+ Assert.assertEquals(person.getName() + "1", resultPerson.getName());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ public void configure() throws Exception {
+ from("direct:person").bean(receiver);
+ }
+ };
+ }
+
+ public final class PersonReceiver implements PersonHandler {
+ @Override
+ public Person onPerson(Person person) {
+ return new Person(person.getName() + "1");
+ }
+ }
+
+ public interface PersonHandler {
+ Person onPerson(Person person);
+ }
+
+}
Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Re: svn commit: r1188162 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/component/bean/ test/java/org/apache/camel/component/bean/pojomessage/
Posted by Claus Ibsen <cl...@gmail.com>.
Hi
Nice refactor
Just a few suggestion for polishing
- the logger in the abstract class is using the other class name
- possible add a bit javadoc to the abstract class
- a method has xxxbody where body is with a little b, and not Body.
On Mon, Oct 24, 2011 at 4:51 PM, <cs...@apache.org> wrote:
> Author: cschneider
> Date: Mon Oct 24 14:51:12 2011
> New Revision: 1188162
>
> URL: http://svn.apache.org/viewvc?rev=1188162&view=rev
> Log:
> CAMEL-4565 Code and tests for sending simple objects from a dynamic proxy
>
> Added:
> camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java (with props)
> camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java (with props)
> camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java (with props)
> camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/
> camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java (with props)
> camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java (with props)
> camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java (with props)
> Modified:
> camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
>
> Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java?rev=1188162&view=auto
> ==============================================================================
> --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java (added)
> +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java Mon Oct 24 14:51:12 2011
> @@ -0,0 +1,217 @@
> +/**
> + * 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.reflect.InvocationHandler;
> +import java.lang.reflect.Method;
> +import java.lang.reflect.Type;
> +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.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.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 transient Logger LOG = LoggerFactory.getLogger(CamelInvocationHandler.class);
> + private static ExecutorService executorService;
> + protected final Endpoint endpoint;
> + protected final Producer producer;
> +
> + public AbstractCamelInvocationHandler(Endpoint endpoint, Producer producer) {
> + super();
> + 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;
> + }
> + }
> + }
> +
> + protected Object invokeWithbody(final Method method, Object body, final ExchangePattern pattern) throws InterruptedException, Throwable {
> + final Exchange exchange = new DefaultExchange(endpoint, pattern);
> + exchange.getIn().setBody(body);
> +
> + // is the return type a future
> + final boolean isFuture = method.getReturnType() == Future.class;
> +
> + // create task to execute the proxy and gather the reply
> + FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
> + public Object call() throws Exception {
> + // process the exchange
> + LOG.trace("Proxied method call {} invoking producer: {}", method.getName(), producer);
> + producer.process(exchange);
> +
> + Object answer = afterInvoke(method, exchange, pattern, isFuture);
> + LOG.trace("Proxied method call {} returning: {}", method.getName(), answer);
> + return answer;
> + }
> + });
> +
> + if (isFuture) {
> + // submit task and return future
> + if (LOG.isTraceEnabled()) {
> + LOG.trace("Submitting task for exchange id {}", exchange.getExchangeId());
> + }
> + getExecutorService(exchange.getContext()).submit(task);
> + return task;
> + } else {
> + // execute task now
> + try {
> + task.run();
> + return task.get();
> + } catch (ExecutionException e) {
> + // we don't want the wrapped exception from JDK
> + throw e.getCause();
> + }
> + }
> + }
> +
> + protected Object afterInvoke(Method method, Exchange exchange, ExchangePattern pattern, boolean isFuture) throws Exception {
> + // check if we had an exception
> + Throwable cause = exchange.getException();
> + if (cause != null) {
> + Throwable found = findSuitableException(cause, method);
> + if (found != null) {
> + if (found instanceof Exception) {
> + throw (Exception)found;
> + } else {
> + // wrap as exception
> + throw new CamelExchangeException("Error processing exchange", exchange, cause);
> + }
> + }
> + // special for runtime camel exceptions as they can be nested
> + if (cause instanceof RuntimeCamelException) {
> + // if the inner cause is a runtime exception we can throw it
> + // directly
> + if (cause.getCause() instanceof RuntimeException) {
> + throw (RuntimeException)((RuntimeCamelException)cause).getCause();
> + }
> + throw (RuntimeCamelException)cause;
> + }
> + // okay just throw the exception as is
> + if (cause instanceof Exception) {
> + throw (Exception)cause;
> + } else {
> + // wrap as exception
> + throw new CamelExchangeException("Error processing exchange", exchange, cause);
> + }
> + }
> +
> + Class<?> to = isFuture ? getGenericType(exchange.getContext(), method.getGenericReturnType()) : method.getReturnType();
> +
> + // do not return a reply if the method is VOID
> + if (to == Void.TYPE) {
> + return null;
> + }
> +
> + return getBody(exchange, to);
> + }
> +
> + protected static Class<?> getGenericType(CamelContext context, Type type) throws ClassNotFoundException {
> + if (type == null) {
> + // fallback and use object
> + return Object.class;
> + }
> +
> + // unfortunately java dont provide a nice api for getting the generic
> + // type of the return type
> + // due type erasure, so we have to gather it based on a String
> + // representation
> + String name = ObjectHelper.between(type.toString(), "<", ">");
> + if (name != null) {
> + if (name.contains("<")) {
> + // we only need the outer type
> + name = ObjectHelper.before(name, "<");
> + }
> + return context.getClassResolver().resolveMandatoryClass(name);
> + } else {
> + // fallback and use object
> + return Object.class;
> + }
> + }
> +
> + protected static synchronized ExecutorService getExecutorService(CamelContext context) {
> + // CamelContext will shutdown thread pool when it shutdown so we can
> + // lazy create it on demand
> + // but in case of hot-deploy or the likes we need to be able to
> + // re-create it (its a shared static instance)
> + if (executorService == null || executorService.isTerminated() || executorService.isShutdown()) {
> + // try to lookup a pool first based on id/profile
> + executorService = context.getExecutorServiceStrategy().lookup(CamelInvocationHandler.class, "CamelInvocationHandler", "CamelInvocationHandler");
> + if (executorService == null) {
> + executorService = context.getExecutorServiceStrategy().newDefaultThreadPool(CamelInvocationHandler.class, "CamelInvocationHandler");
> + }
> + }
> + return executorService;
> + }
> +
> + /**
> + * Tries to find the best suited exception to throw.
> + * <p/>
> + * It looks in the exception hierarchy from the caused exception and matches
> + * this against the declared exceptions being thrown on the method.
> + *
> + * @param cause the caused exception
> + * @param method the method
> + * @return the exception to throw, or <tt>null</tt> if not possible to find
> + * a suitable exception
> + */
> + protected Throwable findSuitableException(Throwable cause, Method method) {
> + if (method.getExceptionTypes() == null || method.getExceptionTypes().length == 0) {
> + return null;
> + }
> +
> + // see if there is any exception which matches the declared exception on
> + // the method
> + for (Class<?> type : method.getExceptionTypes()) {
> + Object fault = ObjectHelper.getException(type, cause);
> + if (fault != null) {
> + return Throwable.class.cast(fault);
> + }
> + }
> +
> + return null;
> + }
> +
> +}
>
> Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
> ------------------------------------------------------------------------------
> svn:mime-type = text/plain
>
> Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java?rev=1188162&r1=1188161&r2=1188162&view=diff
> ==============================================================================
> --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java (original)
> +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/CamelInvocationHandler.java Mon Oct 24 14:51:12 2011
> @@ -18,213 +18,30 @@ package org.apache.camel.component.bean;
>
> import java.lang.reflect.InvocationHandler;
> import java.lang.reflect.Method;
> -import java.lang.reflect.Type;
> -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.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.InvalidPayloadException;
> import org.apache.camel.Producer;
> -import org.apache.camel.RuntimeCamelException;
> -import org.apache.camel.util.ObjectHelper;
> -import org.slf4j.Logger;
> -import org.slf4j.LoggerFactory;
>
> /**
> - * An {@link java.lang.reflect.InvocationHandler} which invokes a
> - * message exchange on a camel {@link Endpoint}
> - *
> - * @version
> + * An {@link java.lang.reflect.InvocationHandler} which invokes a message
> + * exchange on a camel {@link Endpoint}
> + *
> + * @version
> */
> -public class CamelInvocationHandler implements InvocationHandler {
> - private static final transient Logger LOG = LoggerFactory.getLogger(CamelInvocationHandler.class);
> -
> - // use a static thread pool to not create a new thread pool for each invocation
> - private static ExecutorService executorService;
> -
> - private final Endpoint endpoint;
> - private final Producer producer;
> +public class CamelInvocationHandler extends AbstractCamelInvocationHandler implements InvocationHandler {
> private final MethodInfoCache methodInfoCache;
>
> public CamelInvocationHandler(Endpoint endpoint, Producer producer, MethodInfoCache methodInfoCache) {
> - this.endpoint = endpoint;
> - this.producer = producer;
> + super(endpoint, producer);
> this.methodInfoCache = methodInfoCache;
> }
>
> public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
> BeanInvocation invocation = new BeanInvocation(method, args);
> MethodInfo methodInfo = methodInfoCache.getMethodInfo(method);
> -
> final ExchangePattern pattern = methodInfo != null ? methodInfo.getPattern() : ExchangePattern.InOut;
> - final Exchange exchange = endpoint.createExchange(pattern);
> - exchange.getIn().setBody(invocation);
> -
> - // is the return type a future
> - final boolean isFuture = method.getReturnType() == Future.class;
> -
> - // create task to execute the proxy and gather the reply
> - FutureTask task = new FutureTask<Object>(new Callable<Object>() {
> - public Object call() throws Exception {
> - // process the exchange
> - LOG.trace("Proxied method call {} invoking producer: {}", method.getName(), producer);
> - producer.process(exchange);
> -
> - Object answer = afterInvoke(method, exchange, pattern, isFuture);
> - LOG.trace("Proxied method call {} returning: {}", method.getName(), answer);
> - return answer;
> - }
> - });
> -
> - if (isFuture) {
> - // submit task and return future
> - if (LOG.isTraceEnabled()) {
> - LOG.trace("Submitting task for exchange id {}", exchange.getExchangeId());
> - }
> - getExecutorService(exchange.getContext()).submit(task);
> - return task;
> - } else {
> - // execute task now
> - try {
> - task.run();
> - return task.get();
> - } catch (ExecutionException e) {
> - // we don't want the wrapped exception from JDK
> - throw e.getCause();
> - }
> - }
> - }
> -
> - protected Object afterInvoke(Method method, Exchange exchange, ExchangePattern pattern, boolean isFuture) throws Exception {
> - // check if we had an exception
> - Throwable cause = exchange.getException();
> - if (cause != null) {
> - Throwable found = findSuitableException(cause, method);
> - if (found != null) {
> - if (found instanceof Exception) {
> - throw (Exception) found;
> - } else {
> - // wrap as exception
> - throw new CamelExchangeException("Error processing exchange", exchange, cause);
> - }
> - }
> - // special for runtime camel exceptions as they can be nested
> - if (cause instanceof RuntimeCamelException) {
> - // if the inner cause is a runtime exception we can throw it directly
> - if (cause.getCause() instanceof RuntimeException) {
> - throw (RuntimeException) ((RuntimeCamelException) cause).getCause();
> - }
> - throw (RuntimeCamelException) cause;
> - }
> - // okay just throw the exception as is
> - if (cause instanceof Exception) {
> - throw (Exception) cause;
> - } else {
> - // wrap as exception
> - throw new CamelExchangeException("Error processing exchange", exchange, cause);
> - }
> - }
> -
> - // do not return a reply if the method is VOID
> - Class<?> to = method.getReturnType();
> - if (to == Void.TYPE) {
> - return null;
> - }
> -
> - // use type converter so we can convert output in the desired type defined by the method
> - // and let it be mandatory so we know wont return null if we cant convert it to the defined type
> - Object answer;
> - if (!isFuture) {
> - answer = getBody(exchange, to);
> - } else {
> - // if its a Future then we need to extract the class from the future type so we know
> - // which class to return the result as
> - Class<?> returnTo = getGenericType(exchange.getContext(), method.getGenericReturnType());
> - answer = getBody(exchange, returnTo);
> - }
> -
> - return answer;
> - }
> -
> - 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;
> - }
> - }
> - }
> -
> - protected static Class getGenericType(CamelContext context, Type type) throws ClassNotFoundException {
> - if (type == null) {
> - // fallback and use object
> - return Object.class;
> - }
> -
> - // unfortunately java dont provide a nice api for getting the generic type of the return type
> - // due type erasure, so we have to gather it based on a String representation
> - String name = ObjectHelper.between(type.toString(), "<", ">");
> - if (name != null) {
> - if (name.contains("<")) {
> - // we only need the outer type
> - name = ObjectHelper.before(name, "<");
> - }
> - return context.getClassResolver().resolveMandatoryClass(name);
> - } else {
> - // fallback and use object
> - return Object.class;
> - }
> - }
> -
> - /**
> - * Tries to find the best suited exception to throw.
> - * <p/>
> - * It looks in the exception hierarchy from the caused exception and matches this against the declared exceptions
> - * being thrown on the method.
> - *
> - * @param cause the caused exception
> - * @param method the method
> - * @return the exception to throw, or <tt>null</tt> if not possible to find a suitable exception
> - */
> - protected Throwable findSuitableException(Throwable cause, Method method) {
> - if (method.getExceptionTypes() == null || method.getExceptionTypes().length == 0) {
> - return null;
> - }
> -
> - // see if there is any exception which matches the declared exception on the method
> - for (Class<?> type : method.getExceptionTypes()) {
> - Object fault = ObjectHelper.getException(type, cause);
> - if (fault != null) {
> - return Throwable.class.cast(fault);
> - }
> - }
> -
> - return null;
> - }
> -
> - protected static synchronized ExecutorService getExecutorService(CamelContext context) {
> - // CamelContext will shutdown thread pool when it shutdown so we can lazy create it on demand
> - // but in case of hot-deploy or the likes we need to be able to re-create it (its a shared static instance)
> - if (executorService == null || executorService.isTerminated() || executorService.isShutdown()) {
> - executorService = context.getExecutorServiceManager().newDefaultThreadPool(CamelInvocationHandler.class, "CamelInvocationHandler");
> - }
> - return executorService;
> + return invokeWithbody(method, invocation, pattern);
> }
>
> }
> -
>
> Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java?rev=1188162&view=auto
> ==============================================================================
> --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java (added)
> +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java Mon Oct 24 14:51:12 2011
> @@ -0,0 +1,48 @@
> +/**
> + * 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.reflect.Method;
> +
> +import org.apache.camel.Endpoint;
> +import org.apache.camel.ExchangePattern;
> +import org.apache.camel.Producer;
> +import org.apache.camel.RuntimeCamelException;
> +
> +/**
> + * Special InvocationHandler for methods that have only one parameter. This
> + * parameter is directly sent to as the body of the message. The idea is to use
> + * that as a very open message format especially when combined with e.g. JAXB
> + * serialization.
> + */
> +public class PojoMessageInvocationHandler extends AbstractCamelInvocationHandler {
> + public PojoMessageInvocationHandler(Endpoint endpoint, Producer producer) {
> + super(endpoint, producer);
> + }
> +
> + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
> + int argsLength = (args == null) ? 0 : args.length;
> + if (argsLength != 1) {
> + throw new RuntimeCamelException(String.format("Error creating proxy for %s.%s Number of arguments must be 1 but is %d",
> + method.getDeclaringClass().getName(),
> + method.getName(), argsLength));
> + }
> + final ExchangePattern pattern = method.getReturnType() != Void.TYPE ? ExchangePattern.InOut : ExchangePattern.InOnly;
> + return invokeWithbody(method, args[0], pattern);
> + }
> +
> +}
>
> Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoMessageInvocationHandler.java
> ------------------------------------------------------------------------------
> svn:mime-type = text/plain
>
> Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java?rev=1188162&view=auto
> ==============================================================================
> --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java (added)
> +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java Mon Oct 24 14:51:12 2011
> @@ -0,0 +1,40 @@
> +/**
> + * 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.reflect.Proxy;
> +
> +import org.apache.camel.Endpoint;
> +import org.apache.camel.Producer;
> +import org.apache.camel.util.ServiceHelper;
> +
> +/**
> + * Create a dynamic proxy for a given interface and endpoint that sends the parameter object to the endpoint and optionally
> + * receives a reply. Unlike the ProxyHelper this works only with methods that have only one parameter.
> + */
> +public final class PojoProxyHelper {
> + private PojoProxyHelper() {
> + }
> +
> + @SuppressWarnings("unchecked")
> + public static <T> T createProxy(Endpoint endpoint, Class<?>... interfaceClasses) throws Exception {
> + Producer producer = endpoint.createProducer();
> + // ensure the producer is started
> + ServiceHelper.startService(producer);
> + return (T)Proxy.newProxyInstance(ProxyHelper.getClassLoader(interfaceClasses), interfaceClasses.clone(), new PojoMessageInvocationHandler(endpoint, producer));
> + }
> +}
>
> Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/PojoProxyHelper.java
> ------------------------------------------------------------------------------
> svn:mime-type = text/plain
>
> Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java?rev=1188162&view=auto
> ==============================================================================
> --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java (added)
> +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java Mon Oct 24 14:51:12 2011
> @@ -0,0 +1,33 @@
> +/**
> + * 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.pojomessage;
> +
> +public class Person {
> + String name;
> +
> + public Person() {
> + }
> +
> + public Person(String name) {
> + this.name = name;
> + }
> +
> + public String getName() {
> + return name;
> + }
> +
> +}
> \ No newline at end of file
>
> Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/Person.java
> ------------------------------------------------------------------------------
> svn:mime-type = text/plain
>
> Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java?rev=1188162&view=auto
> ==============================================================================
> --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java (added)
> +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java Mon Oct 24 14:51:12 2011
> @@ -0,0 +1,73 @@
> +/**
> + * 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.pojomessage;
> +
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +import junit.framework.Assert;
> +
> +import org.apache.camel.ContextTestSupport;
> +import org.apache.camel.Endpoint;
> +import org.apache.camel.builder.RouteBuilder;
> +import org.apache.camel.component.bean.PojoProxyHelper;
> +import org.apache.camel.component.mock.MockEndpoint;
> +import org.junit.Test;
> +
> +public class PojoProxyHelperOneWayTest extends ContextTestSupport {
> +
> + PersonReceiver receiver = new PersonReceiver();
> +
> + @Test
> + public void testOneWay() throws Exception {
> + Endpoint personEndpoint = context.getEndpoint("direct:person");
> + MockEndpoint result = (MockEndpoint)context.getEndpoint("mock:result");
> + Person person = new Person("Chris");
> + result.expectedBodiesReceived(person);
> + PersonHandler sender = PojoProxyHelper.createProxy(personEndpoint, PersonHandler.class);
> +
> + sender.onPerson(person);
> +
> + result.assertIsSatisfied();
> + Assert.assertEquals(1, receiver.receivedPersons.size());
> + Assert.assertEquals(person.getName(), receiver.receivedPersons.get(0).getName());
> + }
> +
> + @Override
> + protected RouteBuilder createRouteBuilder() throws Exception {
> + return new RouteBuilder() {
> +
> + @Override
> + public void configure() throws Exception {
> + from("direct:person").to("mock:result").bean(receiver);
> + }
> + };
> + }
> +
> + public final class PersonReceiver implements PersonHandler {
> + public List<Person> receivedPersons = new ArrayList<Person>();
> +
> + @Override
> + public void onPerson(Person person) {
> + receivedPersons.add(person);
> + }
> + }
> +
> + public interface PersonHandler {
> + void onPerson(Person person);
> + }
> +}
>
> Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperOneWayTest.java
> ------------------------------------------------------------------------------
> svn:mime-type = text/plain
>
> Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java
> URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java?rev=1188162&view=auto
> ==============================================================================
> --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java (added)
> +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java Mon Oct 24 14:51:12 2011
> @@ -0,0 +1,61 @@
> +/**
> + * 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.pojomessage;
> +
> +import junit.framework.Assert;
> +
> +import org.apache.camel.ContextTestSupport;
> +import org.apache.camel.Endpoint;
> +import org.apache.camel.builder.RouteBuilder;
> +import org.apache.camel.component.bean.PojoProxyHelper;
> +import org.junit.Test;
> +
> +public class PojoProxyHelperRequestReplyTest extends ContextTestSupport {
> +
> + PersonReceiver receiver = new PersonReceiver();
> +
> + @Test
> + public void testRequestReply() throws Exception {
> + Endpoint personEndpoint = context.getEndpoint("direct:person");
> + Person person = new Person("Chris");
> + PersonHandler sender = PojoProxyHelper.createProxy(personEndpoint, PersonHandler.class);
> +
> + Person resultPerson = sender.onPerson(person);
> + Assert.assertEquals(person.getName() + "1", resultPerson.getName());
> + }
> +
> + @Override
> + protected RouteBuilder createRouteBuilder() throws Exception {
> + return new RouteBuilder() {
> + public void configure() throws Exception {
> + from("direct:person").bean(receiver);
> + }
> + };
> + }
> +
> + public final class PersonReceiver implements PersonHandler {
> + @Override
> + public Person onPerson(Person person) {
> + return new Person(person.getName() + "1");
> + }
> + }
> +
> + public interface PersonHandler {
> + Person onPerson(Person person);
> + }
> +
> +}
>
> Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/pojomessage/PojoProxyHelperRequestReplyTest.java
> ------------------------------------------------------------------------------
> svn:mime-type = text/plain
>
>
>
--
Claus Ibsen
-----------------
FuseSource
Email: cibsen@fusesource.com
Web: http://fusesource.com
Twitter: davsclaus, fusenews
Blog: http://davsclaus.blogspot.com/
Author of Camel in Action: http://www.manning.com/ibsen/