KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2002-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.axis.description;
18
19 import org.apache.axis.utils.BeanPropertyDescriptor;
20 import org.apache.axis.utils.BeanUtils;
21 import org.apache.axis.utils.Messages;
22 import org.apache.axis.utils.cache.MethodCache;
23
24 import javax.xml.namespace.QName JavaDoc;
25 import java.io.Serializable JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Hashtable JavaDoc;
29 import java.util.Map JavaDoc;
30
31 /**
32  * A TypeDesc represents a Java<->XML data binding. It is essentially
33  * a collection of FieldDescs describing how to map each field in a Java
34  * class to XML.
35  *
36  * @author Glen Daniels (gdaniels@apache.org)
37  */

38 public class TypeDesc implements Serializable JavaDoc {
39     public static final Class JavaDoc [] noClasses = new Class JavaDoc [] {};
40     public static final Object JavaDoc[] noObjects = new Object JavaDoc[] {};
41     
42     /** A map of class -> TypeDesc */
43     private static Map JavaDoc classMap = new Hashtable JavaDoc();
44
45     /** Have we already introspected for the special "any" property desc? */
46     private boolean lookedForAny = false;
47
48     /** Can this instance search for metadata in parents of the type it describes? */
49     private boolean canSearchParents = true;
50     private boolean hasSearchedParents = false;
51     
52     /** My superclass TypeDesc */
53     private TypeDesc parentDesc = null;
54
55     /**
56      * Creates a new <code>TypeDesc</code> instance. The type desc can search
57      * the metadata of its type'sparent classes.
58      *
59      * @param javaClass a <code>Class</code> value
60      */

61     public TypeDesc(Class JavaDoc javaClass) {
62         this(javaClass, true);
63     }
64     
65     /**
66      * Creates a new <code>TypeDesc</code> instance.
67      *
68      * @param javaClass a <code>Class</code> value
69      * @param canSearchParents whether the type desc can search the metadata of
70      * its type's parent classes.
71      */

72     public TypeDesc(Class JavaDoc javaClass, boolean canSearchParents) {
73         this.javaClass = javaClass;
74         this.canSearchParents = canSearchParents;
75         Class JavaDoc cls = javaClass.getSuperclass();
76         if (cls != null && !cls.getName().startsWith("java.")) {
77             parentDesc = getTypeDescForClass(cls);
78         }
79     }
80
81     /**
82      * Static function to explicitly register a type description for
83      * a given class.
84      *
85      * @param cls the Class we're registering metadata about
86      * @param td the TypeDesc containing the metadata
87      */

88     public static void registerTypeDescForClass(Class JavaDoc cls, TypeDesc td)
89     {
90         classMap.put(cls, td);
91     }
92
93     /**
94      * Static function for centralizing access to type metadata for a
95      * given class.
96      *
97      * This checks for a static getTypeDesc() method on the
98      * class or _Helper class.
99      * Eventually we may extend this to provide for external
100      * metadata config (via files sitting in the classpath, etc).
101      *
102      */

103     public static TypeDesc getTypeDescForClass(Class JavaDoc cls)
104     {
105         // First see if we have one explicitly registered
106
// or cached from previous lookup
107
TypeDesc result = (TypeDesc)classMap.get(cls);
108
109         if (result == null) {
110             try {
111                 Method JavaDoc getTypeDesc =
112                     MethodCache.getInstance().getMethod(cls,
113                                                         "getTypeDesc",
114                                                         noClasses);
115                 if (getTypeDesc != null) {
116                     result = (TypeDesc)getTypeDesc.invoke(null, noObjects);
117                     if (result != null) {
118                         classMap.put(cls, result);
119                     }
120                 }
121             } catch (Exception JavaDoc e) {
122             }
123         }
124         
125         return result;
126     }
127
128     /** The Java class for this type */
129     private Class JavaDoc javaClass = null;
130
131     /** The XML type QName for this type */
132     private QName JavaDoc xmlType = null;
133
134     /** The various fields in here */
135     private FieldDesc [] fields;
136
137     /** A cache of FieldDescs by name */
138     private HashMap JavaDoc fieldNameMap = new HashMap JavaDoc();
139     
140     /** A cache of FieldDescs by Element QName */
141     private HashMap JavaDoc fieldElementMap = null;
142     
143     /** Are there any fields which are serialized as attributes? */
144     private boolean _hasAttributes = false;
145
146     /** Introspected property descriptors */
147     private BeanPropertyDescriptor[] propertyDescriptors = null;
148     /** Map with key = property descriptor name, value = descriptor */
149     private Map JavaDoc propertyMap = null;
150
151     /**
152      * Indication if this type has support for xsd:any.
153      */

154     private BeanPropertyDescriptor anyDesc = null;
155
156     public BeanPropertyDescriptor getAnyDesc() {
157         return anyDesc;
158     }
159
160     /**
161      * Obtain the current array of FieldDescs
162      */

163     public FieldDesc[] getFields() {
164         return fields;
165     }
166
167     public FieldDesc[] getFields(boolean searchParents) {
168         // note that if canSearchParents is false, this is identical
169
// to getFields(), because the parent type's metadata is off
170
// limits for restricted types which are required to provide a
171
// complete description of their content model in their own
172
// metadata, per the XML schema rules for
173
// derivation-by-restriction
174
if (canSearchParents && searchParents && !hasSearchedParents) {
175             // check superclasses if they exist
176
if (parentDesc != null) {
177                 FieldDesc [] parentFields = parentDesc.getFields(true);
178 // START FIX http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17188
179
if (parentFields != null) {
180                     if (fields != null) {
181                         FieldDesc [] ret = new FieldDesc[parentFields.length + fields.length];
182                         System.arraycopy(parentFields, 0, ret, 0, parentFields.length);
183                         System.arraycopy(fields, 0, ret, parentFields.length, fields.length);
184                         fields = ret;
185                     } else {
186                         FieldDesc [] ret = new FieldDesc[parentFields.length];
187                         System.arraycopy(parentFields, 0, ret, 0, parentFields.length);
188                         fields = ret;
189                     }
190 // END FIX http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17188
191
}
192             }
193             
194             hasSearchedParents = true;
195         }
196
197         return fields;
198     }
199
200     /**
201      * Replace the array of FieldDescs, making sure we keep our convenience
202      * caches in sync.
203      */

204     public void setFields(FieldDesc [] newFields)
205     {
206         fieldNameMap = new HashMap JavaDoc();
207         fields = newFields;
208         _hasAttributes = false;
209         fieldElementMap = null;
210         
211         for (int i = 0; i < newFields.length; i++) {
212             FieldDesc field = newFields[i];
213             if (!field.isElement()) {
214                 _hasAttributes = true;
215             }
216             fieldNameMap.put(field.getFieldName(), field);
217         }
218     }
219
220     /**
221      * Add a new FieldDesc, keeping the convenience fields in sync.
222      */

223     public void addFieldDesc(FieldDesc field)
224     {
225         if (field == null) {
226             throw new IllegalArgumentException JavaDoc(
227                     Messages.getMessage("nullFieldDesc"));
228         }
229         
230         int numFields = 0;
231         if (fields != null) {
232             numFields = fields.length;
233         }
234         FieldDesc [] newFields = new FieldDesc[numFields + 1];
235         if (fields != null) {
236             System.arraycopy(fields, 0, newFields, 0, numFields);
237         }
238         newFields[numFields] = field;
239         fields = newFields;
240         
241         // Keep track of the field by name for fast lookup
242
fieldNameMap.put(field.getFieldName(), field);
243         
244         if (!_hasAttributes && !field.isElement())
245             _hasAttributes = true;
246     }
247
248     /**
249      * Get the QName associated with this field, but only if it's
250      * marked as an element.
251      */

252     public QName JavaDoc getElementNameForField(String JavaDoc fieldName)
253     {
254         FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName);
255         if (desc == null) {
256             // check superclasses if they exist
257
// and we are allowed to look
258
if (canSearchParents) {
259                 if (parentDesc != null) {
260                     return parentDesc.getElementNameForField(fieldName);
261                 }
262             }
263         } else if (desc.isElement()) {
264             return desc.getXmlName();
265         }
266         return null;
267     }
268     
269     /**
270      * Get the QName associated with this field, but only if it's
271      * marked as an attribute.
272      */

