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.AfterPropertiesConfigured;
026import org.apache.camel.CamelContext;
027import org.apache.camel.Expression;
028import org.apache.camel.Predicate;
029import org.apache.camel.RuntimeCamelException;
030import org.apache.camel.spi.Language;
031import org.apache.camel.spi.Metadata;
032import org.apache.camel.util.ObjectHelper;
033
034/**
035 * To use a Java bean (aka method call) in Camel expressions or predicates.
036 */
037@Metadata(firstVersion = "1.3.0", label = "language,core,java", title = "Bean method")
038@XmlRootElement(name = "method")
039@XmlAccessorType(XmlAccessType.FIELD)
040public class MethodCallExpression extends ExpressionDefinition {
041    @XmlAttribute
042    private String ref;
043    @XmlAttribute
044    private String method;
045    @XmlAttribute(name = "beanType")
046    private String beanTypeName;
047    @XmlTransient
048    private Class<?> beanType;
049    @XmlTransient
050    private Object instance;
051
052    public MethodCallExpression() {
053    }
054
055    public MethodCallExpression(String beanName) {
056        this(beanName, null);
057    }
058
059    public MethodCallExpression(String beanName, String method) {
060        super((String)null); // we dont use @XmlValue but the attributes instead
061        if (beanName != null && beanName.startsWith("ref:")) {
062            beanName = beanName.substring(4);
063        } else if (beanName != null && beanName.startsWith("bean:")) {
064            beanName = beanName.substring(5);
065        }
066        setRef(beanName);
067        setMethod(method);
068    }
069
070    public MethodCallExpression(Object instance) {
071        this(instance, null);
072    }
073
074    public MethodCallExpression(Object instance, String method) {
075        super((String)null); // we dont use @XmlValue but the attributes instead
076        // must use setter as they have special logic
077        setInstance(instance);
078        setMethod(method);
079    }
080
081    public MethodCallExpression(Class<?> type) {
082        this(type, null);
083    }
084
085    public MethodCallExpression(Class<?> type, String method) {
086        super((String)null); // we dont use @XmlValue but the attributes instead
087        setBeanType(type);
088        setBeanTypeName(type.getName());
089        setMethod(method);
090    }
091
092    @Override
093    public String getLanguage() {
094        return "bean";
095    }
096
097    public String getRef() {
098        return ref;
099    }
100
101    /**
102     * Reference to bean to lookup in the registry
103     */
104    public void setRef(String ref) {
105        this.ref = ref;
106    }
107
108    public String getMethod() {
109        return method;
110    }
111
112    /**
113     * Name of method to call
114     */
115    public void setMethod(String method) {
116        this.method = method;
117    }
118
119    public Class<?> getBeanType() {
120        return beanType;
121    }
122
123    public void setBeanType(Class<?> beanType) {
124        this.beanType = beanType;
125        this.instance = null;
126    }
127
128    public String getBeanTypeName() {
129        return beanTypeName;
130    }
131
132    /**
133     * Class name of the bean to use
134     */
135    public void setBeanTypeName(String beanTypeName) {
136        this.beanTypeName = beanTypeName;
137    }
138
139    public Object getInstance() {
140        return instance;
141    }
142
143    public void setInstance(Object instance) {
144        // people may by mistake pass in a class type as the instance
145        if (instance instanceof Class) {
146            this.beanType = (Class<?>)instance;
147            this.instance = null;
148        } else {
149            this.beanType = null;
150            this.instance = instance;
151        }
152    }
153
154    @Override
155    public Expression createExpression(CamelContext camelContext) {
156        if (beanType == null && beanTypeName != null) {
157            try {
158                beanType = camelContext.getClassResolver().resolveMandatoryClass(beanTypeName);
159            } catch (ClassNotFoundException e) {
160                throw RuntimeCamelException.wrapRuntimeCamelException(e);
161            }
162        }
163
164        // special for bean language where we need to configure it first
165        Language lan = camelContext.resolveLanguage("bean");
166        configureLanguage(camelContext, lan);
167        // .. and create expression with null value as we use the configured
168        // properties instead
169        Expression exp = lan.createExpression(null);
170        if (exp instanceof AfterPropertiesConfigured) {
171            ((AfterPropertiesConfigured)exp).afterPropertiesConfigured(camelContext);
172        }
173        return exp;
174    }
175
176    protected void configureLanguage(CamelContext camelContext, Language language) {
177        if (instance != null) {
178            setProperty(camelContext, language, "bean", instance);
179        }
180        if (beanType != null) {
181            setProperty(camelContext, language, "beanType", beanType);
182        }
183        if (ref != null) {
184            setProperty(camelContext, language, "ref", ref);
185        }
186        if (method != null) {
187            setProperty(camelContext, language, "method", method);
188        }
189    }
190
191    @Override
192    public Predicate createPredicate(CamelContext camelContext) {
193        return (Predicate)createExpression(camelContext);
194    }
195
196    private String beanName() {
197        if (ref != null) {
198            return ref;
199        } else if (instance != null) {
200            return ObjectHelper.className(instance);
201        }
202        return getExpression();
203    }
204
205    @Override
206    public String toString() {
207        boolean isRef = ref != null;
208        return "bean[" + (isRef ? "ref:" : "") + beanName() + (method != null ? " method:" + method : "") + "]";
209    }
210
211}