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        @XmlTransient
052        private Class<?> beanClass;
053        @XmlTransient
054        private Object bean;
055    
056        public BeanDefinition() {
057        }
058    
059        public BeanDefinition(String ref) {
060            this.ref = ref;
061        }
062    
063        public BeanDefinition(String ref, String method) {
064            this.ref = ref;
065            this.method = method;
066        }
067    
068        @Override
069        public String toString() {
070            return "Bean[" + description() + "]";
071        }
072        
073        public String description() {
074            if (ref != null) {
075                String methodText = "";
076                if (method != null) {
077                    methodText = " method: " + method;
078                }
079                return "ref:" + ref + methodText;
080            } else if (bean != null) {
081                return bean.toString();
082            } else if (beanClass != null) {
083                return beanClass.getName();
084            } else if (beanType != null) {
085                return beanType;
086            } else {
087                return "";
088            }
089        }
090        
091        @Override
092        public String getLabel() {
093            return "bean[" + description() + "]";
094        }
095    
096        @Override
097        public String getShortName() {
098            return "bean";
099        }
100    
101        public String getRef() {
102            return ref;
103        }
104    
105        public void setRef(String ref) {
106            this.ref = ref;
107        }
108    
109        public String getMethod() {
110            return method;
111        }
112    
113        public void setMethod(String method) {
114            this.method = method;
115        }
116    
117        public void setBean(Object bean) {
118            this.bean = bean;
119        }
120    
121        public String getBeanType() {
122            return beanType;
123        }
124    
125        public void setBeanType(String beanType) {
126            this.beanType = beanType;
127        }
128    
129        public void setBeanType(Class<?> beanType) {
130            this.beanClass = beanType;
131        }
132    
133        // Fluent API
134        //-------------------------------------------------------------------------
135        /**
136         * Sets the ref String on camel bean
137         *
138         * @param ref  the bean's id in the registry
139         * @return the builder
140         * @deprecated not in use, will be removed in next Camel release
141         */
142        @Deprecated
143        public BeanDefinition ref(String ref) {
144            setRef(ref);
145            return this;
146        }
147        
148        /**
149         * Sets the calling method name of camel bean
150         *
151         * @param method  the bean's method name which wants camel to call
152         * @return the builder
153         * @deprecated not in use, will be removed in next Camel release
154         */
155        @Deprecated
156        public BeanDefinition method(String method) {
157            setMethod(method);
158            return this;
159        }
160        
161        /**
162         * Sets the bean's instance that camel to call
163         *
164         * @param bean the instance of the bean
165         * @return the builder
166         * @deprecated not in use, will be removed in next Camel release
167         */
168        @Deprecated
169        public BeanDefinition bean(Object bean) {
170            setBean(bean);
171            return this;
172        }
173        
174        /**
175         * Sets the Class of the bean
176         *
177         * @param beanType the Class of the bean
178         * @return the builder
179         * @deprecated not in use, will be removed in next Camel release
180         */
181        @Deprecated
182        public BeanDefinition beanType(Class<?> beanType) {
183            setBeanType(beanType);
184            return this;
185        }
186    
187        @Override
188        public Processor createProcessor(RouteContext routeContext) {
189            BeanProcessor answer;
190            Class<?> clazz = bean != null ? bean.getClass() : null;
191            BeanHolder beanHolder;
192    
193            if (ObjectHelper.isNotEmpty(ref)) {
194                beanHolder = new RegistryBean(routeContext.getCamelContext(), ref);
195                // bean holder will check if the bean exists
196                bean = beanHolder.getBean();
197                answer = new BeanProcessor(beanHolder);
198            } else {
199                if (bean == null) {
200                    
201                    if (beanType == null && beanClass == null) {
202                        throw new IllegalArgumentException("bean, ref or beanType must be provided");
203                    }
204    
205                    // the clazz is either from beanType or beanClass
206                    if (beanType != null) {
207                        try {
208                            clazz = routeContext.getCamelContext().getClassResolver().resolveMandatoryClass(beanType);
209                        } catch (ClassNotFoundException e) {
210                            throw ObjectHelper.wrapRuntimeCamelException(e);
211                        }
212                    } else {
213                        clazz = beanClass;
214                    }
215    
216                    // create a bean if there is a default public no-arg constructor
217                    if (ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) {
218                        bean = CamelContextHelper.newInstance(routeContext.getCamelContext(), clazz);
219                        ObjectHelper.notNull(bean, "bean", this);
220                    }
221                }
222    
223                // validate the bean type is not from java so you by mistake think its a reference
224                // to a bean name but the String is being invoke instead
225                if (bean instanceof String) {
226                    throw new IllegalArgumentException("The bean instance is a java.lang.String type: " + bean
227                        + ". We suppose you want to refer to a bean instance by its id instead. Please use beanRef.");
228                }
229    
230                // the holder should either be bean or type based
231                beanHolder = bean != null ? new ConstantBeanHolder(bean, routeContext.getCamelContext()) : new ConstantTypeBeanHolder(clazz, routeContext.getCamelContext());
232                answer = new BeanProcessor(beanHolder);
233            }
234    
235            // check for method exists
236            if (method != null) {
237                answer.setMethod(method);
238    
239                // check there is a method with the given name, and leverage BeanInfo for that
240                BeanInfo beanInfo = beanHolder.getBeanInfo();
241                if (bean != null) {
242                    // there is a bean instance, so check for any methods
243                    if (!beanInfo.hasMethod(method)) {
244                        throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, bean, method));
245                    }
246                } else if (clazz != null) {
247                    // there is no bean instance, so check for static methods only
248                    if (!beanInfo.hasStaticMethod(method)) {
249                        throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, clazz, method, true));
250                    }
251                }
252            }
253    
254            return answer;
255        }
256    
257    }