KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > description > TypeDesc


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.jboss.axis.description;
57
58 import org.jboss.axis.utils.BeanPropertyDescriptor;
59 import org.jboss.axis.utils.BeanUtils;
60 import org.jboss.axis.utils.ClassUtils;
61 import org.jboss.axis.utils.Messages;
62 import org.jboss.logging.Logger;
63
64 import javax.xml.namespace.QName JavaDoc;
65 import java.lang.reflect.Method JavaDoc;
66 import java.util.HashMap JavaDoc;
67 import java.util.Hashtable JavaDoc;
68 import java.util.Iterator JavaDoc;
69 import java.util.Map JavaDoc;
70
71 /**
72  * A TypeDesc represents a Java<->XML data binding. It is essentially
73  * a collection of FieldDescs describing how to map each field in a Java
74  * class to XML.
75  *
76  * @author Glen Daniels (gdaniels@apache.org)
77  */

78 public class TypeDesc
79 {
80    // provide logging
81
private final Logger log = Logger.getLogger(TypeDesc.class);
82
83    public static final Class JavaDoc[] noClasses = new Class JavaDoc[]{};
84    public static final Object JavaDoc[] noObjects = new Object JavaDoc[]{};
85
86    /**
87     * A map of class -> TypeDesc
88     */

89    private static Map JavaDoc classMap = new Hashtable JavaDoc();
90
91    /**
92     * Have we already introspected for the special "any" property desc?
93     */

94    private boolean lookedForAny;
95
96    /**
97     * The Java class for this type
98     */

99    private Class JavaDoc javaClass;
100
101    /**
102     * The XML type QName for this type
103     */

104    private QName JavaDoc xmlType;
105
106    /**
107     * The various fields in here
108     */

109    private FieldDesc[] fields;
110
111    /**
112     * A cache of FieldDescs by name
113     */

114    private HashMap JavaDoc fieldNameMap = new HashMap JavaDoc();
115
116    /**
117     * A cache of FieldDescs by Element QName
118     */

119    private HashMap JavaDoc fieldElementMap;
120
121    /**
122     * Are there any fields which are serialized as attributes?
123     */

124    private boolean hasAttributes;
125
126    /**
127     * Introspected property descriptors
128     */

129    private BeanPropertyDescriptor[] propertyDescriptors;
130
131    /**
132     * Map with key = property descriptor name, value = descriptor
133     */

134    private Map JavaDoc propertyMap;
135
136    /**
137     * Indication if this type has support for xsd:any.
138     */

139    private BeanPropertyDescriptor anyDesc;
140
141    public TypeDesc(Class JavaDoc javaClass)
142    {
143       this.javaClass = javaClass;
144    }
145
146    /**
147     * Static function to explicitly register a type description for
148     * a given class.
149     *
150     * @param cls the Class we're registering metadata about
151     * @param td the TypeDesc containing the metadata
152     */

153    public static void registerTypeDescForClass(Class JavaDoc cls, TypeDesc td)
154    {
155       classMap.put(cls, td);
156    }
157
158    /**
159     * Static function for centralizing access to type metadata for a
160     * given class.
161     * <p/>
162     * This checks for a static getTypeDesc() method on the
163     * class or _Helper class.
164     * Eventually we may extend this to provide for external
165     * metadata config (via files sitting in the classpath, etc).
166     * <p/>
167     * (Could introduce a cache here for speed as an optimization)
168     */

169    public static TypeDesc getTypeDescForClass(Class JavaDoc cls)
170    {
171       // First see if we have one explicitly registered
172
TypeDesc result = (TypeDesc)classMap.get(cls);
173       if (result != null)
174       {
175          return result;
176       }
177
178       try
179       {
180          Method JavaDoc getTypeDesc = null;
181          try
182          {
183             getTypeDesc =
184                     cls.getMethod("getTypeDesc", noClasses);
185          }
186          catch (NoSuchMethodException JavaDoc e)
187          {
188          }
189          if (getTypeDesc == null)
190          {
191             // Look for a Helper Class
192
Class JavaDoc helper = ClassUtils.forName(cls.getName() + "_Helper");
193             try
194             {
195                getTypeDesc =
196                        helper.getMethod("getTypeDesc", noClasses);
197             }
198             catch (NoSuchMethodException JavaDoc e)
199             {
200             }
201          }
202          if (getTypeDesc != null)
203          {
204             return (TypeDesc)getTypeDesc.invoke(null,
205                     noObjects);
206          }
207       }
208       catch (Exception JavaDoc e)
209       {
210       }
211       return null;
212    }
213
214    public BeanPropertyDescriptor getAnyDesc()
215    {
216       return anyDesc;
217    }
218
219    /**
220     * Obtain the current array of FieldDescs
221     */

222    public FieldDesc[] getFields()
223    {
224       return fields;
225    }
226
227    public FieldDesc[] getFields(boolean searchParents)
228    {
229       if (searchParents)
230       {
231          // check superclasses if they exist
232
Class JavaDoc cls = javaClass.getSuperclass();
233          if (cls != null && !cls.getName().startsWith("java."))
234          {
235             TypeDesc superDesc = getTypeDescForClass(cls);
236             if (superDesc != null)
237             {
238                FieldDesc[] parentFields = superDesc.getFields(true);
239 // START FIX http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17188
240
if (parentFields != null)
241                {
242                   if (fields != null)
243                   {
244                      FieldDesc[] ret = new FieldDesc[parentFields.length + fields.length];
245                      System.arraycopy(parentFields, 0, ret, 0, parentFields.length);
246                      System.arraycopy(fields, 0, ret, parentFields.length, fields.length);
247                      fields = ret;
248                   }
249                   else
250                   {
251                      FieldDesc[] ret = new FieldDesc[parentFields.length];
252                      System.arraycopy(parentFields, 0, ret, 0, parentFields.length);
253                      fields = ret;
254                   }
255                }
256 // END FIX http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17188
257
}
258          }
259       }
260
261       return fields;
262    }
263
264    /**
265     * Replace the array of FieldDescs, making sure we keep our convenience
266     * caches in sync.
267     */

268    public void setFields(FieldDesc[] newFields)
269    {
270       fieldNameMap = new HashMap JavaDoc();
271       fields = newFields;
272       hasAttributes = false;
273       fieldElementMap = null;
274
275       for (int i = 0; i < newFields.length; i++)
276       {
277          FieldDesc field = newFields[i];
278          if (field.isElement())
279          {
280             fieldNameMap.put(field.getFieldName(), field);
281          }
282          else
283          {
284             hasAttributes = true;
285          }
286       }
287    }
288
289    /**
290     * Add a new FieldDesc, keeping the convenience fields in sync.
291     */

292    public void addFieldDesc(FieldDesc field)
293    {
294       if (field == null)
295       {
296          throw new IllegalArgumentException JavaDoc(Messages.getMessage("nullFieldDesc"));
297       }
298
299       int numFields = 0;
300       if (fields != null)
301       {
302          numFields = fields.length;
303       }
304       FieldDesc[] newFields = new FieldDesc[numFields + 1];
305       if (fields != null)
306       {
307          System.arraycopy(fields, 0, newFields, 0, numFields);
308       }
309       newFields[numFields] = field;
310       fields = newFields;
311
312       // Keep track of the field by name for fast lookup
313
fieldNameMap.put(field.getFieldName(), field);
314
315       if (!hasAttributes && !field.isElement())
316          hasAttributes = true;
317    }
318
319    /**
320     * Get the QName associated with this field, but only if it's
321     * marked as an element.
322     */

323    public QName JavaDoc getElementNameForField(String JavaDoc fieldName)
324    {
325       FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName);
326       if (desc == null)
327       {
328          // check superclasses if they exist
329
Class JavaDoc cls = javaClass.getSuperclass();
330          if (cls != null && !cls.getName().startsWith("java."))
331          {
332             TypeDesc superDesc = getTypeDescForClass(cls);
333             if (superDesc != null)
334             {
335                return superDesc.getElementNameForField(fieldName);
336             }
337          }
338       }
339       else if (!desc.isElement())
340       {
341          return null;
342       }
343       return desc.getXmlName();
344    }
345
346    /**
347     * Get the QName associated with this field, but only if it's
348     * marked as an attribute.
349     */

