    001    /* $Id: SetPropertyRule.java 568192 2007-08-21 16:41:16Z bayard $
    002     *
    003     * Licensed to the Apache Software Foundation (ASF) under one or more
    004     * contributor license agreements.  See the NOTICE file distributed with
    005     * this work for additional information regarding copyright ownership.
    006     * The ASF licenses this file to You under the Apache License, Version 2.0
    007     * (the "License"); you may not use this file except in compliance with
    008     * the License.  You may obtain a copy of the License at
    009     *
    010     *      http://www.apache.org/licenses/LICENSE-2.0
    011     *
    012     * Unless required by applicable law or agreed to in writing, software
    013     * distributed under the License is distributed on an "AS IS" BASIS,
    014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    015     * See the License for the specific language governing permissions and
    016     * limitations under the License.
    017     */
    018
    019
    020    package org.apache.commons.digester;
    021
    022
    023    import java.beans.PropertyDescriptor;
    024
    025    import org.apache.commons.beanutils.BeanUtils;
    026    import org.apache.commons.beanutils.DynaBean;
    027    import org.apache.commons.beanutils.DynaProperty;
    028    import org.apache.commons.beanutils.PropertyUtils;
    029    import org.xml.sax.Attributes;
    030
    031
    032    /**
    033     * Rule implementation that sets an individual property on the object at the
    034     * top of the stack, based on attributes with specified names.
    035     */
    036
    037    public class SetPropertyRule extends Rule {
    038
    039
    040        // ----------------------------------------------------------- Constructors
    041
    042
    043        /**
    044         * Construct a "set property" rule with the specified name and value
    045         * attributes.
    046         *
    047         * @param digester The digester with which this rule is associated
    048         * @param name Name of the attribute that will contain the name of the
    049         *  property to be set
    050         * @param value Name of the attribute that will contain the value to which
    051         *  the property should be set
    052         *
    053         * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
    054         * Use {@link #SetPropertyRule(String name, String value)} instead.
    055         */
    056        public SetPropertyRule(Digester digester, String name, String value) {
    057
    058            this(name, value);
    059
    060        }
    061
    062        /**
    063         * Construct a "set property" rule with the specified name and value
    064         * attributes.
    065         *
    066         * @param name Name of the attribute that will contain the name of the
    067         *  property to be set
    068         * @param value Name of the attribute that will contain the value to which
    069         *  the property should be set
    070         */
    071        public SetPropertyRule(String name, String value) {
    072
    073            this.name = name;
    074            this.value = value;
    075
    076        }
    077
    078        // ----------------------------------------------------- Instance Variables
    079
    080
    081        /**
    082         * The attribute that will contain the property name.
    083         */
    084        protected String name = null;
    085
    086
    087        /**
    088         * The attribute that will contain the property value.
    089         */
    090        protected String value = null;
    091
    092
    093        // --------------------------------------------------------- Public Methods
    094
    095
    096        /**
    097         * Process the beginning of this element.
    098         *
    099         * @param attributes The attribute list of this element
    100         *
    101         * @exception NoSuchMethodException if the bean does not
    102         *  have a writeable property of the specified name
    103         */
    104        public void begin(Attributes attributes) throws Exception {
    105
    106            if (attributes.getLength() == 0 ) {
    107                return;
    108            }
    109
    110            // Identify the actual property name and value to be used
    111            String actualName = null;
    112            String actualValue = null;
    113            for (int i = 0; i < attributes.getLength(); i++) {
    114                String name = attributes.getLocalName(i);
    115                if ("".equals(name)) {
    116                    name = attributes.getQName(i);
    117                }
    118                String value = attributes.getValue(i);
    119                if (name.equals(this.name)) {
    120                    actualName = value;
    121                } else if (name.equals(this.value)) {
    122                    actualValue = value;
    123                }
    124            }
    125
    126            // Get a reference to the top object
    127            Object top = digester.peek();
    128
    129            // Log some debugging information
    130            if (digester.log.isDebugEnabled()) {
    131                digester.log.debug("[SetPropertyRule]{" + digester.match +
    132                        "} Set " + top.getClass().getName() + " property " +
    133                        actualName + " to " + actualValue);
    134            }
    135
    136            // Force an exception if the property does not exist
    137            // (BeanUtils.setProperty() silently returns in this case)
    138            //
    139            // This code should probably use PropertyUtils.isWriteable(),
    140            // like SetPropertiesRule does.
    141            if (top instanceof DynaBean) {
    142                DynaProperty desc =
    143                    ((DynaBean) top).getDynaClass().getDynaProperty(actualName);
    144                if (desc == null) {
    145                    throw new NoSuchMethodException
    146                        ("Bean has no property named " + actualName);
    147                }
    148            } else /* this is a standard JavaBean */ {
    149                PropertyDescriptor desc =
    150                    PropertyUtils.getPropertyDescriptor(top, actualName);
    151                if (desc == null) {
    152                    throw new NoSuchMethodException
    153                        ("Bean has no property named " + actualName);
    154                }
    155            }
    156
    157            // Set the property (with conversion as necessary)
    158            BeanUtils.setProperty(top, actualName, actualValue);
    159
    160        }
    161
    162
    163        /**
    164         * Render a printable version of this Rule.
    165         */
    166        public String toString() {
    167
    168            StringBuffer sb = new StringBuffer("SetPropertyRule[");
    169            sb.append("name=");
    170            sb.append(name);
    171            sb.append(", value=");
    172            sb.append(value);
    173            sb.append("]");
    174            return (sb.toString());
    175
    176        }
    177
    178
    179    }