KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > shark > wfxml > 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.wfxml.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     private boolean isEmptyObjectType(QName JavaDoc name) {
92        return (name.getLocalPart().equals("GetPropertiesRq"))
93        || (name.getLocalPart().equals("SubscribeRs"))
94        || (name.getLocalPart().equals("UnsubscribeRs"))
95        || (name.getLocalPart().equals("CompletedRs"))
96        || (name.getLocalPart().equals("StateChangedRs"));
97     }
98     /**
99      * Serialize a bean. Done simply by serializing each bean property.
100      * @param name is the element name
101      * @param attributes are the attributes...serialize is free to add more.
102      * @param value is the value
103      * @param context is the SerializationContext
104      */

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

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

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

345             if (typeDesc != null) {
346                 Class JavaDoc fieldType = propertyDescriptor[i].getType();
347                 FieldDesc field = typeDesc.getFieldByName(propName);
348
349                 if (field != null) {
350                     QName JavaDoc qname = field.getXmlName();
351                     QName JavaDoc fieldXmlType = field.getXmlType();
352                     boolean isAnonymous = fieldXmlType != null && fieldXmlType.getLocalPart().startsWith(">");
353
354                     if (qname != null) {
355                         // FIXME!
356
// Check to see if this is in the right namespace -
357
// if it's not, we need to use an <element ref="">
358
// to represent it!!!
359

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

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

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

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