001/* $Id: SetPropertyRule.java 992060 2010-09-02 19:09:47Z simonetripodi $
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
020package org.apache.commons.digester;
021
022
023import java.beans.PropertyDescriptor;
024
025import org.apache.commons.beanutils.BeanUtils;
026import org.apache.commons.beanutils.DynaBean;
027import org.apache.commons.beanutils.DynaProperty;
028import org.apache.commons.beanutils.PropertyUtils;
029import 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
037public 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    @Deprecated
057    public SetPropertyRule(Digester digester, String name, String value) {
058
059        this(name, value);
060
061    }
062
063    /**
064     * Construct a "set property" rule with the specified name and value
065     * attributes.
066     *
067     * @param name Name of the attribute that will contain the name of the
068     *  property to be set
069     * @param value Name of the attribute that will contain the value to which
070     *  the property should be set
071     */
072    public SetPropertyRule(String name, String value) {
073
074        this.name = name;
075        this.value = value;
076
077    }
078
079    // ----------------------------------------------------- Instance Variables
080
081
082    /**
083     * The attribute that will contain the property name.
084     */
085    protected String name = null;
086
087
088    /**
089     * The attribute that will contain the property value.
090     */
091    protected String value = null;
092
093
094    // --------------------------------------------------------- Public Methods
095
096
097    /**
098     * Process the beginning of this element.
099     *
100     * @param attributes The attribute list of this element
101     *
102     * @exception NoSuchMethodException if the bean does not
103     *  have a writeable property of the specified name
104     */
105    @Override
106    public void begin(Attributes attributes) throws Exception {
107
108        if (attributes.getLength() == 0 ) {
109            return;
110        }
111
112        // Identify the actual property name and value to be used
113        String actualName = null;
114        String actualValue = null;
115        for (int i = 0; i < attributes.getLength(); i++) {
116            String name = attributes.getLocalName(i);
117            if ("".equals(name)) {
118                name = attributes.getQName(i);
119            }
120            String value = attributes.getValue(i);
121            if (name.equals(this.name)) {
122                actualName = value;
123            } else if (name.equals(this.value)) {
124                actualValue = value;
125            }
126        }
127
128        // Get a reference to the top object
129        Object top = digester.peek();
130
131        // Log some debugging information
132        if (digester.log.isDebugEnabled()) {
133            digester.log.debug("[SetPropertyRule]{" + digester.match +
134                    "} Set " + top.getClass().getName() + " property " +
135                    actualName + " to " + actualValue);
136        }
137
138        // Force an exception if the property does not exist
139        // (BeanUtils.setProperty() silently returns in this case)
140        //
141        // This code should probably use PropertyUtils.isWriteable(), 
142        // like SetPropertiesRule does.
143        if (top instanceof DynaBean) {
144            DynaProperty desc =
145                ((DynaBean) top).getDynaClass().getDynaProperty(actualName);
146            if (desc == null) {
147                throw new NoSuchMethodException
148                    ("Bean has no property named " + actualName);
149            }
150        } else /* this is a standard JavaBean */ {
151            PropertyDescriptor desc =
152                PropertyUtils.getPropertyDescriptor(top, actualName);
153            if (desc == null) {
154                throw new NoSuchMethodException
155                    ("Bean has no property named " + actualName);
156            }
157        }
158
159        // Set the property (with conversion as necessary)
160        BeanUtils.setProperty(top, actualName, actualValue);
161
162    }
163
164
165    /**
166     * Render a printable version of this Rule.
167     */
168    @Override
169    public String toString() {
170
171        StringBuffer sb = new StringBuffer("SetPropertyRule[");
172        sb.append("name=");
173        sb.append(name);
174        sb.append(", value=");
175        sb.append(value);
176        sb.append("]");
177        return (sb.toString());
178
179    }
180
181
182}