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