350    public QName JavaDoc getAttributeNameForField(String JavaDoc fieldName)
351    {
352       FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName);
353       if (desc == null)
354       {
355          // check superclasses if they exist
356
Class JavaDoc cls = javaClass.getSuperclass();
357          if (cls != null && !cls.getName().startsWith("java."))
358          {
359             TypeDesc superDesc = getTypeDescForClass(cls);
360             if (superDesc != null)
361             {
362                return superDesc.getAttributeNameForField(fieldName);
363             }
364          }
365       }
366       else if (desc.isElement())
367       {
368          return null;
369       }
370       QName JavaDoc ret = desc.getXmlName();
371       if (ret == null)
372       {
373          ret = new QName JavaDoc("", fieldName);
374       }
375       return ret;
376    }
377
378    /**
379     * Get the field name associated with this QName, but only if it's
380     * marked as an element.
381     */

382    public String JavaDoc getFieldNameForElement(QName JavaDoc qname)
383    {
384       // have we already computed the answer to this question?
385
if (fieldElementMap != null)
386       {
387          String JavaDoc cached = (String JavaDoc)fieldElementMap.get(qname);
388          if (cached != null) return cached;
389       }
390
391       String JavaDoc result = null;
392
393       String JavaDoc localPart = qname.getLocalPart();
394
395       // check fields in this class
396
for (int i = 0; fields != null && i < fields.length; i++)
397       {
398          FieldDesc field = fields[i];
399          if (field.isElement())
400          {
401             QName JavaDoc xmlName = field.getXmlName();
402             if (localPart.equals(xmlName.getLocalPart()))
403             {
404                if (qname.getNamespaceURI().equals(xmlName.getNamespaceURI()))
405                {
406                   result = field.getFieldName();
407                   break;
408                }
409             }
410          }
411       }
412
413       // check superclasses if they exist
414
if (result == null)
415       {
416          Class JavaDoc cls = javaClass.getSuperclass();
417          if (cls != null && !cls.getName().startsWith("java."))
418          {
419             TypeDesc superDesc = getTypeDescForClass(cls);
420             if (superDesc != null)
421             {
422                result = superDesc.getFieldNameForElement(qname);
423             }
424          }
425       }
426
427       // cache the answer away for quicker retrieval next time.
428
if (result != null)
429       {
430          if (fieldElementMap == null) fieldElementMap = new HashMap JavaDoc();
431          fieldElementMap.put(qname, result);
432       }
433
434       return result;
435    }
436
437    /**
438     * Get the field name associated with this QName, but only if it's
439     * marked as an attribute.
440     */

