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.language; 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.CamelContext; 026import org.apache.camel.Expression; 027import org.apache.camel.ExpressionIllegalSyntaxException; 028import org.apache.camel.Predicate; 029import org.apache.camel.component.bean.BeanHolder; 030import org.apache.camel.component.bean.BeanInfo; 031import org.apache.camel.component.bean.ConstantBeanHolder; 032import org.apache.camel.component.bean.ConstantStaticTypeBeanHolder; 033import org.apache.camel.component.bean.MethodNotFoundException; 034import org.apache.camel.component.bean.RegistryBean; 035import org.apache.camel.language.bean.BeanExpression; 036import org.apache.camel.util.ObjectHelper; 037import 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) 047public 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 ConstantStaticTypeBeanHolder(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}