001    /*
002     * Copyright 2002-2005 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.springframework.binding.value.support;
017    
018    import java.lang.reflect.Method;
019    
020    import org.springframework.binding.value.ValueModel;
021    import org.springframework.util.Assert;
022    
023    /**
024     * A value model that derives it's value from the result of invoking a method. 
025     * The parameters for the method invocation are generated from a list of
026     * "source" value models. Should any of the "source" values change the method
027     * will be invoked and if the return value has changed the value held by 
028     * this class will be updated.
029     *  
030     * @author  Oliver Hutchison
031     */
032    public final class MethodInvokingDerivedValueModel extends AbstractDerivedValueModel {
033    
034        private final Object target;
035    
036        private final Method method;
037    
038        private Object value;
039    
040        public MethodInvokingDerivedValueModel(Object target, String methodName, ValueModel[] paramSourceValueModels) {
041            super(paramSourceValueModels);
042            this.target = target;
043            this.method = getPropertyMethod(target, methodName, paramSourceValueModels.length);
044            Assert.notNull(method, "No method with name [" + methodName + "] and " + paramSourceValueModels.length
045                    + " parameters found on class.");
046            sourceValuesChanged();
047        }
048    
049        protected void sourceValuesChanged() {
050            Object oldValue = value;
051            try {
052                value = method.invoke(target, getSourceValues());
053                fireValueChange(oldValue, value);
054            }
055            catch (Exception e) {
056                e.printStackTrace();
057            }
058        }
059    
060        public Object getValue() {
061            return value;
062        }
063    
064        private Method getPropertyMethod(Object target, String methodName, int numberOfParams) {
065            Method propertyMethod = null;
066            Method[] methods = target.getClass().getMethods();
067            for (int i = 0; i < methods.length; i++) {
068                Method method = methods[i];
069                if (method.getName().equals(methodName) && method.getParameterTypes().length == numberOfParams) {
070                    if (propertyMethod != null) {
071                        throw new UnsupportedOperationException("Found than one method with name '" + methodName + "' and "
072                                + numberOfParams + " parameters on class '" + target.getClass().getName() + "'.");
073                    }
074                    propertyMethod = method;
075                }
076            }
077            return propertyMethod;
078        }
079    }