441    public String JavaDoc getFieldNameForAttribute(QName JavaDoc qname)
442    {
443       String JavaDoc possibleMatch = null;
444
445       for (int i = 0; fields != null && i < fields.length; i++)
446       {
447          FieldDesc field = fields[i];
448          if (!field.isElement())
449          {
450             // It's an attribute, so if we have a solid match, return
451
// its name.
452
if (qname.equals(field.getXmlName()))
453             {
454                return field.getFieldName();
455             }
456             // Not a solid match, but it's still possible we might match
457
// the default (i.e. QName("", fieldName))
458
if (qname.getNamespaceURI().equals("") &&
459                     qname.getLocalPart().equals(field.getFieldName()))
460             {
461                possibleMatch = field.getFieldName();
462             }
463          }
464       }
465
466       if (possibleMatch == null)
467       {
468          // check superclasses if they exist
469
Class JavaDoc cls = javaClass.getSuperclass();
470          if (cls != null && !cls.getName().startsWith("java."))
471          {
472             TypeDesc superDesc = getTypeDescForClass(cls);
473             if (superDesc != null)
474             {
475                possibleMatch = superDesc.getFieldNameForAttribute(qname);
476             }
477          }
478       }
479
480       return possibleMatch;
481    }
482
483    /**
484     * Get a FieldDesc by field name.
485     */

