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