273     public QName JavaDoc getAttributeNameForField(String JavaDoc fieldName)
274     {
275         FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName);
276         if (desc == null) {
277             // check superclasses if they exist
278
// and we are allowed to look
279
if (canSearchParents) {
280                 if (parentDesc != null) {
281                     return parentDesc.getAttributeNameForField(fieldName);
282                 }
283             }
284         } else if (!desc.isElement()) {
285             QName JavaDoc ret = desc.getXmlName();
286             if (ret == null) {
287                 ret = new QName JavaDoc("", fieldName);
288             }
289             return ret;
290         }
291         return null;
292     }
293
294     /**
295      * Get the field name associated with this QName, but only if it's
296      * marked as an element.
297      *
298      * If the "ignoreNS" argument is true, just compare localNames.
299      */

300     public String JavaDoc getFieldNameForElement(QName JavaDoc qname, boolean ignoreNS)
301     {
302         // have we already computed the answer to this question?
303
if (fieldElementMap != null) {
304             String JavaDoc cached = (String JavaDoc) fieldElementMap.get(qname);
305             if (cached != null) return cached;
306         }
307
308         String JavaDoc result = null;
309
310         String JavaDoc localPart = qname.getLocalPart();
311
312         // check fields in this class
313
for (int i = 0; fields != null && i < fields.length; i++) {
314             FieldDesc field = fields[i];
315             if (field.isElement()) {
316                 QName JavaDoc xmlName = field.getXmlName();
317                 if (localPart.equals(xmlName.getLocalPart())) {
318                     if (ignoreNS || qname.getNamespaceURI().
319                                         equals(xmlName.getNamespaceURI())) {
320                         result = field.getFieldName();
321                         break;
322                     }
323                 }
324             }
325         }
326         
327         // check superclasses if they exist
328
// and we are allowed to look
329
if (result == null && canSearchParents) {
330             if (parentDesc != null) {
331                 result = parentDesc.getFieldNameForElement(qname, ignoreNS);
332             }
333         }
334
335         // cache the answer away for quicker retrieval next time.
336
if (result != null) {
337             if (fieldElementMap == null) fieldElementMap = new HashMap JavaDoc();
338             fieldElementMap.put(qname, result);
339         }
340
341         return result;
342     }
343     
344     /**
345      * Get the field name associated with this QName, but only if it's
346      * marked as an attribute.
347      */

