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.language;
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.CamelContext;
026 import org.apache.camel.Expression;
027 import org.apache.camel.ExpressionIllegalSyntaxException;
028 import org.apache.camel.Predicate;
029 import org.apache.camel.component.bean.BeanHolder;
030 import org.apache.camel.component.bean.BeanInfo;
031 import org.apache.camel.component.bean.ConstantBeanHolder;
032 import org.apache.camel.component.bean.ConstantTypeBeanHolder;
033 import org.apache.camel.component.bean.MethodNotFoundException;
034 import org.apache.camel.component.bean.RegistryBean;
035 import org.apache.camel.language.bean.BeanExpression;
036 import org.apache.camel.util.ObjectHelper;
037 import org.apache.camel.util.OgnlHelper;
038
039 /**
040 * For expressions and predicates using the
041 * <a href="http://camel.apache.org/bean-language.html">bean language</a>
042 *
043 * @version
044 */
045 @XmlRootElement(name = "method")
046 @XmlAccessorType(XmlAccessType.FIELD)
047 public class MethodCallExpression extends ExpressionDefinition {
048 @XmlAttribute
049 @Deprecated
050 private String bean;
051 @XmlAttribute
052 private String ref;
053 @XmlAttribute
054 private String method;
055 @XmlAttribute(name = "beanType")
056 private String beanTypeName;
057 @XmlTransient
058 private Class<?> beanType;
059 @XmlTransient
060 private Object instance;
061
062 public MethodCallExpression() {
063 }
064
065 public MethodCallExpression(String beanName) {
066 this(beanName, null);
067 }
068
069 public MethodCallExpression(String beanName, String method) {
070 super(beanName);
071 this.method = method;
072 }
073
074 public MethodCallExpression(Object instance) {
075 this(instance, null);
076 }
077
078 public MethodCallExpression(Object instance, String method) {
079 super(ObjectHelper.className(instance));
080 // must use setter as they have special logic
081 setInstance(instance);
082 setMethod(method);
083 }
084
085 public MethodCallExpression(Class<?> type) {
086 this(type, null);
087 }
088
089 public MethodCallExpression(Class<?> type, String method) {
090 super(type.getName());
091 this.beanType = type;
092 this.method = method;
093 }
094
095 public String getLanguage() {
096 return "bean";
097 }
098
099 public String getBean() {
100 return bean;
101 }
102
103 public void setBean(String bean) {
104 this.bean = bean;
105 }
106
107 public String getRef() {
108 return ref;
109 }
110
111 public void setRef(String ref) {
112 this.ref = ref;
113 }
114
115 public String getMethod() {
116 return method;
117 }
118
119 public void setMethod(String method) {
120 this.method = method;
121 }
122
123 public Class<?> getBeanType() {
124 return beanType;
125 }
126
127 public void setBeanType(Class<?> beanType) {
128 this.beanType = beanType;
129 this.instance = null;
130 }
131
132 public String getBeanTypeName() {
133 return beanTypeName;
134 }
135
136 public void setBeanTypeName(String beanTypeName) {
137 this.beanTypeName = beanTypeName;
138 }
139
140 public Object getInstance() {
141 return instance;
142 }
143
144 public void setInstance(Object instance) {
145 // people may by mistake pass in a class type as the instance
146 if (instance instanceof Class) {
147 this.beanType = (Class<?>) instance;
148 this.instance = null;
149 } else {
150 this.beanType = null;
151 this.instance = instance;
152 }
153 }
154
155 @Override
156 public Expression createExpression(CamelContext camelContext) {
157 Expression answer;
158
159 if (beanType == null && beanTypeName != null) {
160 try {
161 beanType = camelContext.getClassResolver().resolveMandatoryClass(beanTypeName);
162 } catch (ClassNotFoundException e) {
163 throw ObjectHelper.wrapRuntimeCamelException(e);
164 }
165 }
166
167 BeanHolder holder;
168 if (beanType != null) {
169 // create a bean if there is a default public no-arg constructor
170 if (ObjectHelper.hasDefaultPublicNoArgConstructor(beanType)) {
171 instance = camelContext.getInjector().newInstance(beanType);
172 holder = new ConstantBeanHolder(instance, camelContext);
173 } else {
174 holder = new ConstantTypeBeanHolder(beanType, camelContext);
175 }
176 } else if (instance != null) {
177 holder = new ConstantBeanHolder(instance, camelContext);
178 } else {
179 String ref = beanName();
180 // if its a ref then check that the ref exists
181 BeanHolder regHolder = new RegistryBean(camelContext, ref);
182 // get the bean which will check that it exists
183 instance = regHolder.getBean();
184 holder = new ConstantBeanHolder(instance, camelContext);
185 }
186
187 // create answer using the holder
188 answer = new BeanExpression(holder, getMethod());
189
190 // and do sanity check that if a method name was given, that it exists
191 validateHasMethod(camelContext, instance, beanType, getMethod());
192 return answer;
193 }
194
195 @Override
196 public Predicate createPredicate(CamelContext camelContext) {
197 return (BeanExpression) createExpression(camelContext);
198 }
199
200 /**
201 * Validates the given bean has the method.
202 * <p/>
203 * This implementation will skip trying to validate OGNL method name expressions.
204 *
205 * @param context camel context
206 * @param bean the bean instance
207 * @param type the bean type
208 * @param method the method, can be <tt>null</tt> if no method name provided
209 * @throws org.apache.camel.RuntimeCamelException is thrown if bean does not have the method
210 */
211 protected void validateHasMethod(CamelContext context, Object bean, Class<?> type, String method) {
212 if (method == null) {
213 return;
214 }
215
216 if (bean == null && type == null) {
217 throw new IllegalArgumentException("Either bean or type should be provided on " + this);
218 }
219
220 // do not try to validate ognl methods
221 if (OgnlHelper.isValidOgnlExpression(method)) {
222 return;
223 }
224
225 // if invalid OGNL then fail
226 if (OgnlHelper.isInvalidValidOgnlExpression(method)) {
227 ExpressionIllegalSyntaxException cause = new ExpressionIllegalSyntaxException(method);
228 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(bean != null ? bean : type, method, cause));
229 }
230
231 if (bean != null) {
232 BeanInfo info = new BeanInfo(context, bean.getClass());
233 if (!info.hasMethod(method)) {
234 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, bean, method));
235 }
236 } else {
237 BeanInfo info = new BeanInfo(context, type);
238 // must be a static method as we do not have a bean instance to invoke
239 if (!info.hasStaticMethod(method)) {
240 throw ObjectHelper.wrapRuntimeCamelException(new MethodNotFoundException(null, type, method, true));
241 }
242 }
243 }
244
245 protected String beanName() {
246 if (bean != null) {
247 return bean;
248 } else if (ref != null) {
249 return ref;
250 } else if (instance != null) {
251 return ObjectHelper.className(instance);
252 }
253 return getExpression();
254 }
255
256 @Override
257 public String toString() {
258 return "bean{" + beanName() + (method != null ? ", method=" + method : "") + "}";
259 }
260 }