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