001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.betwixt.digester; 018 019 import java.beans.BeanInfo; 020 import java.beans.Introspector; 021 import java.beans.PropertyDescriptor; 022 import java.util.Set; 023 024 import org.apache.commons.betwixt.AttributeDescriptor; 025 import org.apache.commons.betwixt.BeanProperty; 026 import org.apache.commons.betwixt.Descriptor; 027 import org.apache.commons.betwixt.ElementDescriptor; 028 import org.apache.commons.betwixt.NodeDescriptor; 029 import org.apache.commons.betwixt.XMLBeanInfo; 030 import org.apache.commons.logging.Log; 031 import org.apache.commons.logging.LogFactory; 032 import org.xml.sax.Attributes; 033 import org.xml.sax.SAXException; 034 035 /** <p><code>AddDefaultsRule</code> appends all the default properties 036 * to the current element.</p> 037 * 038 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> 039 */ 040 public class AddDefaultsRule extends RuleSupport { 041 042 /** Logger */ 043 private static final Log log = LogFactory.getLog( AddDefaultsRule.class ); 044 045 /** Base constructor */ 046 public AddDefaultsRule() { 047 } 048 049 // Rule interface 050 //------------------------------------------------------------------------- 051 052 /** 053 * Process the beginning of this element. 054 * 055 * @param attributes The attribute list of this element 056 * @throws Exception generally this will indicate an unrecoverable error 057 */ 058 public void begin(String name, String namespace, Attributes attributes) throws Exception { 059 boolean addProperties = true; 060 String addPropertiesAttributeValue = attributes.getValue("add-properties"); 061 if (addPropertiesAttributeValue != null) 062 { 063 addProperties = Boolean.valueOf(addPropertiesAttributeValue).booleanValue(); 064 } 065 066 boolean addAdders = true; 067 String addAddersAttributeValue = attributes.getValue("add-adders"); 068 if (addAddersAttributeValue != null) 069 { 070 addAdders = Boolean.valueOf(addAddersAttributeValue).booleanValue(); 071 } 072 073 boolean guessNames = true; 074 String guessNamesAttributeValue = attributes.getValue("guess-names"); 075 if (guessNamesAttributeValue != null) 076 { 077 guessNames = Boolean.valueOf(guessNamesAttributeValue).booleanValue(); 078 } 079 080 if (addProperties) { 081 addDefaultProperties(); 082 } 083 084 if (addAdders) { 085 addAdders(guessNames); 086 } 087 } 088 089 /** 090 * Adds default adder methods 091 */ 092 private void addAdders(boolean guessNames) { 093 Class beanClass = getBeanClass(); 094 // default any addProperty() methods 095 getXMLIntrospector().defaultAddMethods( 096 getRootElementDescriptor(), 097 beanClass, !guessNames); 098 } 099 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 }