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    }