View Javadoc

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