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
044: .getLog(AddDefaultsRule.class);
045:
046: /** Base constructor */
047: public AddDefaultsRule() {
048: }
049:
050: // Rule interface
051: //-------------------------------------------------------------------------
052:
053: /**
054: * Process the beginning of this element.
055: *
056: * @param attributes The attribute list of this element
057: * @throws Exception generally this will indicate an unrecoverable error
058: */
059: public void begin(String name, String namespace,
060: Attributes attributes) throws Exception {
061: boolean addProperties = true;
062: String addPropertiesAttributeValue = attributes
063: .getValue("add-properties");
064: if (addPropertiesAttributeValue != null) {
065: addProperties = Boolean
066: .valueOf(addPropertiesAttributeValue)
067: .booleanValue();
068: }
069:
070: boolean addAdders = true;
071: String addAddersAttributeValue = attributes
072: .getValue("add-adders");
073: if (addAddersAttributeValue != null) {
074: addAdders = Boolean.valueOf(addAddersAttributeValue)
075: .booleanValue();
076: }
077:
078: boolean guessNames = true;
079: String guessNamesAttributeValue = attributes
080: .getValue("guess-names");
081: if (guessNamesAttributeValue != null) {
082: guessNames = Boolean.valueOf(guessNamesAttributeValue)
083: .booleanValue();
084: }
085:
086: if (addProperties) {
087: addDefaultProperties();
088: }
089:
090: if (addAdders) {
091: addAdders(guessNames);
092: }
093: }
094:
095: /**
096: * Adds default adder methods
097: */
098: private void addAdders(boolean guessNames) {
099: Class beanClass = getBeanClass();
100: // default any addProperty() methods
101: getXMLIntrospector().defaultAddMethods(
102: getRootElementDescriptor(), beanClass, !guessNames);
103: }
104:
105: /**
106: * Adds default property methods
107: *
108: */
109: private void addDefaultProperties() {
110: Class beanClass = getBeanClass();
111: Set processedProperties = getProcessedPropertyNameSet();
112: if (beanClass != null) {
113: try {
114: boolean attributesForPrimitives = getXMLInfoDigester()
115: .isAttributesForPrimitives();
116: BeanInfo beanInfo;
117: if (getXMLIntrospector().getConfiguration()
118: .ignoreAllBeanInfo()) {
119: beanInfo = Introspector.getBeanInfo(beanClass,
120: Introspector.IGNORE_ALL_BEANINFO);
121: } else {
122: beanInfo = Introspector.getBeanInfo(beanClass);
123: }
124: PropertyDescriptor[] descriptors = beanInfo
125: .getPropertyDescriptors();
126: if (descriptors != null) {
127: for (int i = 0, size = descriptors.length; i < size; i++) {
128: PropertyDescriptor descriptor = descriptors[i];
129: // have we already created a property for this
130: String propertyName = descriptor.getName();
131: if (processedProperties.contains(propertyName)) {
132: continue;
133: }
134: if (!getXMLIntrospector().getConfiguration()
135: .getPropertySuppressionStrategy()
136: .suppressProperty(beanClass,
137: descriptor.getPropertyType(),
138: descriptor.getName())) {
139: Descriptor nodeDescriptor = getXMLIntrospector()
140: .createXMLDescriptor(
141: new BeanProperty(descriptor));
142: if (nodeDescriptor != null) {
143: addDescriptor(nodeDescriptor);
144: }
145: }
146: }
147: }
148: } catch (Exception e) {
149: log.info("Caught introspection exception", e);
150: }
151: }
152: }
153:
154: // Implementation methods
155: //-------------------------------------------------------------------------
156:
157: /**
158: * Add a desciptor to the top object on the Digester stack.
159: *
160: * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
161: * @throws SAXException if the parent for the addDefaults element is not a <element>
162: * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a
163: * <code>ElementDescriptor</code>
164: * @deprecated 0.5 replaced {@link #addDescriptor( Descriptor )}
165: */
166: protected void addDescriptor(NodeDescriptor nodeDescriptor)
167: throws SAXException {
168: addDescriptor((Descriptor) nodeDescriptor);
169: }
170:
171: /**
172: * Add a desciptor to the top object on the Digester stack.
173: *
174: * @param nodeDescriptor add this <code>NodeDescriptor</code>. Must not be null.
175: * @throws SAXException if the parent for the addDefaults element is not a <element>
176: * or if the top object on the stack is not a <code>XMLBeanInfo</code> or a
177: * <code>ElementDescriptor</code>
178: * @since 0.5
179: */
180: protected void addDescriptor(Descriptor nodeDescriptor)
181: throws SAXException {
182: Object top = digester.peek();
183: if (top instanceof XMLBeanInfo) {
184: log
185: .warn("It is advisable to put an <addDefaults/> element inside an <element> tag");
186:
187: XMLBeanInfo beanInfo = (XMLBeanInfo) top;
188: // if there is already a root element descriptor then use it
189: // otherwise use this descriptor
190: if (nodeDescriptor instanceof ElementDescriptor) {
191: ElementDescriptor elementDescriptor = (ElementDescriptor) nodeDescriptor;
192: ElementDescriptor root = beanInfo
193: .getElementDescriptor();
194: if (root == null) {
195: beanInfo.setElementDescriptor(elementDescriptor);
196: } else {
197: root.addElementDescriptor(elementDescriptor);
198: }
199: } else {
200: throw new SAXException(
201: "the <addDefaults> element should be within an <element> tag");
202: }
203: } else if (top instanceof ElementDescriptor) {
204: ElementDescriptor parent = (ElementDescriptor) top;
205: if (nodeDescriptor instanceof ElementDescriptor) {
206: parent
207: .addElementDescriptor((ElementDescriptor) nodeDescriptor);
208: } else {
209: parent
210: .addAttributeDescriptor((AttributeDescriptor) nodeDescriptor);
211: }
212: } else {
213: throw new SAXException(
214: "Invalid use of <addDefaults>. It should be nested inside <element> element");
215: }
216: }
217:
218: /**
219: * Gets an <code>ElementDescriptor</code> for the top on digester's stack.
220: *
221: * @return the top object or the element description if the top object
222: * is an <code>ElementDescriptor</code> or a <code>XMLBeanInfo</code> class (respectively)
223: * Otherwise null.
224: */
225: protected ElementDescriptor getRootElementDescriptor() {
226: Object top = digester.peek();
227: if (top instanceof XMLBeanInfo) {
228: XMLBeanInfo beanInfo = (XMLBeanInfo) top;
229: return beanInfo.getElementDescriptor();
230:
231: } else if (top instanceof ElementDescriptor) {
232: ElementDescriptor parent = (ElementDescriptor) top;
233: // XXX: could maybe walk up the parent hierarchy?
234: return parent;
235: }
236: return null;
237: }
238: }
|