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.language.juel;
018    
019    import java.lang.reflect.Method;
020    import java.lang.reflect.Modifier;
021    import java.util.ArrayList;
022    import java.util.List;
023    
024    import javax.el.BeanELResolver;
025    import javax.el.ELContext;
026    import javax.el.PropertyNotFoundException;
027    
028    /**
029     * An extension of the JUEL {@link BeanELResolver} which also supports the resolving of methods
030     *
031     * @version 
032     */
033    public class BeanAndMethodELResolver extends BeanELResolver {
034        public BeanAndMethodELResolver() {
035            super(false);
036        }
037    
038        @Override
039        public Object getValue(ELContext elContext, Object base, Object property) {
040            try {
041                return (property instanceof Method) ? property : super.getValue(elContext, base, property);
042            } catch (PropertyNotFoundException e) {
043                // lets see if its a method call...
044                Method method = findMethod(elContext, base, property);
045                if (method != null) {
046                    elContext.setPropertyResolved(true);
047                    return method;
048                } else {
049                    throw e;
050                }
051            }
052        }
053    
054        protected Method findMethod(ELContext elContext, Object base, Object property) {
055            if (base != null) {
056                Method[] methods = base.getClass().getMethods();
057                List<Method> matching = new ArrayList<Method>();
058                for (Method method : methods) {
059                    if (method.getName().equals(property.toString()) && Modifier.isPublic(method.getModifiers())) {
060                        matching.add(method);
061                    }
062                }
063                int size = matching.size();
064                if (size > 0) {
065                    if (size > 1) {
066                        // TODO there's currently no way for JUEL to tell us how many parameters there are
067                        // so lets just pick the first one that has a single param by default
068                        for (Method method : matching) {
069                            Class<?>[] paramTypes = method.getParameterTypes();
070                            if (paramTypes.length == 1) {
071                                return method;
072                            }
073                        }
074                    }
075                    // lets default to the first one
076                    return matching.get(0);
077                }
078            }
079            return null;
080        }
081    }