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