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