1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.betwixt.digester;
  17. import java.beans.BeanInfo;
  18. import java.beans.Introspector;
  19. import java.beans.PropertyDescriptor;
  20. import java.util.Set;
  21. import org.apache.commons.betwixt.AttributeDescriptor;
  22. import org.apache.commons.betwixt.BeanProperty;
  23. import org.apache.commons.betwixt.Descriptor;
  24. import org.apache.commons.betwixt.ElementDescriptor;
  25. import org.apache.commons.betwixt.NodeDescriptor;
  26. import org.apache.commons.betwixt.XMLBeanInfo;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.xml.sax.Attributes;
  30. import org.xml.sax.SAXException;
  31. /** <p><code>AddDefaultsRule</code> appends all the default properties
  32. * to the current element.</p>
  33. *
  34. * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  35. */
  36. public class AddDefaultsRule extends RuleSupport {
  37. /** Logger */
  38. private static final Log log = LogFactory.getLog( AddDefaultsRule.class );
  39. /** Base constructor */
  40. public AddDefaultsRule() {
  41. }
  42. // Rule interface
  43. //-------------------------------------------------------------------------
  44. /**
  45. * Process the beginning of this element.
  46. *
  47. * @param attributes The attribute list of this element
  48. * @throws Exception generally this will indicate an unrecoverable error
  49. */
  50. public void begin(String name, String namespace, Attributes attributes) throws Exception {
  51. boolean addProperties = true;
  52. String addPropertiesAttributeValue = attributes.getValue("add-properties");
  53. if (addPropertiesAttributeValue != null)
  54. {
  55. addProperties = Boolean.valueOf(addPropertiesAttributeValue).booleanValue();
  56. }
  57. boolean addAdders = true;
  58. String addAddersAttributeValue = attributes.getValue("add-adders");
  59. if (addAddersAttributeValue != null)
  60. {
  61. addProperties = Boolean.valueOf(addAddersAttributeValue).booleanValue();
  62. }
  63. if (addProperties) {
  64. addDefaultProperties();
  65. }
  66. if (addAdders) {
  67. addAdders();
  68. }
  69. }
  70. /**
  71. * Adds default adder methods
  72. */
  73. private void addAdders() {
  74. Class beanClass = getBeanClass();
  75. // default any addProperty() methods
  76. getXMLIntrospector().defaultAddMethods(
  77. getRootElementDescriptor(),
  78. beanClass );
  79. }
  80. /**
  81. * Adds default property methods
  82. *
  83. */
  84. private void addDefaultProperties() {
  85. Class beanClass = getBeanClass();
  86. Set processedProperties = getProcessedPropertyNameSet();
  87. if ( beanClass != null ) {
  88. try {
  89. boolean attributesForPrimitives = getXMLInfoDigester().isAttributesForPrimitives();
  90. BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
  91. PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
  92. if ( descriptors != null ) {
  93. for ( int i = 0, size = descriptors.length; i < size; i++ ) {
  94. PropertyDescriptor descriptor = descriptors[i];
  95. // have we already created a property for this
  96. String propertyName = descriptor.getName();
  97. if ( processedProperties.contains( propertyName ) ) {
  98. continue;
  99. }
  100. Descriptor nodeDescriptor =
  101. getXMLIntrospector().createXMLDescriptor(new BeanProperty(descriptor));
  102. if ( nodeDescriptor != null ) {
  103. addDescriptor( nodeDescriptor );
  104. }
  105. }
  106. }
  107. } catch (Exception e) {
  108. log.info( "Caught introspection exception", e );
  109. }
  110. }
  111. }
  112. // Implementation methods
  113. //-------------------------------------------------------------------------
  114. /**
  115. * Add a desciptor to the top object on the Digester stack.
  116. *
  117. * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
  118. * @throws SAXException if the parent for the addDefaults element is not a <element>
  119. * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a
  120. * <code>ElementDescriptor</code>
  121. * @deprecated 0.5 replaced {@link #addDescriptor( Descriptor )}
  122. */
  123. protected void addDescriptor( NodeDescriptor nodeDescriptor ) throws SAXException {
  124. addDescriptor( (Descriptor) nodeDescriptor );
  125. }
  126. /**
  127. * Add a desciptor to the top object on the Digester stack.
  128. *
  129. * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
  130. * @throws SAXException if the parent for the addDefaults element is not a <element>
  131. * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a
  132. * <code>ElementDescriptor</code>
  133. * @since 0.5
  134. */
  135. protected void addDescriptor( Descriptor nodeDescriptor ) throws SAXException {
  136. Object top = digester.peek();
  137. if ( top instanceof XMLBeanInfo ) {
  138. log.warn( "It is advisable to put an <addDefaults/> element inside an <element> tag" );
  139. XMLBeanInfo beanInfo = (XMLBeanInfo) top;
  140. // if there is already a root element descriptor then use it
  141. // otherwise use this descriptor
  142. if ( nodeDescriptor instanceof ElementDescriptor ) {
  143. ElementDescriptor elementDescriptor = (ElementDescriptor) nodeDescriptor;
  144. ElementDescriptor root = beanInfo.getElementDescriptor() ;
  145. if ( root == null ) {
  146. beanInfo.setElementDescriptor( elementDescriptor );
  147. } else {
  148. root.addElementDescriptor( elementDescriptor );
  149. }
  150. } else {
  151. throw new SAXException(
  152. "the <addDefaults> element should be within an <element> tag" );
  153. }
  154. } else if ( top instanceof ElementDescriptor ) {
  155. ElementDescriptor parent = (ElementDescriptor) top;
  156. if ( nodeDescriptor instanceof ElementDescriptor ) {
  157. parent.addElementDescriptor( (ElementDescriptor) nodeDescriptor );
  158. } else {
  159. parent.addAttributeDescriptor( (AttributeDescriptor) nodeDescriptor );
  160. }
  161. } else {
  162. throw new SAXException(
  163. "Invalid use of <addDefaults>. It should be nested inside <element> element" );
  164. }
  165. }
  166. /**
  167. * Gets an <code>ElementDescriptor</code> for the top on digester's stack.
  168. *
  169. * @return the top object or the element description if the top object
  170. * is an <code>ElementDescriptor</code> or a <code>XMLBeanInfo</code> class (respectively)
  171. * Otherwise null.
  172. */
  173. protected ElementDescriptor getRootElementDescriptor() {
  174. Object top = digester.peek();
  175. if ( top instanceof XMLBeanInfo ) {
  176. XMLBeanInfo beanInfo = (XMLBeanInfo) top;
  177. return beanInfo.getElementDescriptor();
  178. } else if ( top instanceof ElementDescriptor ) {
  179. ElementDescriptor parent = (ElementDescriptor) top;
  180. // XXX: could maybe walk up the parent hierarchy?
  181. return parent;
  182. }
  183. return null;
  184. }
  185. }