1. /* $Id: BeanPropertySetterRule.java,v 1.20 2004/05/10 06:30:06 skitching Exp $
  2. *
  3. * Copyright 2001-2004 The Apache Software Foundation.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.commons.digester;
  18. import java.beans.PropertyDescriptor;
  19. import org.apache.commons.beanutils.BeanUtils;
  20. import org.apache.commons.beanutils.DynaBean;
  21. import org.apache.commons.beanutils.DynaProperty;
  22. import org.apache.commons.beanutils.PropertyUtils;
  23. /**
  24. * <p> Rule implements sets a bean property on the top object
  25. * to the body text.</p>
  26. *
  27. * <p> The property set:</p>
  28. * <ul><li>can be specified when the rule is created</li>
  29. * <li>or can match the current element when the rule is called.</li></ul>
  30. *
  31. * <p> Using the second method and the {@link ExtendedBaseRules} child match
  32. * pattern, all the child elements can be automatically mapped to properties
  33. * on the parent object.</p>
  34. */
  35. public class BeanPropertySetterRule extends Rule {
  36. // ----------------------------------------------------------- Constructors
  37. /**
  38. * <p>Construct rule that sets the given property from the body text.</p>
  39. *
  40. * @param digester associated <code>Digester</code>
  41. * @param propertyName name of property to set
  42. *
  43. * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
  44. * Use {@link #BeanPropertySetterRule(String propertyName)} instead.
  45. */
  46. public BeanPropertySetterRule(Digester digester, String propertyName) {
  47. this(propertyName);
  48. }
  49. /**
  50. * <p>Construct rule that automatically sets a property from the body text.
  51. *
  52. * <p> This construct creates a rule that sets the property
  53. * on the top object named the same as the current element.
  54. *
  55. * @param digester associated <code>Digester</code>
  56. *
  57. * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
  58. * Use {@link #BeanPropertySetterRule()} instead.
  59. */
  60. public BeanPropertySetterRule(Digester digester) {
  61. this();
  62. }
  63. /**
  64. * <p>Construct rule that sets the given property from the body text.</p>
  65. *
  66. * @param propertyName name of property to set
  67. */
  68. public BeanPropertySetterRule(String propertyName) {
  69. this.propertyName = propertyName;
  70. }
  71. /**
  72. * <p>Construct rule that automatically sets a property from the body text.
  73. *
  74. * <p> This construct creates a rule that sets the property
  75. * on the top object named the same as the current element.
  76. */
  77. public BeanPropertySetterRule() {
  78. this((String)null);
  79. }
  80. // ----------------------------------------------------- Instance Variables
  81. /**
  82. * Set this property on the top object.
  83. */
  84. protected String propertyName = null;
  85. /**
  86. * The body text used to set the property.
  87. */
  88. protected String bodyText = null;
  89. // --------------------------------------------------------- Public Methods
  90. /**
  91. * Process the body text of this element.
  92. *
  93. * @param namespace the namespace URI of the matching element, or an
  94. * empty string if the parser is not namespace aware or the element has
  95. * no namespace
  96. * @param name the local name if the parser is namespace aware, or just
  97. * the element name otherwise
  98. * @param text The text of the body of this element
  99. */
  100. public void body(String namespace, String name, String text)
  101. throws Exception {
  102. // log some debugging information
  103. if (digester.log.isDebugEnabled()) {
  104. digester.log.debug("[BeanPropertySetterRule]{" +
  105. digester.match + "} Called with text '" + text + "'");
  106. }
  107. bodyText = text.trim();
  108. }
  109. /**
  110. * Process the end of this element.
  111. *
  112. * @param namespace the namespace URI of the matching element, or an
  113. * empty string if the parser is not namespace aware or the element has
  114. * no namespace
  115. * @param name the local name if the parser is namespace aware, or just
  116. * the element name otherwise
  117. *
  118. * @exception NoSuchMethodException if the bean does not
  119. * have a writeable property of the specified name
  120. */
  121. public void end(String namespace, String name) throws Exception {
  122. String property = propertyName;
  123. if (property == null) {
  124. // If we don't have a specific property name,
  125. // use the element name.
  126. property = name;
  127. }
  128. // Get a reference to the top object
  129. Object top = digester.peek();
  130. // log some debugging information
  131. if (digester.log.isDebugEnabled()) {
  132. digester.log.debug("[BeanPropertySetterRule]{" + digester.match +
  133. "} Set " + top.getClass().getName() + " property " +
  134. property + " with text " + bodyText);
  135. }
  136. // Force an exception if the property does not exist
  137. // (BeanUtils.setProperty() silently returns in this case)
  138. if (top instanceof DynaBean) {
  139. DynaProperty desc =
  140. ((DynaBean) top).getDynaClass().getDynaProperty(property);
  141. if (desc == null) {
  142. throw new NoSuchMethodException
  143. ("Bean has no property named " + property);
  144. }
  145. } else /* this is a standard JavaBean */ {
  146. PropertyDescriptor desc =
  147. PropertyUtils.getPropertyDescriptor(top, property);
  148. if (desc == null) {
  149. throw new NoSuchMethodException
  150. ("Bean has no property named " + property);
  151. }
  152. }
  153. // Set the property (with conversion as necessary)
  154. BeanUtils.setProperty(top, property, bodyText);
  155. }
  156. /**
  157. * Clean up after parsing is complete.
  158. */
  159. public void finish() throws Exception {
  160. bodyText = null;
  161. }
  162. /**
  163. * Render a printable version of this Rule.
  164. */
  165. public String toString() {
  166. StringBuffer sb = new StringBuffer("BeanPropertySetterRule[");
  167. sb.append("propertyName=");
  168. sb.append(propertyName);
  169. sb.append("]");
  170. return (sb.toString());
  171. }
  172. }