KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > shark > asap > util > BeanSerializerShark


1 /*
2  * Copyright 2001-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.enhydra.shark.asap.util;
18
19 import org.apache.axis.AxisFault;
20 import org.apache.axis.Constants;
21 import org.apache.axis.components.logger.LogFactory;
22 import org.apache.axis.description.FieldDesc;
23 import org.apache.axis.description.TypeDesc;
24 import org.apache.axis.encoding.SerializationContext;
25 import org.apache.axis.encoding.Serializer;
26 import org.apache.axis.message.MessageElement;
27 import org.apache.axis.utils.BeanPropertyDescriptor;
28 import org.apache.axis.utils.BeanUtils;
29 import org.apache.axis.utils.Messages;
30 import org.apache.axis.utils.FieldPropertyDescriptor;
31 import org.apache.axis.wsdl.fromJava.Types;
32 import org.apache.axis.wsdl.symbolTable.SchemaUtils;
33 import org.apache.commons.logging.Log;
34 import org.w3c.dom.Element JavaDoc;
35 import org.xml.sax.Attributes JavaDoc;
36 import org.xml.sax.helpers.AttributesImpl JavaDoc;
37 import org.apache.axis.encoding.ser.*;
38
39 import javax.xml.namespace.QName JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.io.Serializable JavaDoc;
42 import java.lang.reflect.InvocationTargetException JavaDoc;
43 import java.lang.reflect.Modifier JavaDoc;
44 import java.util.List JavaDoc;
45 import java.lang.reflect.InvocationTargetException JavaDoc;
46 import java.lang.reflect.Method JavaDoc;
47
48 /**
49  * General purpose serializer/deserializerFactory for an arbitrary java bean.
50  *
51  * @author Sam Ruby <rubys@us.ibm.com>
52  * @author Rich Scheuerle <scheu@us.ibm.com>
53  * @author Tom Jordahl <tomj@macromedia.com>
54  */

