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 // create a bean if there is a default public no-arg constructor 278 if (isCacheBean() && ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) { 279 bean = CamelContextHelper.newInstance(routeContext.getCamelContext(), clazz); 280 ObjectHelper.notNull(bean, "bean", this); 281 } 282 } 283 284 // validate the bean type is not from java so you by mistake think its a reference 285 // to a bean name but the String is being invoke instead 286 if (bean instanceof String) { 287 throw new IllegalArgumentException("The bean instance is a java.lang.String type: " + bean 288 + ". We suppose you want to refer to a bean instance by its id instead. Please use ref."); 289 } 290 291 // the holder should either be bean or type based 292 if (bean != null) { 293 beanHolder = new ConstantBeanHolder(bean, routeContext.getCamelContext()); 294 } else { 295 if (isCacheBean() && ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) { 296 // we can only cache if we can create an instance of the bean, and for that we need a public constructor 297 beanHolder = new ConstantTypeBeanHolder(clazz, routeContext.getCamelContext()).createCacheHolder(); 298 } else { 299 if (ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) { 300 beanHolder = new ConstantTypeBeanHolder(clazz, routeContext.getCamelContext()); 301 } else { 302 // this is only for invoking static methods on the bean 303 beanHolder = new ConstantStaticTypeBeanHolder(clazz, routeContext.getCamelContext()); 304 } 305 } 306 } 307 answer = new BeanProcessor(beanHolder); 308 } 309 310 // check for multiParameterArray setting 311 if (multiParameterArray != null) { 312 answer.setMultiParameterArray(multiParameterArray); 313 } 314 315 // check for method exists 316 if (method != null) { 317 answer.setMethod(method); 318 319 // check there is a method with the given name, and leverage BeanInfo for that 320 // which we only do if we are caching the bean as otherwise we will create a bean instance for this check 321 // which we only want to do if we cache the bean 322 if (isCacheBean()) { 323 BeanInfo beanInfo = beanHolder.getBeanInfo(); 324 if (bean != null) { 325 // there is a bean instance, so check for any methods 326 if (!beanInfo.hasMethod(method)) { 327 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, bean, method)); 328 } 329 } else if (clazz != null) { 330 // there is no bean instance, so check for static methods only 331 if (!beanInfo.hasStaticMethod(method)) { 332 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, clazz, method, true)); 333 } 334 } 335 } 336 } 337 338 return answer; 339 } 340 341 private boolean isCacheBean() { 342 return cache == null || cache; 343 } 344 345}