486    public FieldDesc getFieldByName(String JavaDoc name)
487    {
488       FieldDesc ret = (FieldDesc)fieldNameMap.get(name);
489       if (ret == null)
490       {
491          Class JavaDoc cls = javaClass.getSuperclass();
492          if (cls != null && !cls.getName().startsWith("java."))
493          {
494             TypeDesc superDesc = getTypeDescForClass(cls);
495             if (superDesc != null)
496             {
497                ret = superDesc.getFieldByName(name);
498             }
499          }
500       }
501       return ret;
502    }
503
504    /**
505     * Do we have any FieldDescs marked as attributes?
506     */

507    public boolean hasAttributes()
508    {
509       return hasAttributes;
510    }
511
512    public QName JavaDoc getXmlType()
513    {
514       return xmlType;
515    }
516
517    public void setXmlType(QName JavaDoc xmlType)
518    {
519       this.xmlType = xmlType;
520    }
521
522    /**
523     * Get/Cache the property descriptors
524     *
525     * @return PropertyDescriptor
526     */

527    public BeanPropertyDescriptor[] getPropertyDescriptors()
528    {
529       // Return the propertyDescriptors if already set.
530
// If not set, use BeanUtils.getPd to get the property descriptions.
531
//
532
// Since javaClass is a generated class, there
533
// may be a faster way to set the property descriptions than
534
// using BeanUtils.getPd. But for now calling getPd is sufficient.
535
if (propertyDescriptors == null)
536       {
537          propertyDescriptors = BeanUtils.getPd(javaClass, this);
538          if (!lookedForAny)
539          {
540             anyDesc = BeanUtils.getAnyContentPD(javaClass);
541             lookedForAny = true;
542          }
543       }
544       return propertyDescriptors;
545    }
546
547    /**
548     * Set the property descriptors for this type, for example in a different order
549     */

550    public void setPropertyDescriptors(BeanPropertyDescriptor[] propertyDescriptors)
551    {
552       this.propertyDescriptors = propertyDescriptors;
553       this.propertyMap = null;
554    }
555
556    public BeanPropertyDescriptor getAnyContentDescriptor()
557    {
558       if (!lookedForAny)
559       {
560          anyDesc = BeanUtils.getAnyContentPD(javaClass);
561          lookedForAny = true;
562       }
563       return anyDesc;
564    }
565
566    /**
567     * Get/Cache the property descriptor map
568     *
569     * @return Map with key=propertyName, value=descriptor
570     */

571    public Map JavaDoc getPropertyDescriptorMap()
572    {
573       // Return map if already set.
574
if (propertyMap != null)
575       {
576          return propertyMap;
577       }
578
579       // Make sure properties exist
580
if (propertyDescriptors == null)
581       {
582          getPropertyDescriptors();
583       }
584
585       // Build the map
586
propertyMap = new HashMap JavaDoc();
587       for (int i = 0; i < propertyDescriptors.length; i++)
588       {
589          BeanPropertyDescriptor bpd = propertyDescriptors[i];
590          String JavaDoc bpName = bpd.getName();
591          
592          propertyMap.put(bpName, bpd);
593       }
594
595       return propertyMap;
596    }
597 }
598
Popular Tags