View Javadoc

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