001 /* $Id: BeanPropertySetterRule.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
030
031 /**
032 * <p> Rule implements sets a bean property on the top object
033 * to the body text.</p>
034 *
035 * <p> The property set:</p>
036 * <ul><li>can be specified when the rule is created</li>
037 * <li>or can match the current element when the rule is called.</li></ul>
038 *
039 * <p> Using the second method and the {@link ExtendedBaseRules} child match
040 * pattern, all the child elements can be automatically mapped to properties
041 * on the parent object.</p>
042 */
043
044 public class BeanPropertySetterRule extends Rule {
045
046
047 // ----------------------------------------------------------- Constructors
048
049
050 /**
051 * <p>Construct rule that sets the given property from the body text.</p>
052 *
053 * @param digester associated <code>Digester</code>
054 * @param propertyName name of property to set
055 *
056 * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
057 * Use {@link #BeanPropertySetterRule(String propertyName)} instead.
058 */
059 @Deprecated
060 public BeanPropertySetterRule(Digester digester, String propertyName) {
061
062 this(propertyName);
063
064 }
065
066 /**
067 * <p>Construct rule that automatically sets a property from the body text.
068 *
069 * <p> This construct creates a rule that sets the property
070 * on the top object named the same as the current element.
071 *
072 * @param digester associated <code>Digester</code>
073 *
074 * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
075 * Use {@link #BeanPropertySetterRule()} instead.
076 */
077 @Deprecated
078 public BeanPropertySetterRule(Digester digester) {
079
080 this();
081
082 }
083
084 /**
085 * <p>Construct rule that sets the given property from the body text.</p>
086 *
087 * @param propertyName name of property to set
088 */
089 public BeanPropertySetterRule(String propertyName) {
090
091 this.propertyName = propertyName;
092
093 }
094
095 /**
096 * <p>Construct rule that automatically sets a property from the body text.
097 *
098 * <p> This construct creates a rule that sets the property
099 * on the top object named the same as the current element.
100 */
101 public BeanPropertySetterRule() {
102
103 this((String)null);
104
105 }
106
107 // ----------------------------------------------------- Instance Variables
108
109
110 /**
111 * Set this property on the top object.
112 */
113 protected String propertyName = null;
114
115
116 /**
117 * The body text used to set the property.
118 */
119 protected String bodyText = null;
120
121
122 // --------------------------------------------------------- Public Methods
123
124
125 /**
126 * Process the body text of this element.
127 *
128 * @param namespace the namespace URI of the matching element, or an
129 * empty string if the parser is not namespace aware or the element has
130 * no namespace
131 * @param name the local name if the parser is namespace aware, or just
132 * the element name otherwise
133 * @param text The text of the body of this element
134 */
135 @Override
136 public void body(String namespace, String name, String text)
137 throws Exception {
138
139 // log some debugging information
140 if (digester.log.isDebugEnabled()) {
141 digester.log.debug("[BeanPropertySetterRule]{" +
142 digester.match + "} Called with text '" + text + "'");
143 }
144
145 bodyText = text.trim();
146
147 }
148
149
150 /**
151 * Process the end of this element.
152 *
153 * @param namespace the namespace URI of the matching element, or an
154 * empty string if the parser is not namespace aware or the element has
155 * no namespace
156 * @param name the local name if the parser is namespace aware, or just
157 * the element name otherwise
158 *
159 * @exception NoSuchMethodException if the bean does not
160 * have a writeable property of the specified name
161 */
162 @Override
163 public void end(String namespace, String name) throws Exception {
164
165 String property = propertyName;
166
167 if (property == null) {
168 // If we don't have a specific property name,
169 // use the element name.
170 property = name;
171 }
172
173 // Get a reference to the top object
174 Object top = digester.peek();
175
176 // log some debugging information
177 if (digester.log.isDebugEnabled()) {
178 digester.log.debug("[BeanPropertySetterRule]{" + digester.match +
179 "} Set " + top.getClass().getName() + " property " +
180 property + " with text " + bodyText);
181 }
182
183 // Force an exception if the property does not exist
184 // (BeanUtils.setProperty() silently returns in this case)
185 if (top instanceof DynaBean) {
186 DynaProperty desc =
187 ((DynaBean) top).getDynaClass().getDynaProperty(property);
188 if (desc == null) {
189 throw new NoSuchMethodException
190 ("Bean has no property named " + property);
191 }
192 } else /* this is a standard JavaBean */ {
193 PropertyDescriptor desc =
194 PropertyUtils.getPropertyDescriptor(top, property);
195 if (desc == null) {
196 throw new NoSuchMethodException
197 ("Bean has no property named " + property);
198 }
199 }
200
201 // Set the property (with conversion as necessary)
202 BeanUtils.setProperty(top, property, bodyText);
203
204 }
205
206
207 /**
208 * Clean up after parsing is complete.
209 */
210 @Override
211 public void finish() throws Exception {
212
213 bodyText = null;
214
215 }
216
217
218 /**
219 * Render a printable version of this Rule.
220 */
221 @Override
222 public String toString() {
223
224 StringBuffer sb = new StringBuffer("BeanPropertySetterRule[");
225 sb.append("propertyName=");
226 sb.append(propertyName);
227 sb.append("]");
228 return (sb.toString());
229
230 }
231
232 }