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