001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.bean;
018
019 import java.lang.reflect.InvocationTargetException;
020 import java.lang.reflect.Method;
021
022 import org.apache.camel.CamelContext;
023 import org.apache.camel.Exchange;
024 import org.apache.camel.Message;
025 import org.apache.camel.NoTypeConversionAvailableException;
026 import org.apache.camel.Processor;
027 import org.apache.camel.impl.ServiceSupport;
028 import org.apache.camel.util.ObjectHelper;
029 import org.apache.camel.util.ServiceHelper;
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032
033 /**
034 * A {@link Processor} which converts the inbound exchange to a method
035 * invocation on a POJO
036 *
037 * @version $Revision: 13853 $
038 */
039 public class BeanProcessor extends ServiceSupport implements Processor {
040 public static final String METHOD_NAME = "org.apache.camel.MethodName";
041 public static final String MULTI_PARAMETER_ARRAY = "org.apache.camel.MultiParameterArray";
042 private static final transient Log LOG = LogFactory.getLog(BeanProcessor.class);
043
044 private boolean multiParameterArray;
045 private Method methodObject;
046 private String method;
047 private BeanHolder beanHolder;
048
049 public BeanProcessor(Object pojo, BeanInfo beanInfo) {
050 this(new ConstantBeanHolder(pojo, beanInfo));
051 }
052
053 public BeanProcessor(Object pojo, CamelContext camelContext, ParameterMappingStrategy parameterMappingStrategy) {
054 this(pojo, new BeanInfo(camelContext, pojo.getClass(), parameterMappingStrategy));
055 }
056
057 public BeanProcessor(Object pojo, CamelContext camelContext) {
058 this(pojo, camelContext, BeanInfo.createParameterMappingStrategy(camelContext));
059 }
060
061 public BeanProcessor(BeanHolder beanHolder) {
062 this.beanHolder = beanHolder;
063 }
064
065 @Override
066 public String toString() {
067 String description = methodObject != null ? " " + methodObject : "";
068 return "BeanProcessor[" + beanHolder + description + "]";
069 }
070
071 public void process(Exchange exchange) throws Exception {
072 Object bean = beanHolder.getBean();
073 exchange.setProperty("org.apache.camel.bean.BeanHolder", beanHolder);
074
075 Processor processor = getProcessor();
076 BeanInfo beanInfo = beanHolder.getBeanInfo();
077
078 // do we have a custom adapter for this POJO to a Processor
079 if (processor != null) {
080 processor.process(exchange);
081 return;
082 }
083 Message in = exchange.getIn();
084
085 if (in.getHeader(MULTI_PARAMETER_ARRAY) == null) {
086 in.setHeader(MULTI_PARAMETER_ARRAY, isMultiParameterArray());
087 }
088
089 try {
090 BeanInvocation beanInvoke = in.getBody(BeanInvocation.class);
091 if (beanInvoke != null) {
092 beanInvoke.invoke(bean, exchange);
093 return;
094 }
095 } catch (NoTypeConversionAvailableException ex) {
096 // ignore, body is not a BeanInvocation
097 }
098
099 boolean isExplicitMethod = false;
100 String prevMethod = null;
101 MethodInvocation invocation;
102 if (methodObject != null) {
103 invocation = beanInfo.createInvocation(methodObject, bean, exchange);
104 } else {
105 // we just override the bean's invocation method name here
106 if (ObjectHelper.isNotNullAndNonEmpty(method)) {
107 prevMethod = in.getHeader(METHOD_NAME, String.class);
108 in.setHeader(METHOD_NAME, method);
109 isExplicitMethod = true;
110 }
111 invocation = beanInfo.createInvocation(bean, exchange);
112 }
113 if (invocation == null) {
114 throw new IllegalStateException(
115 "No method invocation could be created, no maching method could be found on: " + bean);
116 }
117 Object value = null;
118 try {
119 value = invocation.proceed();
120 } catch (InvocationTargetException e) {
121 // lets unwrap the exception
122 Throwable throwable = e.getCause();
123 if (throwable instanceof Exception) {
124 Exception exception = (Exception)throwable;
125 throw exception;
126 } else {
127 Error error = (Error)throwable;
128 throw error;
129 }
130 } finally {
131 if (isExplicitMethod) {
132 in.setHeader(METHOD_NAME, prevMethod);
133 }
134 }
135
136 if (value != null) {
137 if (exchange.getPattern().isOutCapable()) {
138 // force out creating if not already created (as its lazy)
139 if (LOG.isDebugEnabled()) {
140 LOG.debug("Setting bean invocation result on the OUT message: " + value);
141 }
142 exchange.getOut(true).setBody(value);
143 // propagate headers
144 exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
145 } else {
146 // if not out then set it on the in
147 if (LOG.isDebugEnabled()) {
148 LOG.debug("Setting bean invocation result on the IN message: " + value);
149 }
150 exchange.getIn().setBody(value);
151 }
152 }
153 }
154
155 protected Processor getProcessor() {
156 return beanHolder.getProcessor();
157 }
158
159 // Properties
160 // -----------------------------------------------------------------------
161
162 public Method getMethodObject() {
163 return methodObject;
164 }
165
166 public void setMethodObject(Method methodObject) {
167 this.methodObject = methodObject;
168 }
169
170 public String getMethod() {
171 return method;
172 }
173
174 public boolean isMultiParameterArray() {
175 return multiParameterArray;
176 }
177
178 public void setMultiParameterArray(boolean mpArray) {
179 multiParameterArray = mpArray;
180 }
181
182 /**
183 * Sets the method name to use
184 */
185 public void setMethod(String method) {
186 this.method = method;
187 }
188
189 /**
190 * Kept around for backwards compatibility, please use {@link #setMethod(String)}
191 * in future instead.
192 *
193 * @deprecated use {@link #setMethod(String)}. Will be removed in Camel 2.0.
194 */
195 @Deprecated
196 public void setMethodName(String method) {
197 setMethod(method);
198 }
199
200 // Implementation methods
201 //-------------------------------------------------------------------------
202 protected void doStart() throws Exception {
203 ServiceHelper.startService(getProcessor());
204 }
205
206 protected void doStop() throws Exception {
207 ServiceHelper.stopService(getProcessor());
208 }
209 }