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.commons.jexl2.internal;
018    
019    import java.lang.reflect.InvocationTargetException;
020    
021    /**
022     * Specialized executor to set a property of an object.
023     * <p>Duck as in duck-typing for an interface like:
024     * <code>
025     * interface Set {
026     *      Object set(Object property, Object value);
027     * }
028     * </code>
029     * </p>
030     * @since 2.0
031     */
032    public final class DuckSetExecutor extends AbstractExecutor.Set {
033        /** The property. */
034        private final Object property;
035        
036        /**
037         * Creates an instance.
038         *@param is the introspector
039         *@param clazz the class to find the set method from
040         *@param key the key to use as 1st argument to the set method
041         *@param value the value to use as 2nd argument to the set method
042         */
043        public DuckSetExecutor(Introspector is, Class<?> clazz, Object key, Object value) {
044            super(clazz, discover(is, clazz, key, value));
045            property = key;
046        }
047    
048        /** {@inheritDoc} */
049        @Override
050        public Object getTargetProperty() {
051            return property;
052        }
053    
054        /** {@inheritDoc} */
055        @Override
056        public Object execute(Object obj, Object value)
057                throws IllegalAccessException, InvocationTargetException {
058            Object[] pargs = {property, value};
059            if (method != null) {
060                method.invoke(obj, pargs);
061            }
062            return value;
063        }
064    
065        /** {@inheritDoc} */
066        @Override
067        public Object tryExecute(Object obj, Object key, Object value) {
068            if (obj != null && method !=  null
069                // ensure method name matches the property name
070                && property.equals(key)
071                && objectClass.equals(obj.getClass())) {
072                try {
073                    Object[] args = {property, value};
074                    method.invoke(obj, args);
075                    return value;
076                } catch (InvocationTargetException xinvoke) {
077                    return TRY_FAILED; // fail
078                } catch (IllegalAccessException xill) {
079                    return TRY_FAILED;// fail
080                }
081            }
082            return TRY_FAILED;
083        }
084    
085        /**
086         * Discovers the method for a {@link DuckSet}.
087         *@param is the introspector
088         *@param clazz the class to find the set method from
089         *@param key the key to use as 1st argument to the set method
090         *@param value the value to use as 2nd argument to the set method
091         *@return the method if found, null otherwise
092         */
093        private static java.lang.reflect.Method discover(Introspector is,
094                Class<?> clazz, Object key, Object value) {
095            return is.getMethod(clazz, "set", makeArgs(key, value));
096        }
097    }