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 */ 017package org.apache.camel.model; 018 019import javax.xml.bind.annotation.XmlAccessType; 020import javax.xml.bind.annotation.XmlAccessorType; 021import javax.xml.bind.annotation.XmlAttribute; 022import javax.xml.bind.annotation.XmlRootElement; 023import javax.xml.bind.annotation.XmlTransient; 024 025import org.apache.camel.Processor; 026import org.apache.camel.component.bean.BeanHolder; 027import org.apache.camel.component.bean.BeanInfo; 028import org.apache.camel.component.bean.BeanProcessor; 029import org.apache.camel.component.bean.ConstantBeanHolder; 030import org.apache.camel.component.bean.ConstantStaticTypeBeanHolder; 031import org.apache.camel.component.bean.ConstantTypeBeanHolder; 032import org.apache.camel.component.bean.MethodNotFoundException; 033import org.apache.camel.component.bean.RegistryBean; 034import org.apache.camel.spi.Metadata; 035import org.apache.camel.spi.RouteContext; 036import org.apache.camel.util.CamelContextHelper; 037import org.apache.camel.util.ObjectHelper; 038 039/** 040 * Calls a java bean 041 * 042 * @version 043 */ 044@Metadata(label = "eip,endpoint") 045@XmlRootElement(name = "bean") 046@XmlAccessorType(XmlAccessType.FIELD) 047public class BeanDefinition extends NoOutputDefinition<BeanDefinition> { 048 @XmlAttribute 049 private String ref; 050 @XmlAttribute 051 private String method; 052 @XmlAttribute 053 private String beanType; 054 @XmlAttribute @Metadata(defaultValue = "true") 055 private Boolean cache; 056 @XmlAttribute 057 @Deprecated 058 private Boolean multiParameterArray; 059 @XmlTransient 060 private Class<?> beanClass; 061 @XmlTransient 062 private Object bean; 063 064 public BeanDefinition() { 065 } 066 067 public BeanDefinition(String ref) { 068 this.ref = ref; 069 } 070 071 public BeanDefinition(String ref, String method) { 072 this.ref = ref; 073 this.method = method; 074 } 075 076 @Override 077 public String toString() { 078 return "Bean[" + description() + "]"; 079 } 080 081 public String description() { 082 if (ref != null) { 083 String methodText = ""; 084 if (method != null) { 085 methodText = " method:" + method; 086 } 087 return "ref:" + ref + methodText; 088 } else if (bean != null) { 089 return bean.toString(); 090 } else if (beanClass != null) { 091 return beanClass.getName(); 092 } else if (beanType != null) { 093 return beanType; 094 } else { 095 return ""; 096 } 097 } 098 099 @Override 100 public String getLabel() { 101 return "bean[" + description() + "]"; 102 } 103 104 public String getRef() { 105 return ref; 106 } 107 108 /** 109 * Sets a reference to a bean to use 110 */ 111 public void setRef(String ref) { 112 this.ref = ref; 113 } 114 115 public String getMethod() { 116 return method; 117 } 118 119 /** 120 * Sets the method name on the bean to use 121 */ 122 public void setMethod(String method) { 123 this.method = method; 124 } 125 126 /** 127 * Sets an instance of the bean to use 128 */ 129 public void setBean(Object bean) { 130 this.bean = bean; 131 } 132 133 public String getBeanType() { 134 return beanType; 135 } 136 137 /** 138 * Sets the Class of the bean 139 */ 140 public void setBeanType(String beanType) { 141 this.beanType = beanType; 142 } 143 144 /** 145 * Sets the Class of the bean 146 */ 147 public void setBeanType(Class<?> beanType) { 148 this.beanClass = beanType; 149 } 150 151 public Boolean getCache() { 152 return cache; 153 } 154 155 /** 156 * Caches the bean lookup, to avoid lookup up bean on every usage. 157 */ 158 public void setCache(Boolean cache) { 159 this.cache = cache; 160 } 161 162 public Boolean getMultiParameterArray() { 163 return multiParameterArray; 164 } 165 166 /** 167 * Whether the message body is an array type. 168 * 169 * @deprecated is to be replaced with a better solution in Camel 3.0 170 */ 171 @Deprecated 172 public void setMultiParameterArray(Boolean multiParameterArray) { 173 this.multiParameterArray = multiParameterArray; 174 } 175 176 // Fluent API 177 //------------------------------------------------------------------------- 178 /** 179 * Sets a reference to a bean to use 180 * 181 * @param ref the bean's id in the registry 182 * @return the builder 183 * @deprecated not in use, will be removed in next Camel release 184 */ 185 @Deprecated 186 public BeanDefinition ref(String ref) { 187 setRef(ref); 188 return this; 189 } 190 191 /** 192 * Sets the method name on the bean to use 193 * 194 * @param method the bean's method name which wants camel to call 195 * @return the builder 196 * @deprecated not in use, will be removed in next Camel release 197 */ 198 @Deprecated 199 public BeanDefinition method(String method) { 200 setMethod(method); 201 return this; 202 } 203 204 /** 205 * Sets an instance of the bean to use 206 * 207 * @param bean the instance of the bean 208 * @return the builder 209 * @deprecated not in use, will be removed in next Camel release 210 */ 211 @Deprecated 212 public BeanDefinition bean(Object bean) { 213 setBean(bean); 214 return this; 215 } 216 217 /** 218 * Sets the Class of the bean 219 * 220 * @param beanType the Class of the bean 221 * @return the builder 222 * @deprecated not in use, will be removed in next Camel release 223 */ 224 @Deprecated 225 public BeanDefinition beanType(Class<?> beanType) { 226 setBeanType(beanType); 227 return this; 228 } 229 230 /** 231 * Caches the bean lookup, to avoid lookup up bean on every usage. 232 * 233 * @return the builder 234 */ 235 @Deprecated 236 public BeanDefinition cache() { 237 setCache(true); 238 return this; 239 } 240 241 @Override 242 public Processor createProcessor(RouteContext routeContext) throws Exception { 243 BeanProcessor answer; 244 Class<?> clazz = bean != null ? bean.getClass() : null; 245 BeanHolder beanHolder; 246 247 if (ObjectHelper.isNotEmpty(ref)) { 248 // lets cache by default 249 if (isCacheBean()) { 250 // cache the registry lookup which avoids repeat lookup in the registry 251 beanHolder = new RegistryBean(routeContext.getCamelContext(), ref).createCacheHolder(); 252 // bean holder will check if the bean exists 253 bean = beanHolder.getBean(); 254 } else { 255 // we do not cache so we invoke on-demand 256 beanHolder = new RegistryBean(routeContext.getCamelContext(), ref); 257 } 258 answer = new BeanProcessor(beanHolder); 259 } else { 260 if (bean == null) { 261 262 if (beanType == null && beanClass == null) { 263 throw new IllegalArgumentException("bean, ref or beanType must be provided"); 264 } 265 266 // the clazz is either from beanType or beanClass 267 if (beanType != null) { 268 try { 269 clazz = routeContext.getCamelContext().getClassResolver().resolveMandatoryClass(beanType); 270 } catch (ClassNotFoundException e) { 271 throw ObjectHelper.wrapRuntimeCamelException(e); 272 } 273 } else { 274 clazz = beanClass; 275 } 276 277 // attempt to create bean using injector which supports auto-wiring 278 if (isCacheBean() && routeContext.getCamelContext().getInjector().supportsAutoWiring()) { 279 try { 280 log.debug("Attempting to create new bean instance from class: {} via auto-wiring enabled", clazz); 281 bean = CamelContextHelper.newInstance(routeContext.getCamelContext(), clazz); 282 } catch (Throwable e) { 283 log.debug("Error creating new bean instance from class: " + clazz + ". This exception is ignored", e); 284 } 285 } 286 287 // create a bean if there is a default public no-arg constructor 288 if (bean == null && isCacheBean() && ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) { 289 log.debug("Class has default no-arg constructor so creating a new bean instance: {}", clazz); 290 bean = CamelContextHelper.newInstance(routeContext.getCamelContext(), clazz); 291 ObjectHelper.notNull(bean, "bean", this); 292 } 293 } 294 295 // validate the bean type is not from java so you by mistake think its a reference 296 // to a bean name but the String is being invoke instead 297 if (bean instanceof String) { 298 throw new IllegalArgumentException("The bean instance is a java.lang.String type: " + bean 299 + ". We suppose you want to refer to a bean instance by its id instead. Please use ref."); 300 } 301 302 // the holder should either be bean or type based 303 if (bean != null) { 304 beanHolder = new ConstantBeanHolder(bean, routeContext.getCamelContext()); 305 } else { 306 if (isCacheBean() && ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) { 307 // we can only cache if we can create an instance of the bean, and for that we need a public constructor 308 beanHolder = new ConstantTypeBeanHolder(clazz, routeContext.getCamelContext()).createCacheHolder(); 309 } else { 310 if (ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) { 311 beanHolder = new ConstantTypeBeanHolder(clazz, routeContext.getCamelContext()); 312 } else { 313 // this is only for invoking static methods on the bean 314 beanHolder = new ConstantStaticTypeBeanHolder(clazz, routeContext.getCamelContext()); 315 } 316 } 317 } 318 answer = new BeanProcessor(beanHolder); 319 } 320 321 // check for multiParameterArray setting 322 if (multiParameterArray != null) { 323 answer.setMultiParameterArray(multiParameterArray); 324 } 325 326 // check for method exists 327 if (method != null) { 328 answer.setMethod(method); 329 330 // check there is a method with the given name, and leverage BeanInfo for that 331 // which we only do if we are caching the bean as otherwise we will create a bean instance for this check 332 // which we only want to do if we cache the bean 333 if (isCacheBean()) { 334 BeanInfo beanInfo = beanHolder.getBeanInfo(); 335 if (bean != null) { 336 // there is a bean instance, so check for any methods 337 if (!beanInfo.hasMethod(method)) { 338 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, bean, method)); 339 } 340 } else if (clazz != null) { 341 // there is no bean instance, so check for static methods only 342 if (!beanInfo.hasStaticMethod(method)) { 343 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, clazz, method, true)); 344 } 345 } 346 } 347 } 348 349 return answer; 350 } 351 352 private boolean isCacheBean() { 353 return cache == null || cache; 354 } 355 356}