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    
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        @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    }