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.Descriptor;
25  import org.apache.commons.betwixt.ElementDescriptor;
26  import org.apache.commons.betwixt.NodeDescriptor;
27  import org.apache.commons.betwixt.XMLBeanInfo;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.xml.sax.Attributes;
31  import org.xml.sax.SAXException;
32  
33  /*** <p><code>AddDefaultsRule</code> appends all the default properties
34    * to the current element.</p>
35    *
36    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
37    * @version $Revision: 1.11.2.1 $
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(Attributes attributes) throws Exception {
58          Class beanClass = getBeanClass();
59          Set procesedProperties = getProcessedPropertyNameSet();
60          if ( beanClass != null ) {
61              try {
62                  boolean attributesForPrimitives = getXMLInfoDigester().isAttributesForPrimitives();
63                  BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
64                  PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
65                  if ( descriptors != null ) {
66                      for ( int i = 0, size = descriptors.length; i < size; i++ ) {
67                          PropertyDescriptor descriptor = descriptors[i];
68                          // have we already created a property for this
69                          String name = descriptor.getName();
70                          if ( procesedProperties.contains( name ) ) {
71                              continue;
72                          }
73                          Descriptor nodeDescriptor = getXMLIntrospector().createDescriptor(
74                                      descriptor, attributesForPrimitives);
75                          if ( nodeDescriptor != null ) {
76                              addDescriptor( nodeDescriptor );
77                          }
78                      }
79                  }
80              } catch (Exception e) {
81                  log.info( "Caught introspection exception", e );
82              }
83          }
84          
85          // default any addProperty() methods
86          XMLIntrospectorHelper.defaultAddMethods( 
87                                              getXMLIntrospector(), 
88                                              getRootElementDescriptor(), 
89                                              beanClass );
90      }
91  
92  
93      // Implementation methods
94      //-------------------------------------------------------------------------    
95     
96      /***
97      * Add a desciptor to the top object on the Digester stack.
98      * 
99      * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
100     * @throws SAXException if the parent for the addDefaults element is not a <element> 
101     * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a 
102     * <code>ElementDescriptor</code>
103     * @deprecated 0.5 replaced by {@link #addDescriptor( Descriptor )} 
104     */
105     protected void addDescriptor( NodeDescriptor nodeDescriptor ) throws SAXException {
106         addDescriptor( (Descriptor) nodeDescriptor );
107     }
108       
109     /***
110     * Add a desciptor to the top object on the Digester stack.
111     * 
112     * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
113     * @throws SAXException if the parent for the addDefaults element is not a <element> 
114     * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a 
115     * <code>ElementDescriptor</code>
116     * @since 0.5
117     */
118     protected void addDescriptor( Descriptor nodeDescriptor ) throws SAXException {
119         Object top = digester.peek();
120         if ( top instanceof XMLBeanInfo ) {
121             log.warn( "It is advisable to put an <addDefaults/> element inside an <element> tag" );
122             
123             XMLBeanInfo beanInfo = (XMLBeanInfo) top;
124             // if there is already a root element descriptor then use it
125             // otherwise use this descriptor
126             if ( nodeDescriptor instanceof ElementDescriptor ) {
127                 ElementDescriptor elementDescriptor = (ElementDescriptor) nodeDescriptor;
128                 ElementDescriptor root = beanInfo.getElementDescriptor() ;
129                 if ( root == null ) {
130                     beanInfo.setElementDescriptor( elementDescriptor );
131                 } else {
132                     root.addElementDescriptor( elementDescriptor );
133                 }
134             } else { 
135                 throw new SAXException( 
136                     "the <addDefaults> element should be within an <element> tag" );
137             }
138         } else if ( top instanceof ElementDescriptor ) {
139             ElementDescriptor parent = (ElementDescriptor) top;
140             if ( nodeDescriptor instanceof ElementDescriptor ) {
141                 parent.addElementDescriptor( (ElementDescriptor) nodeDescriptor );
142             } else {
143                 parent.addAttributeDescriptor( (AttributeDescriptor) nodeDescriptor );
144             }
145         } else {
146             throw new SAXException( 
147                 "Invalid use of <addDefaults>. It should be nested inside <element> element" );
148         }            
149     }     
150 
151     /***
152      * Gets an <code>ElementDescriptor</code> for the top on digester's stack.
153      *
154      * @return the top object or the element description if the top object 
155      * is an <code>ElementDescriptor</code> or a <code>XMLBeanInfo</code> class (respectively)
156      * Otherwise null.
157      */
158     protected ElementDescriptor getRootElementDescriptor() {
159         Object top = digester.peek();
160         if ( top instanceof XMLBeanInfo ) {
161             XMLBeanInfo beanInfo = (XMLBeanInfo) top;
162             return beanInfo.getElementDescriptor();
163             
164         } else if ( top instanceof ElementDescriptor ) {
165             ElementDescriptor parent = (ElementDescriptor) top;
166             // XXX: could maybe walk up the parent hierarchy?
167             return parent;
168         }
169         return null;
170     }
171 }