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
018package org.apache.commons.jexl2.internal;
019import java.lang.reflect.InvocationTargetException;
020/**
021 * Specialized executor to set a property in an object.
022 * @since 2.0
023 */
024public 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