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    
018    package org.apache.commons.jexl2.internal;
019    import java.lang.reflect.InvocationTargetException;
020    /**
021     * Specialized executor to set a property in an object.
022     * @since 2.0
023     */
024    public final class PropertySetExecutor extends AbstractExecutor.Set {
025        /** Index of the first character of the set{p,P}roperty. */
026        private static final int SET_START_INDEX = 3;
027        /** The property. */
028        private final String property;
029    
030        /**
031         * Creates an instance by attempting discovery of the set method.
032         * @param is the introspector
033         * @param clazz the class to introspect
034         * @param identifier the property to set
035         * @param arg the value to set into the property
036         */
037        public PropertySetExecutor(Introspector is, Class<?> clazz, String identifier, Object arg) {
038            super(clazz, discover(is, clazz, identifier, arg));
039            property = identifier;
040    
041        }
042    
043        /** {@inheritDoc} */
044        @Override
045        public Object getTargetProperty() {
046            return property;
047        }
048    
049        /** {@inheritDoc} */
050        @Override
051        public Object execute(Object o, Object arg)
052                throws IllegalAccessException, InvocationTargetException {
053            Object[] pargs = {arg};
054            if (method != null) {
055                method.invoke(o, pargs);
056            }
057            return arg;
058        }
059    
060        /** {@inheritDoc} */
061        @Override
062        public Object tryExecute(Object o, Object identifier, Object arg) {
063            if (o != null && method != null
064                // ensure method name matches the property name
065                && property.equals(identifier)
066                // object class should be same as executor's method declaring class
067                && objectClass.equals(o.getClass())
068                // we are guaranteed the method has one parameter since it is a set(x)
069                && (arg == null || method.getParameterTypes()[0].equals(arg.getClass()))) {
070                try {
071                    return execute(o, arg);
072                } catch (InvocationTargetException xinvoke) {
073                    return TRY_FAILED; // fail
074                } catch (IllegalAccessException xill) {
075                    return TRY_FAILED;// fail
076                }
077            }
078            return TRY_FAILED;
079        }
080    
081    
082        /**
083         * Discovers the method for a {@link PropertySet}.
084         * <p>The method to be found should be named "set{P,p}property.</p>
085         *@param is the introspector
086         *@param clazz the class to find the get method from
087         *@param property the name of the property to set
088         *@param arg the value to assign to the property
089         *@return the method if found, null otherwise
090         */
091        private static java.lang.reflect.Method discover(Introspector is,
092                final Class<?> clazz, String property, Object arg) {
093            // first, we introspect for the set<identifier> setter method
094            Object[] params = {arg};
095            StringBuilder sb = new StringBuilder("set");
096            sb.append(property);
097            // uppercase nth char
098            char c = sb.charAt(SET_START_INDEX);
099            sb.setCharAt(SET_START_INDEX, Character.toUpperCase(c));
100            java.lang.reflect.Method method = is.getMethod(clazz, sb.toString(), params);
101            // lowercase nth char
102            if (method == null) {
103                sb.setCharAt(SET_START_INDEX, Character.toLowerCase(c));
104                method = is.getMethod(clazz, sb.toString(), params);
105            }
106    
107            return method;
108        }
109    }
110