348     public String JavaDoc getFieldNameForAttribute(QName JavaDoc qname)
349     {
350         String JavaDoc possibleMatch = null;
351
352         for (int i = 0; fields != null && i < fields.length; i++) {
353             FieldDesc field = fields[i];
354             if (!field.isElement()) {
355                 // It's an attribute, so if we have a solid match, return
356
// its name.
357
if (qname.equals(field.getXmlName())) {
358                     return field.getFieldName();
359                 }
360                 // Not a solid match, but it's still possible we might match
361
// the default (i.e. QName("", fieldName))
362
if (qname.getNamespaceURI().equals("") &&
363                     qname.getLocalPart().equals(field.getFieldName())) {
364                     possibleMatch = field.getFieldName();
365                 }
366             }
367         }
368         
369         if (possibleMatch == null && canSearchParents) {
370             // check superclasses if they exist
371
// and we are allowed to look
372
if (parentDesc != null) {
373                 possibleMatch = parentDesc.getFieldNameForAttribute(qname);
374             }
375         }
376         
377         return possibleMatch;
378     }
379
380     /**
381      * Get a FieldDesc by field name.
382      */

383     public FieldDesc getFieldByName(String JavaDoc name)
384     {
385         FieldDesc ret = (FieldDesc)fieldNameMap.get(name);
386         if (ret == null && canSearchParents) {
387             if (parentDesc != null) {
388                 ret = parentDesc.getFieldByName(name);
389             }
390         }
391         return ret;
392     }
393
394     /**
395      * Do we have any FieldDescs marked as attributes?
396      */

397     public boolean hasAttributes() {
398         if (_hasAttributes)
399             return true;
400         
401         if (canSearchParents) {
402             if (parentDesc != null) {
403                 return parentDesc.hasAttributes();
404             }
405         }
406
407         return false;
408     }
409
410     public QName JavaDoc getXmlType() {
411         return xmlType;
412     }
413
414     public void setXmlType(QName JavaDoc xmlType) {
415         this.xmlType = xmlType;
416     }
417
418     /**
419      * Get/Cache the property descriptors
420      * @return PropertyDescriptor
421      */

422     public BeanPropertyDescriptor[] getPropertyDescriptors() {
423         // Return the propertyDescriptors if already set.
424
// If not set, use BeanUtils.getPd to get the property descriptions.
425
//
426
// Since javaClass is a generated class, there
427
// may be a faster way to set the property descriptions than
428
// using BeanUtils.getPd. But for now calling getPd is sufficient.
429
if (propertyDescriptors == null) {
430             makePropertyDescriptors();
431         }
432         return propertyDescriptors;
433     }
434     
435     private synchronized void makePropertyDescriptors() {
436         if (propertyDescriptors != null)
437             return;
438
439         propertyDescriptors = BeanUtils.getPd(javaClass, this);
440         if (!lookedForAny) {
441             anyDesc = BeanUtils.getAnyContentPD(javaClass);
442             lookedForAny = true;
443         }
444     }
445
446     public BeanPropertyDescriptor getAnyContentDescriptor() {
447         if (!lookedForAny) {
448             anyDesc = BeanUtils.getAnyContentPD(javaClass);
449             lookedForAny = true;
450         }
451         return anyDesc;
452     }
453
454     /**
455      * Get/Cache the property descriptor map
456      * @return Map with key=propertyName, value=descriptor
457      */

458     public Map JavaDoc getPropertyDescriptorMap() {
459         synchronized (this) {
460             // Return map if already set.
461
if (propertyMap != null) {
462                 return propertyMap;
463             }
464
465             // Make sure properties exist
466
if (propertyDescriptors == null) {
467                 getPropertyDescriptors();
468             }
469
470             // Build the map
471
propertyMap = new HashMap JavaDoc();
472             for (int i = 0; i < propertyDescriptors.length; i++) {
473                 BeanPropertyDescriptor descriptor = propertyDescriptors[i];
474                 propertyMap.put(descriptor.getName(), descriptor);
475             }
476         }
477         return propertyMap;
478     }
479 }
480
Popular Tags