001: package org.apache.commons.betwixt.digester;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.beans.IntrospectionException;
021: import java.beans.Introspector;
022: import java.beans.PropertyDescriptor;
023: import java.lang.reflect.Method;
024: import java.util.Collection;
025: import java.util.Date;
026: import java.util.Enumeration;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.Map;
030:
031: import org.apache.commons.betwixt.AttributeDescriptor;
032: import org.apache.commons.betwixt.ElementDescriptor;
033: import org.apache.commons.betwixt.NodeDescriptor;
034: import org.apache.commons.betwixt.XMLIntrospector;
035: import org.apache.commons.betwixt.expression.IteratorExpression;
036: import org.apache.commons.betwixt.expression.MapEntryAdder;
037: import org.apache.commons.betwixt.expression.MethodExpression;
038: import org.apache.commons.betwixt.expression.MethodUpdater;
039: import org.apache.commons.betwixt.strategy.PluralStemmer;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042:
043: /**
044: * <p><code>XMLIntrospectorHelper</code> a helper class for
045: * common code shared between the digestor and introspector.</p>
046: *
047: * TODO this class will be deprecated soon
048: * need to move the isLoop and isPrimitiveType but probably need to
049: * think about whether they need replacing with something different.
050: * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
051: * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
052: *
053: * @deprecated
054: */
055: public class XMLIntrospectorHelper {
056:
057: /** Log used for logging (Doh!) */
058: protected static Log log = LogFactory
059: .getLog(XMLIntrospectorHelper.class);
060:
061: /** Base constructor */
062: public XMLIntrospectorHelper() {
063: }
064:
065: /**
066: * <p>Gets the current logging implementation.</p>
067: *
068: * @return current log
069: */
070: public static Log getLog() {
071: return log;
072: }
073:
074: /**
075: * <p>Sets the current logging implementation.</p>
076: *
077: * @param aLog use this <code>Log</code>
078: */
079: public static void setLog(Log aLog) {
080: log = aLog;
081: }
082:
083: /**
084: * Process a property.
085: * Go through and work out whether it's a loop property, a primitive or a standard.
086: * The class property is ignored.
087: *
088: * @param propertyDescriptor create a <code>NodeDescriptor</code> for this property
089: * @param useAttributesForPrimitives write primitives as attributes (rather than elements)
090: * @param introspector use this <code>XMLIntrospector</code>
091: * @return a correctly configured <code>NodeDescriptor</code> for the property
092: * @throws IntrospectionException when bean introspection fails
093: * @deprecated 0.5 this method has been replaced by {@link XMLIntrospector#createDescriptor}
094: */
095: public static NodeDescriptor createDescriptor(
096: PropertyDescriptor propertyDescriptor,
097: boolean useAttributesForPrimitives,
098: XMLIntrospector introspector) throws IntrospectionException {
099: String name = propertyDescriptor.getName();
100: Class type = propertyDescriptor.getPropertyType();
101:
102: if (log.isTraceEnabled()) {
103: log.trace("Creating descriptor for property: name=" + name
104: + " type=" + type);
105: }
106:
107: NodeDescriptor nodeDescriptor = null;
108: Method readMethod = propertyDescriptor.getReadMethod();
109: Method writeMethod = propertyDescriptor.getWriteMethod();
110:
111: if (readMethod == null) {
112: if (log.isTraceEnabled()) {
113: log.trace("No read method for property: name=" + name
114: + " type=" + type);
115: }
116: return null;
117: }
118:
119: if (log.isTraceEnabled()) {
120: log.trace("Read method=" + readMethod.getName());
121: }
122:
123: // choose response from property type
124:
125: // XXX: ignore class property ??
126: if (Class.class.equals(type) && "class".equals(name)) {
127: log.trace("Ignoring class property");
128: return null;
129: }
130: if (isPrimitiveType(type)) {
131: if (log.isTraceEnabled()) {
132: log.trace("Primitive type: " + name);
133: }
134: if (useAttributesForPrimitives) {
135: if (log.isTraceEnabled()) {
136: log.trace("Adding property as attribute: " + name);
137: }
138: nodeDescriptor = new AttributeDescriptor();
139: } else {
140: if (log.isTraceEnabled()) {
141: log.trace("Adding property as element: " + name);
142: }
143: nodeDescriptor = new ElementDescriptor(true);
144: }
145: nodeDescriptor.setTextExpression(new MethodExpression(
146: readMethod));
147:
148: if (writeMethod != null) {
149: nodeDescriptor
150: .setUpdater(new MethodUpdater(writeMethod));
151: }
152: } else if (isLoopType(type)) {
153: if (log.isTraceEnabled()) {
154: log.trace("Loop type: " + name);
155: log.trace("Wrap in collections? "
156: + introspector.isWrapCollectionsInElement());
157: }
158: ElementDescriptor loopDescriptor = new ElementDescriptor();
159: loopDescriptor.setContextExpression(new IteratorExpression(
160: new MethodExpression(readMethod)));
161: loopDescriptor.setWrapCollectionsInElement(introspector
162: .isWrapCollectionsInElement());
163: // XXX: need to support some kind of 'add' or handle arrays, Lists or indexed properties
164: //loopDescriptor.setUpdater( new MethodUpdater( writeMethod ) );
165: if (Map.class.isAssignableFrom(type)) {
166: loopDescriptor.setQualifiedName("entry");
167: // add elements for reading
168: loopDescriptor
169: .addElementDescriptor(new ElementDescriptor(
170: "key"));
171: loopDescriptor
172: .addElementDescriptor(new ElementDescriptor(
173: "value"));
174: }
175:
176: ElementDescriptor elementDescriptor = new ElementDescriptor();
177: elementDescriptor.setWrapCollectionsInElement(introspector
178: .isWrapCollectionsInElement());
179: elementDescriptor
180: .setElementDescriptors(new ElementDescriptor[] { loopDescriptor });
181:
182: nodeDescriptor = elementDescriptor;
183: } else {
184: if (log.isTraceEnabled()) {
185: log.trace("Standard property: " + name);
186: }
187: ElementDescriptor elementDescriptor = new ElementDescriptor();
188: elementDescriptor
189: .setContextExpression(new MethodExpression(
190: readMethod));
191: if (writeMethod != null) {
192: elementDescriptor.setUpdater(new MethodUpdater(
193: writeMethod));
194: }
195:
196: nodeDescriptor = elementDescriptor;
197: }
198:
199: if (nodeDescriptor instanceof AttributeDescriptor) {
200: // we want to use the attributemapper only when it is an attribute..
201: nodeDescriptor.setLocalName(introspector
202: .getAttributeNameMapper()
203: .mapTypeToElementName(name));
204: } else {
205: nodeDescriptor.setLocalName(introspector
206: .getElementNameMapper().mapTypeToElementName(name));
207: }
208:
209: nodeDescriptor.setPropertyName(propertyDescriptor.getName());
210: nodeDescriptor.setPropertyType(type);
211:
212: // XXX: associate more bean information with the descriptor?
213: //nodeDescriptor.setDisplayName( propertyDescriptor.getDisplayName() );
214: //nodeDescriptor.setShortDescription( propertyDescriptor.getShortDescription() );
215:
216: if (log.isTraceEnabled()) {
217: log.trace("Created descriptor:");
218: log.trace(nodeDescriptor);
219: }
220: return nodeDescriptor;
221: }
222:
223: /**
224: * Configure an <code>ElementDescriptor</code> from a <code>PropertyDescriptor</code>.
225: * This uses default element updater (the write method of the property).
226: *
227: * @param elementDescriptor configure this <code>ElementDescriptor</code>
228: * @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
229: * @deprecated 0.6 unused
230: */
231: public static void configureProperty(
232: ElementDescriptor elementDescriptor,
233: PropertyDescriptor propertyDescriptor) {
234:
235: configureProperty(elementDescriptor, propertyDescriptor, null,
236: null);
237: }
238:
239: /**
240: * Configure an <code>ElementDescriptor</code> from a <code>PropertyDescriptor</code>.
241: * A custom update method may be set.
242: *
243: * @param elementDescriptor configure this <code>ElementDescriptor</code>
244: * @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
245: * @param updateMethodName the name of the custom updater method to user.
246: * If null, then then
247: * @param beanClass the <code>Class</code> from which the update method should be found.
248: * This may be null only when <code>updateMethodName</code> is also null.
249: * @since 0.5
250: * @deprecated 0.6 moved into ElementRule
251: */
252: public static void configureProperty(
253: ElementDescriptor elementDescriptor,
254: PropertyDescriptor propertyDescriptor,
255: String updateMethodName, Class beanClass) {
256:
257: Class type = propertyDescriptor.getPropertyType();
258: Method readMethod = propertyDescriptor.getReadMethod();
259: Method writeMethod = propertyDescriptor.getWriteMethod();
260:
261: elementDescriptor.setLocalName(propertyDescriptor.getName());
262: elementDescriptor.setPropertyType(type);
263:
264: // XXX: associate more bean information with the descriptor?
265: //nodeDescriptor.setDisplayName( propertyDescriptor.getDisplayName() );
266: //nodeDescriptor.setShortDescription( propertyDescriptor.getShortDescription() );
267:
268: if (readMethod == null) {
269: log.trace("No read method");
270: return;
271: }
272:
273: if (log.isTraceEnabled()) {
274: log.trace("Read method=" + readMethod.getName());
275: }
276:
277: // choose response from property type
278:
279: // XXX: ignore class property ??
280: if (Class.class.equals(type)
281: && "class".equals(propertyDescriptor.getName())) {
282: log.trace("Ignoring class property");
283: return;
284: }
285: if (isPrimitiveType(type)) {
286: elementDescriptor.setTextExpression(new MethodExpression(
287: readMethod));
288:
289: } else if (isLoopType(type)) {
290: log.trace("Loop type ??");
291:
292: // don't wrap this in an extra element as its specified in the
293: // XML descriptor so no need.
294: elementDescriptor
295: .setContextExpression(new IteratorExpression(
296: new MethodExpression(readMethod)));
297:
298: writeMethod = null;
299: } else {
300: log.trace("Standard property");
301: elementDescriptor
302: .setContextExpression(new MethodExpression(
303: readMethod));
304: }
305:
306: // see if we have a custom method update name
307: if (updateMethodName == null) {
308: // set standard write method
309: if (writeMethod != null) {
310: elementDescriptor.setUpdater(new MethodUpdater(
311: writeMethod));
312: }
313:
314: } else {
315: // see if we can find and set the custom method
316: if (log.isTraceEnabled()) {
317: log.trace("Finding custom method: ");
318: log.trace(" on:" + beanClass);
319: log.trace(" name:" + updateMethodName);
320: }
321:
322: Method updateMethod = null;
323: Method[] methods = beanClass.getMethods();
324: for (int i = 0, size = methods.length; i < size; i++) {
325: Method method = methods[i];
326: if (updateMethodName.equals(method.getName())) {
327: // we have a matching name
328: // check paramters are correct
329: if (methods[i].getParameterTypes().length == 1) {
330: // we'll use first match
331: updateMethod = methods[i];
332: if (log.isTraceEnabled()) {
333: log.trace("Matched method:" + updateMethod);
334: }
335: // done since we're using the first match
336: break;
337: }
338: }
339: }
340:
341: if (updateMethod == null) {
342: if (log.isInfoEnabled()) {
343:
344: log.info("No method with name '" + updateMethodName
345: + "' found for update");
346: }
347: } else {
348:
349: elementDescriptor.setUpdater(new MethodUpdater(
350: updateMethod));
351: elementDescriptor.setSingularPropertyType(updateMethod
352: .getParameterTypes()[0]);
353: if (log.isTraceEnabled()) {
354: log.trace("Set custom updater on "
355: + elementDescriptor);
356: }
357: }
358: }
359: }
360:
361: /**
362: * Configure an <code>AttributeDescriptor</code> from a <code>PropertyDescriptor</code>
363: *
364: * @param attributeDescriptor configure this <code>AttributeDescriptor</code>
365: * @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
366: * @deprecated 0.6 moved into AttributeRule
367: */
368: public static void configureProperty(
369: AttributeDescriptor attributeDescriptor,
370: PropertyDescriptor propertyDescriptor) {
371: Class type = propertyDescriptor.getPropertyType();
372: Method readMethod = propertyDescriptor.getReadMethod();
373: Method writeMethod = propertyDescriptor.getWriteMethod();
374:
375: if (readMethod == null) {
376: log.trace("No read method");
377: return;
378: }
379:
380: if (log.isTraceEnabled()) {
381: log.trace("Read method=" + readMethod);
382: }
383:
384: // choose response from property type
385:
386: // XXX: ignore class property ??
387: if (Class.class.equals(type)
388: && "class".equals(propertyDescriptor.getName())) {
389: log.trace("Ignoring class property");
390: return;
391: }
392: if (isLoopType(type)) {
393: log.warn("Using loop type for an attribute. Type = "
394: + type.getName() + " attribute: "
395: + attributeDescriptor.getQualifiedName());
396: }
397:
398: log.trace("Standard property");
399: attributeDescriptor.setTextExpression(new MethodExpression(
400: readMethod));
401:
402: if (writeMethod != null) {
403: attributeDescriptor.setUpdater(new MethodUpdater(
404: writeMethod));
405: }
406:
407: attributeDescriptor.setLocalName(propertyDescriptor.getName());
408: attributeDescriptor.setPropertyType(type);
409:
410: // XXX: associate more bean information with the descriptor?
411: //nodeDescriptor.setDisplayName( propertyDescriptor.getDisplayName() );
412: //nodeDescriptor.setShortDescription( propertyDescriptor.getShortDescription() );
413: }
414:
415: /**
416: * Add any addPropety(PropertyType) methods as Updaters
417: * which are often used for 1-N relationships in beans.
418: * <br>
419: * The tricky part here is finding which ElementDescriptor corresponds
420: * to the method. e.g. a property 'items' might have an Element descriptor
421: * which the method addItem() should match to.
422: * <br>
423: * So the algorithm we'll use
424: * by default is to take the decapitalized name of the property being added
425: * and find the first ElementDescriptor that matches the property starting with
426: * the string. This should work for most use cases.
427: * e.g. addChild() would match the children property.
428: *
429: * @param introspector use this <code>XMLIntrospector</code> for introspection
430: * @param rootDescriptor add defaults to this descriptor
431: * @param beanClass the <code>Class</code> to which descriptor corresponds
432: * @deprecated 0.6 use the method in XMLIntrospector instead
433: */
434: public static void defaultAddMethods(XMLIntrospector introspector,
435: ElementDescriptor rootDescriptor, Class beanClass) {
436: // lets iterate over all methods looking for one of the form
437: // add*(PropertyType)
438: if (beanClass != null) {
439: Method[] methods = beanClass.getMethods();
440: for (int i = 0, size = methods.length; i < size; i++) {
441: Method method = methods[i];
442: String name = method.getName();
443: if (name.startsWith("add")) {
444: // XXX: should we filter out non-void returning methods?
445: // some beans will return something as a helper
446: Class[] types = method.getParameterTypes();
447: if (types != null) {
448: if (log.isTraceEnabled()) {
449: log.trace("Searching for match for "
450: + method);
451: }
452:
453: if ((types.length == 1) || types.length == 2) {
454: String propertyName = Introspector
455: .decapitalize(name.substring(3));
456: if (propertyName.length() == 0)
457: continue;
458: if (log.isTraceEnabled()) {
459: log.trace(name + "->" + propertyName);
460: }
461:
462: // now lets try find the ElementDescriptor which displays
463: // a property which starts with propertyName
464: // and if so, we'll set a new Updater on it if there
465: // is not one already
466: ElementDescriptor descriptor = findGetCollectionDescriptor(
467: introspector, rootDescriptor,
468: propertyName);
469:
470: if (log.isDebugEnabled()) {
471: log.debug("!! " + propertyName + " -> "
472: + descriptor);
473: log
474: .debug("!! "
475: + name
476: + " -> "
477: + (descriptor != null ? descriptor
478: .getPropertyName()
479: : ""));
480: }
481: if (descriptor != null) {
482: boolean isMapDescriptor = Map.class
483: .isAssignableFrom(descriptor
484: .getPropertyType());
485: if (!isMapDescriptor
486: && types.length == 1) {
487: // this may match a standard collection or iteration
488: log
489: .trace("Matching collection or iteration");
490:
491: descriptor
492: .setUpdater(new MethodUpdater(
493: method));
494: descriptor
495: .setSingularPropertyType(types[0]);
496:
497: if (log.isDebugEnabled()) {
498: log.debug("!! " + method);
499: log.debug("!! " + types[0]);
500: }
501:
502: // is there a child element with no localName
503: ElementDescriptor[] children = descriptor
504: .getElementDescriptors();
505: if (children != null
506: && children.length > 0) {
507: ElementDescriptor child = children[0];
508: String localName = child
509: .getLocalName();
510: if (localName == null
511: || localName.length() == 0) {
512: child
513: .setLocalName(introspector
514: .getElementNameMapper()
515: .mapTypeToElementName(
516: propertyName));
517: }
518: }
519:
520: } else if (isMapDescriptor
521: && types.length == 2) {
522: // this may match a map
523: log.trace("Matching map");
524: ElementDescriptor[] children = descriptor
525: .getElementDescriptors();
526: // see if the descriptor's been set up properly
527: if (children.length == 0) {
528:
529: log
530: .info("'entry' descriptor is missing for map. "
531: + "Updaters cannot be set");
532:
533: } else {
534: // loop through grandchildren
535: // adding updaters for key and value
536: ElementDescriptor[] grandchildren = children[0]
537: .getElementDescriptors();
538: MapEntryAdder adder = new MapEntryAdder(
539: method);
540: for (int n = 0, noOfGrandChildren = grandchildren.length; n < noOfGrandChildren; n++) {
541: if ("key"
542: .equals(grandchildren[n]
543: .getLocalName())) {
544:
545: grandchildren[n]
546: .setUpdater(adder
547: .getKeyUpdater());
548: grandchildren[n]
549: .setSingularPropertyType(types[0]);
550: if (log
551: .isTraceEnabled()) {
552: log
553: .trace("Key descriptor: "
554: + grandchildren[n]);
555: }
556:
557: } else if ("value"
558: .equals(grandchildren[n]
559: .getLocalName())) {
560:
561: grandchildren[n]
562: .setUpdater(adder
563: .getValueUpdater());
564: grandchildren[n]
565: .setSingularPropertyType(types[1]);
566: if (log
567: .isTraceEnabled()) {
568: log
569: .trace("Value descriptor: "
570: + grandchildren[n]);
571: }
572: }
573: }
574: }
575: }
576: } else {
577: if (log.isDebugEnabled()) {
578: log
579: .debug("Could not find an ElementDescriptor with property name: "
580: + propertyName
581: + " to attach the add method: "
582: + method);
583: }
584: }
585: }
586: }
587: }
588: }
589: }
590: }
591:
592: /**
593: * Is this a loop type class?
594: *
595: * @param type is this <code>Class</code> a loop type?
596: * @return true if the type is a loop type, or if type is null
597: * @deprecated 0.7 replaced by {@link org.apache.commons.betwixt.IntrospectionConfiguration#isLoopType(Class)}
598: */
599: public static boolean isLoopType(Class type) {
600: // check for NPEs
601: if (type == null) {
602: log.trace("isLoopType: type is null");
603: return false;
604: }
605: return type.isArray() || Map.class.isAssignableFrom(type)
606: || Collection.class.isAssignableFrom(type)
607: || Enumeration.class.isAssignableFrom(type)
608: || Iterator.class.isAssignableFrom(type);
609: }
610:
611: /**
612: * Is this a primitive type?
613: *
614: * TODO: this method will probably be removed when primitive types
615: * are subsumed into the simple type concept.
616: * This needs moving into XMLIntrospector so that the list of simple
617: * type can be varied.
618: * @param type is this <code>Class<code> a primitive type?
619: * @return true for primitive types
620: * @deprecated 0.6 replaced by {@link org.apache.commons.betwixt.strategy.TypeBindingStrategy}
621: */
622: public static boolean isPrimitiveType(Class type) {
623: if (type == null) {
624: return false;
625:
626: } else if (type.isPrimitive()) {
627: return true;
628:
629: } else if (type.equals(Object.class)) {
630: return false;
631: }
632: return type.getName().startsWith("java.lang.")
633: || Number.class.isAssignableFrom(type)
634: || String.class.isAssignableFrom(type)
635: || Date.class.isAssignableFrom(type)
636: || java.sql.Date.class.isAssignableFrom(type)
637: || java.sql.Time.class.isAssignableFrom(type)
638: || java.sql.Timestamp.class.isAssignableFrom(type)
639: || java.math.BigDecimal.class.isAssignableFrom(type)
640: || java.math.BigInteger.class.isAssignableFrom(type);
641: }
642:
643: // Implementation methods
644: //-------------------------------------------------------------------------
645:
646: /**
647: * Attempts to find the element descriptor for the getter property that
648: * typically matches a collection or array. The property name is used
649: * to match. e.g. if an addChild() method is detected the
650: * descriptor for the 'children' getter property should be returned.
651: *
652: * @param introspector use this <code>XMLIntrospector</code>
653: * @param rootDescriptor the <code>ElementDescriptor</code> whose child element will be
654: * searched for a match
655: * @param propertyName the name of the 'adder' method to match
656: * @return <code>ElementDescriptor</code> for the matching getter
657: * @deprecated 0.6 moved into XMLIntrospector
658: */
659: protected static ElementDescriptor findGetCollectionDescriptor(
660: XMLIntrospector introspector,
661: ElementDescriptor rootDescriptor, String propertyName) {
662: // create the Map of propertyName -> descriptor that the PluralStemmer will choose
663: Map map = new HashMap();
664: //String propertyName = rootDescriptor.getPropertyName();
665: if (log.isTraceEnabled()) {
666: log.trace("findPluralDescriptor( " + propertyName
667: + " ):root property name="
668: + rootDescriptor.getPropertyName());
669: }
670:
671: if (rootDescriptor.getPropertyName() != null) {
672: map.put(propertyName, rootDescriptor);
673: }
674: makeElementDescriptorMap(rootDescriptor, map);
675:
676: PluralStemmer stemmer = introspector.getPluralStemmer();
677: ElementDescriptor elementDescriptor = stemmer
678: .findPluralDescriptor(propertyName, map);
679:
680: if (log.isTraceEnabled()) {
681: log.trace("findPluralDescriptor( " + propertyName
682: + " ):ElementDescriptor=" + elementDescriptor);
683: }
684:
685: return elementDescriptor;
686: }
687:
688: /**
689: * Creates a map where the keys are the property names and the values are the ElementDescriptors
690: *
691: * @param rootDescriptor the values of the maps are the children of this
692: * <code>ElementDescriptor</code> index by their property names
693: * @param map the map to which the elements will be added
694: * @deprecated 0.6 moved into XMLIntrospector
695: */
696: protected static void makeElementDescriptorMap(
697: ElementDescriptor rootDescriptor, Map map) {
698: ElementDescriptor[] children = rootDescriptor
699: .getElementDescriptors();
700: if (children != null) {
701: for (int i = 0, size = children.length; i < size; i++) {
702: ElementDescriptor child = children[i];
703: String propertyName = child.getPropertyName();
704: if (propertyName != null) {
705: map.put(propertyName, child);
706: }
707: makeElementDescriptorMap(child, map);
708: }
709: }
710: }
711:
712: /**
713: * Traverse the tree of element descriptors and find the oldValue and swap it with the newValue.
714: * This would be much easier to do if ElementDescriptor supported a parent relationship.
715: *
716: * @param rootDescriptor traverse child graph for this <code>ElementDescriptor</code>
717: * @param oldValue replace this <code>ElementDescriptor</code>
718: * @param newValue replace with this <code>ElementDescriptor</code>
719: * @deprecated 0.6 now unused
720: */
721: protected static void swapDescriptor(
722: ElementDescriptor rootDescriptor,
723: ElementDescriptor oldValue, ElementDescriptor newValue) {
724: ElementDescriptor[] children = rootDescriptor
725: .getElementDescriptors();
726: if (children != null) {
727: for (int i = 0, size = children.length; i < size; i++) {
728: ElementDescriptor child = children[i];
729: if (child == oldValue) {
730: children[i] = newValue;
731: break;
732: }
733: swapDescriptor(child, oldValue, newValue);
734: }
735: }
736: }
737: }
|