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                         if (!getXMLIntrospector().getConfiguration().getPropertySuppressionStrategy()
113                                 .suppressProperty(
114                                         beanClass,
115                                         descriptor.getPropertyType(),
116                                         descriptor.getName())) {
117 	                        Descriptor nodeDescriptor = 
118 	                        		getXMLIntrospector().createXMLDescriptor(new BeanProperty(descriptor));
119 	                        if ( nodeDescriptor != null ) {
120 	                            addDescriptor( nodeDescriptor );
121 	                        }
122                         }
123                     }
124                 }
125             } catch (Exception e) {
126                 log.info( "Caught introspection exception", e );
127             }
128         }
129     }
130 
131 
132     // Implementation methods
133     //-------------------------------------------------------------------------    
134    
135     /***
136     * Add a desciptor to the top object on the Digester stack.
137     * 
138     * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
139     * @throws SAXException if the parent for the addDefaults element is not a <element> 
140     * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a 
141     * <code>ElementDescriptor</code>
142     * @deprecated 0.5 replaced {@link #addDescriptor( Descriptor )} 
143     */
144     protected void addDescriptor( NodeDescriptor nodeDescriptor ) throws SAXException {
145         addDescriptor( (Descriptor) nodeDescriptor );
146     }
147       
148     /***
149     * Add a desciptor to the top object on the Digester stack.
150     * 
151     * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
152     * @throws SAXException if the parent for the addDefaults element is not a <element> 
153     * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a 
154     * <code>ElementDescriptor</code>
155     * @since 0.5
156     */
157     protected void addDescriptor( Descriptor nodeDescriptor ) throws SAXException {
158         Object top = digester.peek();
159         if ( top instanceof XMLBeanInfo ) {
160             log.warn( "It is advisable to put an <addDefaults/> element inside an <element> tag" );
161             
162             XMLBeanInfo beanInfo = (XMLBeanInfo) top;
163             // if there is already a root element descriptor then use it
164             // otherwise use this descriptor
165             if ( nodeDescriptor instanceof ElementDescriptor ) {
166                 ElementDescriptor elementDescriptor = (ElementDescriptor) nodeDescriptor;
167                 ElementDescriptor root = beanInfo.getElementDescriptor() ;
168                 if ( root == null ) {
169                     beanInfo.setElementDescriptor( elementDescriptor );
170                 } else {
171                     root.addElementDescriptor( elementDescriptor );
172                 }
173             } else { 
174                 throw new SAXException( 
175                     "the <addDefaults> element should be within an <element> tag" );
176             }
177         } else if ( top instanceof ElementDescriptor ) {
178             ElementDescriptor parent = (ElementDescriptor) top;
179             if ( nodeDescriptor instanceof ElementDescriptor ) {
180                 parent.addElementDescriptor( (ElementDescriptor) nodeDescriptor );
181             } else {
182                 parent.addAttributeDescriptor( (AttributeDescriptor) nodeDescriptor );
183             }
184         } else {
185             throw new SAXException( 
186                 "Invalid use of <addDefaults>. It should be nested inside <element> element" );
187         }            
188     }     
189 
190     /***
191      * Gets an <code>ElementDescriptor</code> for the top on digester's stack.
192      *
193      * @return the top object or the element description if the top object 
194      * is an <code>ElementDescriptor</code> or a <code>XMLBeanInfo</code> class (respectively)
195      * Otherwise null.
196      */
197     protected ElementDescriptor getRootElementDescriptor() {
198         Object top = digester.peek();
199         if ( top instanceof XMLBeanInfo ) {
200             XMLBeanInfo beanInfo = (XMLBeanInfo) top;
201             return beanInfo.getElementDescriptor();
202             
203         } else if ( top instanceof ElementDescriptor ) {
204             ElementDescriptor parent = (ElementDescriptor) top;
205             // XXX: could maybe walk up the parent hierarchy?
206             return parent;
207         }
208         return null;
209     }
210 }