55 public class BeanSerializerShark implements Serializer, Serializable JavaDoc {
56
57     protected static Log log =
58         LogFactory.getLog(BeanSerializerShark.class.getName());
59
60     QName JavaDoc xmlType;
61     Class JavaDoc javaType;
62
63     protected BeanPropertyDescriptor[] propertyDescriptor = null;
64     protected TypeDesc typeDesc = null;
65
66
67     // Construct BeanSerializer for the indicated class/qname
68
public BeanSerializerShark(Class JavaDoc javaType, QName JavaDoc xmlType) {
69         this(javaType, xmlType, TypeDesc.getTypeDescForClass(javaType));
70     }
71
72     // Construct BeanSerializer for the indicated class/qname
73
public BeanSerializerShark(Class JavaDoc javaType, QName JavaDoc xmlType, TypeDesc typeDesc) {
74         this(javaType, xmlType, typeDesc, null);
75
76         if (typeDesc != null) {
77             propertyDescriptor = typeDesc.getPropertyDescriptors();
78         } else {
79             propertyDescriptor = BeanUtils.getPd(javaType, null);
80         }
81     }
82
83     // Construct BeanSerializer for the indicated class/qname/propertyDesc
84
public BeanSerializerShark(Class JavaDoc javaType, QName JavaDoc xmlType, TypeDesc typeDesc,
85                           BeanPropertyDescriptor[] propertyDescriptor) {
86         this.xmlType = xmlType;
87         this.javaType = javaType;
88         this.typeDesc = typeDesc;
89         this.propertyDescriptor = propertyDescriptor;
90     }
91
92     /**
93      * Serialize a bean. Done simply by serializing each bean property.
94      * @param name is the element name
95      * @param attributes are the attributes...serialize is free to add more.
96      * @param value is the value
97      * @param context is the SerializationContext
98      */

99     public void serialize(QName JavaDoc name, Attributes JavaDoc attributes,
100                           Object JavaDoc value, SerializationContext context)
101         throws IOException JavaDoc
102     {
103         // Check for meta-data in the bean that will tell us if any of the
104
// properties are actually attributes, add those to the element
105
// attribute list
106
Attributes JavaDoc beanAttrs = getObjectAttributes(value, attributes, context);
107
108         // Get the encoding style
109
String JavaDoc encodingStyle = context.getEncodingStyle();
110         boolean isEncoded = Constants.isSOAP_ENC(encodingStyle);
111
112         // check whether we have and xsd:any namespace="##any" type
113
boolean suppressElement = !context.isEncoded() &&
114                                   name.getNamespaceURI().equals("") &&
115                                   name.getLocalPart().equals("any");
116
117         boolean grpElement = name.toString().endsWith("Group");
118         suppressElement |= grpElement;
119
120         if (!suppressElement)
121             context.startElement(name, beanAttrs);
122
123         try {
124             // Serialize each property
125
for (int i=0; i<propertyDescriptor.length; i++) {
126                 String JavaDoc propName = propertyDescriptor[i].getName();
127                 if (propName.equals("class"))
128                     continue;
129                 QName JavaDoc qname = null;
130                 QName JavaDoc xmlType = null;
131                 boolean isOmittable = false;
132
133                 // If we have type metadata, check to see what we're doing
134
// with this field. If it's an attribute, skip it. If it's
135
// an element, use whatever qname is in there. If we can't
136
// find any of this info, use the default.
137

138                 if (typeDesc != null) {
139                     FieldDesc field = typeDesc.getFieldByName(propName);
140                     if (field != null) {
141                         if (!field.isElement())
142                             continue;
143
144                         // If we're SOAP encoded, just use the local part,
145
// not the namespace. Otherwise use the whole
146
// QName.
147
if (isEncoded) {
148                             qname = new QName JavaDoc(
149                                           field.getXmlName().getLocalPart());
150                         } else {
151                             qname = field.getXmlName();
152                         }
153                         isOmittable = field.isMinOccursZero();
154                         xmlType = field.getXmlType();
155                     }
156                 }
157
158                 if (qname == null) {
159                     qname = new QName JavaDoc(isEncoded ? "" : name.getNamespaceURI(),
160                                       propName);
161                 }
162
163                 if (xmlType == null) {
164                     // look up the type QName using the class
165
xmlType = context.getQNameForClass(propertyDescriptor[i].getType());
166                 }
167
168                 // Read the value from the property
169
if(propertyDescriptor[i].isReadable()) {
170                     if (!propertyDescriptor[i].isIndexed()) {
171                         // Normal case: serialize the value
172
Object JavaDoc propValue =
173                             propertyDescriptor[i].get(value);
174                         // if meta data says minOccurs=0, then we can skip
175
// it if its value is null and we aren't doing SOAP
176
// encoding.
177
if (propValue == null &&
178                                 isOmittable &&
179                                 !isEncoded)
180                             continue;
181
182                         if (null == propValue && qname.toString().endsWith("Group")) {
183                             System.err.println("\telemQName:"+ qname +" contains 'Group' not appending nil");
184                             continue;
185                         }
186                         context.serialize(qname,
187                                           null,
188                                           propValue,
189                                           xmlType,
190                                           true,
191                                           null);
192                     } else {
193                         // Collection of properties: serialize each one
194
int j=0;
195                         while(j >= 0) {
196                             Object JavaDoc propValue = null;
197                             try {
198                                 propValue =
199                                     propertyDescriptor[i].get(value, j);
200                                 j++;
201                             } catch (Exception JavaDoc e) {
202                                 j = -1;
203                             }
204                             if (j >= 0) {
205                                 context.serialize(qname, null,
206                                                   propValue, xmlType,
207                                                   true, null);
208                             }
209                         }
210                     }
211                 }
212             }
213
214             BeanPropertyDescriptor anyDesc = typeDesc == null ? null :
215                     typeDesc.getAnyDesc();
216             if (anyDesc != null) {
217                 // If we have "extra" content here, it'll be an array
218
// of MessageElements. Serialize each one.
219
Object JavaDoc anyVal = anyDesc.get(value);
220                 if (anyVal != null && anyVal instanceof MessageElement[]) {
221                     MessageElement [] anyContent = (MessageElement[])anyVal;
222                     for (int i = 0; i < anyContent.length; i++) {
223                         MessageElement element = anyContent[i];
224                         element.output(context);
225                     }
226                 }
227             }
228         } catch (InvocationTargetException JavaDoc ite) {
229             Throwable JavaDoc target = ite.getTargetException();
230             log.error(Messages.getMessage("exception00"), target);
231             throw new IOException JavaDoc(target.toString());
232         } catch (Exception JavaDoc e) {
233             log.error(Messages.getMessage("exception00"), e);
234             throw new IOException JavaDoc(e.toString());
235         }
236
237         if (!suppressElement)
238             context.endElement();
239     }
240
241
242
243     public String JavaDoc getMechanismType() { return Constants.AXIS_SAX; }
244
245     /**
246      * Return XML schema for the specified type, suitable for insertion into
247      * the &lt;types&gt; element of a WSDL document, or underneath an
248      * &lt;element&gt; or &lt;attribute&gt; declaration.
249      *
250      * @param javaType the Java Class we're writing out schema for
251      * @param types the Java2WSDL Types object which holds the context
252      * for the WSDL being generated.
253      * @return a type element containing a schema simpleType/complexType
254      * @see org.apache.axis.wsdl.fromJava.Types
255      */

256     public Element writeSchema(Class JavaDoc javaType, Types types) throws Exception JavaDoc {
257
258         // ComplexType representation of bean class
259
Element complexType = types.createElement("complexType");
260
261         // See if there is a super class, stop if we hit a stop class
262
Element e = null;
263         Class JavaDoc superClass = javaType.getSuperclass();
264         BeanPropertyDescriptor[] superPd = null;
265         List JavaDoc stopClasses = types.getStopClasses();
266         if (superClass != null &&
267                 superClass != java.lang.Object JavaDoc.class &&
268                 superClass != java.lang.Exception JavaDoc.class &&
269                 superClass != java.lang.Throwable JavaDoc.class &&
270                 superClass != java.rmi.RemoteException JavaDoc.class &&
271                 superClass != org.apache.axis.AxisFault.class &&
272                 (stopClasses == null ||
273                 !(stopClasses.contains(superClass.getName()))) ) {
274             // Write out the super class
275
String JavaDoc base = types.writeType(superClass);
276             Element complexContent = types.createElement("complexContent");
277             complexType.appendChild(complexContent);
278             Element extension = types.createElement("extension");
279             complexContent.appendChild(extension);
280             extension.setAttribute("base", base);
281             e = extension;
282             // Get the property descriptors for the super class
283
TypeDesc superTypeDesc = TypeDesc.getTypeDescForClass(superClass);
284             if (superTypeDesc != null) {
285                 superPd = superTypeDesc.getPropertyDescriptors();
286             } else {
287                 superPd = BeanUtils.getPd(superClass, null);
288             }
289         } else {
290             e = complexType;
291         }
292
293         // Add fields under sequence element.
294
// Note: In most situations it would be okay
295
// to put the fields under an all element.
296
// However it is illegal schema to put an
297
// element with minOccurs=0 or maxOccurs>1 underneath
298
// an all element. This is the reason why a sequence
299
// element is used.
300
Element all = types.createElement("sequence");
301         e.appendChild(all);
302
303         if (Modifier.isAbstract(javaType.getModifiers())) {
304             complexType.setAttribute("abstract", "true");
305         }
306
307         // Serialize each property
308
for (int i=0; i<propertyDescriptor.length; i++) {
309             String JavaDoc propName = propertyDescriptor[i].getName();
310
311             // Don't serializer properties named class
312
boolean writeProperty = true;
313             if (propName.equals("class")) {
314                 writeProperty = false;
315             }
316
317             // Don't serialize the property if it is present
318
// in the super class property list
319
if (superPd != null && writeProperty) {
320                 for (int j=0; j<superPd.length && writeProperty; j++) {
321                     if (propName.equals(superPd[j].getName())) {
322                         writeProperty = false;
323                     }
324                 }
325             }
326             if (!writeProperty) {
327                 continue;
328             }
329
330             // If we have type metadata, check to see what we're doing
331
// with this field. If it's an attribute, skip it. If it's
332
// an element, use whatever qname is in there. If we can't
333
// find any of this info, use the default.
334

335             if (typeDesc != null) {
336                 Class JavaDoc fieldType = propertyDescriptor[i].getType();
337                 FieldDesc field = typeDesc.getFieldByName(propName);
338
339                 if (field != null) {
340                     QName JavaDoc qname = field.getXmlName();
341                     QName JavaDoc fieldXmlType = field.getXmlType();
342                     boolean isAnonymous = fieldXmlType != null && fieldXmlType.getLocalPart().startsWith(">");
343
344                     if (qname != null) {
345                         // FIXME!
346
// Check to see if this is in the right namespace -
347
// if it's not, we need to use an <element ref="">
348
// to represent it!!!
349

350                         // Use the default...
351
propName = qname.getLocalPart();
352                     }
353                     if (!field.isElement()) {
354                         writeAttribute(types,
355                                        propName,
356                                        fieldType,
357                                        fieldXmlType,
358                                        complexType);
359                     } else {
360                         writeField(types,
361                                    propName,
362                                    fieldXmlType,
363                                    fieldType,
364                                    propertyDescriptor[i].isIndexed(),
365                                    field.isMinOccursZero(),
366                                    all, isAnonymous);
367                     }
368                 } else {
369                     writeField(types,
370                                propName,
371                                null,
372                                fieldType,
373                                propertyDescriptor[i].isIndexed(), false, all, false);
374                 }
375             } else {
376                 boolean done = false;
377                 if(propertyDescriptor[i] instanceof FieldPropertyDescriptor){
378                     FieldPropertyDescriptor fpd = (FieldPropertyDescriptor) propertyDescriptor[i];
379                     Class JavaDoc clazz = fpd.getField().getType();
380                     if(types.getTypeQName(clazz)!=null) {
381                         writeField(types,
382                                    propName,
383                                    null,
384                                    clazz,
385                                    false, false, all, false);
386
387                         done = true;
388                     }
389                 }
390                 if(!done) {
391                     writeField(types,
392                                propName,
393                                null,
394                                propertyDescriptor[i].getType(),
395                                propertyDescriptor[i].isIndexed(), false, all, false);
396                 }
397
398             }
399         }
400
401         // done
402
return complexType;
403     }
404
405     /**
406      * write a schema representation of the given Class field and append it to
407      * the where Node, recurse on complex types
408      * @param fieldName name of the field
409      * @param xmlType the schema type of the field
410      * @param fieldType type of the field
411      * @param isUnbounded causes maxOccurs="unbounded" if set
412      * @param where location for the generated schema node
413      * @throws Exception
414      */

415     protected void writeField(Types types,
416                               String JavaDoc fieldName,
417                               QName JavaDoc xmlType,
418                               Class JavaDoc fieldType,
419                               boolean isUnbounded,
420                               boolean isOmittable,
421                               Element where,
422                               boolean isAnonymous) throws Exception JavaDoc {
423         Element elem;
424         if (isAnonymous) {
425             elem = types.createElementWithAnonymousType(fieldName,
426             fieldType, isOmittable, where.getOwnerDocument());
427         } else {
428             if (!SchemaUtils.isSimpleSchemaType(xmlType) && Types.isArray(fieldType)) {
429                 xmlType = null;
430             }
431
432             String JavaDoc elementType = types.writeType(fieldType, xmlType);
433
434             if (elementType == null) {
435                 // If writeType returns null, then emit an anytype in such situations.
436
QName JavaDoc anyQN = Constants.XSD_ANYTYPE;
437                 String JavaDoc prefix = types.getNamespaces().getCreatePrefix(anyQN.getNamespaceURI());
438                 elementType = prefix + ":" + anyQN.getLocalPart();
439             }
440
441             elem = types.createElement(fieldName,
442                     elementType,
443                     types.isNullable(fieldType),
444                     isOmittable,
445                     where.getOwnerDocument());
446         }
447
448         if (isUnbounded) {
449             elem.setAttribute("maxOccurs", "unbounded");
450         }
451
452         where.appendChild(elem);
453     }
454
455     /**
456      * write aa attribute element and append it to the 'where' Node
457      * @param fieldName name of the field
458      * @param fieldType type of the field
459      * @param where location for the generated schema node
460      * @throws Exception
461      */

462     protected void writeAttribute(Types types,
463                                 String JavaDoc fieldName,
464                                 Class JavaDoc fieldType,
465                                 QName JavaDoc fieldXmlType,
466                                 Element where) throws Exception JavaDoc {
467
468         // Attribute must be a simple type.
469
if (!types.isAcceptableAsAttribute(fieldType)) {
470             throw new AxisFault(Messages.getMessage("AttrNotSimpleType00",
471                                                      fieldName,
472                                                      fieldType.getName()));
473         }
474         Element elem = types.createAttributeElement(fieldName,
475                                            fieldType, fieldXmlType,
476                                            false,
477                                            where.getOwnerDocument());
478         where.appendChild(elem);
479     }
480
481     /**
482      * Check for meta-data in the bean that will tell us if any of the
483      * properties are actually attributes, add those to the element
484      * attribute list
485      *
486      * @param value the object we are serializing
487      * @return attributes for this element, null if none
488      */

489     protected Attributes JavaDoc getObjectAttributes(Object JavaDoc value,
490                                            Attributes JavaDoc attributes,
491                                            SerializationContext context) {
492
493         if (typeDesc == null || !typeDesc.hasAttributes())
494             return attributes;
495
496         AttributesImpl JavaDoc attrs;
497         if (attributes == null) {
498             attrs = new AttributesImpl JavaDoc();
499         } else if (attributes instanceof AttributesImpl JavaDoc) {
500             attrs = (AttributesImpl JavaDoc)attributes;
501         } else {
502             attrs = new AttributesImpl JavaDoc(attributes);
503         }
504
505         try {
506             // Find each property that is an attribute
507
// and add it to our attribute list
508
for (int i=0; i<propertyDescriptor.length; i++) {
509                 String JavaDoc propName = propertyDescriptor[i].getName();
510                 if (propName.equals("class"))
511                     continue;
512
513                 FieldDesc field = typeDesc.getFieldByName(propName);
514                 // skip it if its not an attribute
515
if (field == null || field.isElement())
516                     continue;
517
518                 QName JavaDoc qname = field.getXmlName();
519                 if (qname == null) {
520                     qname = new QName JavaDoc("", propName);
521                 }
522
523                 if (propertyDescriptor[i].isReadable() &&
524                     !propertyDescriptor[i].isIndexed()) {
525                     // add to our attributes
526
Object JavaDoc propValue = propertyDescriptor[i].get(value);
527                     // Convert true/false to 1/0 in case of soapenv:mustUnderstand
528
if (qname.equals(new QName JavaDoc(Constants.URI_SOAP11_ENV, Constants.ATTR_MUST_UNDERSTAND))) {
529                         if (propValue.equals(Boolean.TRUE)) {
530                                 propValue = "1";
531                         } else if (propValue.equals(Boolean.FALSE)) {
532                                 propValue = "0";
533                         }
534                     }
535                     // If the property value does not exist, don't serialize
536
// the attribute. In the future, the decision to serializer
537
// the attribute may be more sophisticated. For example, don't
538
// serialize if the attribute matches the default value.
539
if (propValue != null) {
540                         setAttributeProperty(propValue,
541                                              qname,
542                                              field.getXmlType(),
543                                              attrs,
544                                              context);
545                     }
546                 }
547             }
548         } catch (Exception JavaDoc e) {
549             // no attributes
550
return attrs;
551         }
552
553         return attrs;
554     }
555
556     private void setAttributeProperty(Object JavaDoc propValue,
557                                       QName JavaDoc qname,
558                                       QName JavaDoc xmlType, AttributesImpl JavaDoc attrs,
559                                       SerializationContext context) throws Exception JavaDoc {
560
561         String JavaDoc namespace = qname.getNamespaceURI();
562         String JavaDoc localName = qname.getLocalPart();
563
564         // org.xml.sax.helpers.AttributesImpl JavaDoc says: "For the
565
// sake of speed, this method does no checking to see if the
566
// attribute is already in the list: that is the
567
// responsibility of the application." check for the existence
568
// of the attribute to avoid adding it more than once.
569
if (attrs.getIndex(namespace, localName) != -1) {
570             return;
571         }
572
573         String JavaDoc propString = context.getValueAsString(propValue, xmlType);
574
575         attrs.addAttribute(namespace,
576                            localName,
577                            context.attributeQName2String(qname),
578                            "CDATA",
579                            propString);
580     }
581 }
582
Popular Tags