KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > wsdl > fromJava > Types


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2002 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.wsdl.fromJava;
57
58 import org.jboss.axis.AxisFault;
59 import org.jboss.axis.Constants;
60 import org.jboss.axis.InternalException;
61 import org.jboss.axis.description.ServiceDesc;
62 import org.jboss.axis.encoding.Serializer;
63 import org.jboss.axis.encoding.SerializerFactory;
64 import org.jboss.axis.encoding.SimpleType;
65 import org.jboss.axis.encoding.TypeMapping;
66 import org.jboss.axis.encoding.ser.BeanSerializerFactory;
67 import org.jboss.axis.encoding.ser.EnumSerializerFactory;
68 import org.jboss.axis.enums.Style;
69 import org.jboss.axis.utils.JavaUtils;
70 import org.jboss.axis.utils.Messages;
71 import org.jboss.axis.utils.XMLUtils;
72 import org.jboss.axis.wsdl.symbolTable.BaseTypeMapping;
73 import org.jboss.axis.wsdl.symbolTable.SymbolTable;
74 import org.jboss.logging.Logger;
75 import org.w3c.dom.Attr JavaDoc;
76 import org.w3c.dom.Document JavaDoc;
77 import org.w3c.dom.Element JavaDoc;
78 import org.w3c.dom.NamedNodeMap JavaDoc;
79 import org.w3c.dom.Node JavaDoc;
80 import org.w3c.dom.NodeList JavaDoc;
81 import org.xml.sax.SAXException JavaDoc;
82
83 import javax.wsdl.Definition;
84 import javax.wsdl.WSDLException;
85 import javax.xml.namespace.QName JavaDoc;
86 import javax.xml.parsers.ParserConfigurationException JavaDoc;
87 import javax.xml.rpc.holders.Holder JavaDoc;
88 import java.io.IOException JavaDoc;
89 import java.lang.reflect.Field JavaDoc;
90 import java.lang.reflect.Modifier JavaDoc;
91 import java.net.URL JavaDoc;
92 import java.util.ArrayList JavaDoc;
93 import java.util.HashMap JavaDoc;
94 import java.util.Iterator JavaDoc;
95 import java.util.List JavaDoc;
96
97 /**
98  * <p>Description: </p> This class is used to recursively serializes a Java Class into
99  * an XML Schema representation.
100  * <p/>
101  * It has utility methods to create a schema node, assosiate namespaces to the various types
102  *
103  * @author unascribed
104  */

105 public class Types
106 {
107    private static Logger log = Logger.getLogger(Types.class.getName());
108
109    Definition def;
110    Namespaces namespaces = null;
111    TypeMapping tm;
112    TypeMapping defaultTM;
113    String JavaDoc targetNamespace;
114    Element JavaDoc wsdlTypesElem = null;
115    HashMap JavaDoc schemaTypes = null;
116    HashMap JavaDoc schemaElementNames = null;
117    HashMap JavaDoc schemaUniqueElementNames = null;
118    HashMap JavaDoc wrapperMap = new HashMap JavaDoc();
119    List JavaDoc stopClasses = null;
120    List JavaDoc beanCompatErrs = new ArrayList JavaDoc();
121    ServiceDesc serviceDesc = null;
122
123    /**
124     * This class serailizes a <code>Class</code> to XML Schema. The constructor
125     * provides the context for the streamed node within the WSDL document
126     *
127     * @param def WSDL Definition Element to declare namespaces
128     * @param tm TypeMappingRegistry to handle known types
129     * @param defaultTM default TM
130     * @param namespaces user defined or autogenerated namespace and prefix maps
131     * @param targetNamespace targetNamespace of the document
132     */

133    public Types(Definition def,
134                 TypeMapping tm,
135                 TypeMapping defaultTM,
136                 Namespaces namespaces,
137                 String JavaDoc targetNamespace,
138                 List JavaDoc stopClasses,
139                 ServiceDesc serviceDesc)
140    {
141       this.def = def;
142       this.serviceDesc = serviceDesc;
143       createDocumentFragment();
144       this.tm = tm;
145       this.defaultTM = defaultTM;
146       this.namespaces = namespaces;
147       this.targetNamespace = targetNamespace;
148       this.stopClasses = stopClasses;
149       schemaElementNames = new HashMap JavaDoc();
150       schemaUniqueElementNames = new HashMap JavaDoc();
151       schemaTypes = new HashMap JavaDoc();
152    }
153
154    /**
155     * Return the namespaces object for the current context
156     */

157    public Namespaces getNamespaces()
158    {
159       return namespaces;
160    }
161
162    /**
163     * Loads the types from the input schema file.
164     *
165     * @param inputSchema file or URL
166     */

167    public void loadInputSchema(String JavaDoc inputSchema)
168            throws IOException JavaDoc, WSDLException, SAXException JavaDoc,
169            ParserConfigurationException JavaDoc
170    {
171       // Read the input wsdl file into a Document
172
Document JavaDoc doc = XMLUtils.newDocument(inputSchema);
173
174       // Ensure that the root element is xsd:schema
175
Element JavaDoc root = doc.getDocumentElement();
176       if (root.getLocalName().equals("schema") &&
177               Constants.isSchemaXSD(root.getNamespaceURI()))
178       {
179          Node JavaDoc schema = docHolder.importNode(root, true);
180          if (null == wsdlTypesElem)
181          {
182             writeWsdlTypesElement();
183          }
184          wsdlTypesElem.appendChild(schema);
185
186          // Create a symbol table and populate it with the input types
187
BaseTypeMapping btm =
188                  new BaseTypeMapping()
189                  {
190                     public String JavaDoc getBaseName(QName JavaDoc qNameIn)
191                     {
192                        QName JavaDoc qName = new QName JavaDoc(qNameIn.getNamespaceURI(),
193                                qNameIn.getLocalPart());
194                        Class JavaDoc cls = defaultTM.getClassForQName(qName);
195                        if (cls == null)
196                           return null;
197                        else
198                           return JavaUtils.getTextClassName(cls.getName());
199                     }
200                  };
201          SymbolTable symbolTable = new SymbolTable(btm,
202                  true, false, false);
203          symbolTable.populateTypes(new URL JavaDoc(inputSchema), doc);
204
205          processSymTabEntries(symbolTable);
206       }
207       else
208       {
209          // If not, we'll just bail out... perhaps we should log a warning
210
// or throw an exception?
211
;
212       }
213    }
214
215    /**
216     * Walk the type/element entries in the symbol table and
217     * add each one to the list of processed types. This prevents
218     * the types from being duplicated.
219     *
220     * @param symbolTable
221     */

222    private void processSymTabEntries(SymbolTable symbolTable)
223    {
224       Iterator JavaDoc iterator = symbolTable.getElementIndex().keySet().iterator();
225       while (iterator.hasNext())
226       {
227          QName JavaDoc name = (QName JavaDoc)iterator.next();
228          addToElementsList(name);
229       }
230       iterator = symbolTable.getTypeIndex().keySet().iterator();
231       while (iterator.hasNext())
232       {
233          QName JavaDoc name = (QName JavaDoc)iterator.next();
234          addToTypesList(name);
235       }
236    }
237
238    /**
239     * Load the types from the input wsdl file.
240     *
241     * @param inputWSDL file or URL
242     */

243    public void loadInputTypes(String JavaDoc inputWSDL)
244            throws IOException JavaDoc, WSDLException,
245            SAXException JavaDoc, ParserConfigurationException JavaDoc
246    {
247
248       // Read the input wsdl file into a Document
249
Document JavaDoc doc = XMLUtils.newDocument(inputWSDL);
250
251       // Search for the 'types' element
252
NodeList JavaDoc elements = doc.getChildNodes();
253       if (elements.getLength() > 0 &&
254               elements.item(0).getLocalName().equals("definitions"))
255       {
256          elements = elements.item(0).getChildNodes();
257          for (int i = 0;
258               i < elements.getLength() && wsdlTypesElem == null;
259               i++)
260          {
261             Node JavaDoc node = elements.item(i);
262             if (node.getLocalName() != null &&
263                     node.getLocalName().equals("types"))
264             {
265                wsdlTypesElem = (Element JavaDoc)node;
266             }
267          }
268       }
269
270       // If types element not found, there is no need to continue.
271
if (wsdlTypesElem == null)
272       {
273          return;
274       }
275
276       // Import the types element into the Types docHolder document
277
wsdlTypesElem =
278               (Element JavaDoc)docHolder.importNode(wsdlTypesElem, true);
279       docHolder.appendChild(wsdlTypesElem);
280
281       // Create a symbol table and populate it with the input wsdl document
282
BaseTypeMapping btm =
283               new BaseTypeMapping()
284               {
285                  public String JavaDoc getBaseName(QName JavaDoc qNameIn)
286                  {
287                     QName JavaDoc qName = new QName JavaDoc(qNameIn.getNamespaceURI(),
288                             qNameIn.getLocalPart());
289                     Class JavaDoc cls = defaultTM.getClassForQName(qName);
290                     if (cls == null)
291                        return null;
292                     else
293                        return JavaUtils.getTextClassName(cls.getName());
294                  }
295               };
296       SymbolTable symbolTable = new SymbolTable(btm,
297               true, false, false);
298       symbolTable.populate(null, doc);
299
300       processSymTabEntries(symbolTable);
301    }
302
303    /**
304     * Write out a type referenced by a part type attribute.
305     *
306     * @param type <code>Class</code> to generate the XML Schema info for
307     * @param qname <code>QName</code> of the type. If null, qname is
308     * defaulted from the class.
309     * @return the QName of the generated Schema type, null if void,
310     * if the Class type cannot be converted to a schema type
311     * then xsd:anytype is returned.
312     */

313    public QName JavaDoc writeTypeForPart(Class JavaDoc type, QName JavaDoc qname) throws AxisFault
314    {
315       //patch by costin to fix an NPE; commented out till we find out what the problem is
316
//if you get NullPointerExceptions in this class, turn it on and submit some
317
//replicable test data to the Axis team via bugzilla
318
/*
319       if( type==null ) {
320           return null;
321       }
322       */

323       if (type.getName().equals("void"))
324       {
325          return null;
326       }
327
328       if (Holder JavaDoc.class.isAssignableFrom(type))
329       {
330          type = JavaUtils.getHolderValueType(type);
331       }
332
333       // Get the qname
334
if (qname == null ||
335               (Constants.isSOAP_ENC(qname.getNamespaceURI()) &&
336               "Array".equals(qname.getLocalPart())))
337       {
338          qname = getTypeQName(type);
339          if (qname == null)
340          {
341             throw new AxisFault("Class:" + type.getName());
342          }
343       }
344
345       if (!makeTypeElement(type, qname, null))
346       {
347          qname = Constants.XSD_ANYTYPE;
348       }
349
350       return qname;
351    }
352
353    /**
354     * Write out an element referenced by a part element attribute.
355     *
356     * @param type <code>Class</code> to generate the XML Schema info for
357     * @param qname <code>QName</code> of the element. If null, qname is
358     * defaulted from the class.
359     * @return the QName of the generated Schema type, null if no element
360     */

361    public QName JavaDoc writeElementForPart(Class JavaDoc type, QName JavaDoc qname) throws AxisFault
362    {
363       //patch by costin to fix an NPE; commented out till we find out what the problem is
364
//if you get NullPointerExceptions in this class, turn it on and submit some
365
//replicable test data to the Axis team via bugzilla
366
/*
367       if( type==null ) {
368           return null;
369       }
370       */

371       if (type.getName().equals("void"))
372       {
373          return null;
374       }
375
376       if (Holder JavaDoc.class.isAssignableFrom(type))
377       {
378          type = JavaUtils.getHolderValueType(type);
379       }
380
381       // Get the qname
382
if (qname == null ||
383               (Constants.isSOAP_ENC(qname.getNamespaceURI()) &&
384               "Array".equals(qname.getLocalPart())))
385       {
386          qname = getTypeQName(type);
387          if (qname == null)
388          {
389             throw new AxisFault("Class:" + type.getName());
390          }
391       }
392
393       // Return null it a simple type (not an element)
394
String JavaDoc nsURI = qname.getNamespaceURI();
395       if (Constants.isSchemaXSD(nsURI) ||
396               (Constants.isSOAP_ENC(nsURI) &&
397               !"Array".equals(qname.getLocalPart())))
398       {
399          return null;
400       }
401
402       // Make sure a types section is present
403
if (wsdlTypesElem == null)
404       {
405          writeWsdlTypesElement();
406       }
407
408       // Write Element, if problems occur return null.
409
if (writeTypeAsElement(type, qname) == null)
410       {
411          qname = null;
412       }
413       return qname;
414    }
415
416    /**
417     * Write the element definition for a WRAPPED operation. This will
418     * write out any necessary namespace/schema declarations, an an element
419     * definition with an internal (anonymous) complexType. The name of the
420     * element will be *foo*Request or *foo*Response depending on whether the
421     * request boolean is true. If the operation contains parameters, then
422     * we also generate a &gt;sequence&lt; node underneath the complexType,
423     * and return it for later use by writeWrappedParameter() below.
424     *
425     * @param qname the desired element QName
426     * @param request true if we're writing the request wrapper, false if
427     * writing the response.
428     * @param hasParams true if there are parameters, and thus a sequence
429     * node is needed
430     * @return a DOM Element for the sequence, inside which we'll write the
431     * parameters as elements, or null if there are no parameters
432     */

433    public Element JavaDoc writeWrapperElement(QName JavaDoc qname,
434                                       boolean request,
435                                       boolean hasParams) throws AxisFault
436    {
437       // Make sure a types section is present
438
if (wsdlTypesElem == null)
439       {
440          writeWsdlTypesElement();
441       }
442
443       // Write the namespace definition for the wrapper
444
writeTypeNamespace(qname);
445
446       // Create an <element> for the wrapper
447
Element JavaDoc wrapperElement = docHolder.createElement("element");
448       writeSchemaElement(qname, wrapperElement);
449       wrapperElement.setAttribute("name", qname.getLocalPart());
450
451       // Create an anonymous <complexType> for the wrapper
452
Element JavaDoc complexType = docHolder.createElement("complexType");
453       wrapperElement.appendChild(complexType);
454
455       // If we have parameters in the operation, create a <sequence>
456
// under the complexType and return it.
457
if (hasParams)
458       {
459          Element JavaDoc sequence = docHolder.createElement("sequence");
460          complexType.appendChild(sequence);
461          return sequence;
462       }
463
464       return null;
465    }
466
467    /**
468     * Write a parameter (a sub-element) into a sequence generated by
469     * writeWrapperElement() above.
470     *
471     * @param sequence the &lt;sequence&gt; in which we're writing
472     * @param name is the name of an element to add to the wrapper element.
473     * @param type is the QName of the type of the element.
474     */

475    public void writeWrappedParameter(Element JavaDoc sequence, String JavaDoc name,
476                                      QName JavaDoc type, Class JavaDoc javaType)
477            throws AxisFault
478    {
479
480       if (javaType == void.class)
481       {
482          return;
483       }
484
485       if (type == null)
486       {
487          type = writeTypeForPart(javaType, type);
488       }
489
490       if (type == null)
491       {
492          // throw an Exception!!
493
}
494
495       Element JavaDoc childElem;
496       if (isAnonymousType(type))
497       {
498          childElem = createElementWithAnonymousType(name, javaType,
499                  false, docHolder);
500       }
501       else
502       {
503          // Create the child <element> and add it to the wrapper <sequence>
504
childElem = docHolder.createElement("element");
505          childElem.setAttribute("name", name);
506
507          String JavaDoc prefix = namespaces.getCreatePrefix(type.getNamespaceURI());
508          String JavaDoc prefixedName = prefix + ":" + type.getLocalPart();
509          childElem.setAttribute("type", prefixedName);
510       }
511       sequence.appendChild(childElem);
512    }
513
514    private boolean isAnonymousType(QName JavaDoc type)
515    {
516       return type.getLocalPart().indexOf(SymbolTable.ANON_TOKEN) != -1;
517    }
518
519    /**
520     * Create a schema element for the given type
521     *
522     * @param type the class type
523     * @return the QName of the generated Element or problems occur
524     */

525    private QName JavaDoc writeTypeAsElement(Class JavaDoc type, QName JavaDoc qName) throws AxisFault
526    {
527       if (qName == null ||
528               Constants.equals(Constants.SOAP_ARRAY, qName))
529       {
530          qName = getTypeQName(type);
531       }
532       QName JavaDoc typeQName = writeTypeNamespace(type, qName);
533
534       String JavaDoc elementType = writeType(type, qName);
535       if (elementType != null)
536       {
537          Element JavaDoc element = createElementDecl(qName.getLocalPart(), type, qName, isNullable(type), false);
538          if (element != null)
539             writeSchemaElement(typeQName, element);
540          return qName;
541       }
542       return null;
543    }
544
545    /**
546     * write out the namespace declaration and return the type QName for the
547     * given <code>Class</code>
548     *
549     * @param type input Class
550     * @param qName qname of the Class
551     * @return QName for the schema type representing the class
552     */

553    private QName JavaDoc writeTypeNamespace(Class JavaDoc type, QName JavaDoc qName)
554    {
555       if (qName == null)
556       {
557          qName = getTypeQName(type);
558       }
559       writeTypeNamespace(qName);
560       return qName;
561    }
562
563    /**
564     * write out the namespace declaration.
565     *
566     * @param qName qname of the type
567     */

568    private void writeTypeNamespace(QName JavaDoc qName)
569    {
570       if (qName != null && !qName.getNamespaceURI().equals(""))
571       {
572          String JavaDoc pref = def.getPrefix(qName.getNamespaceURI());
573          if (pref == null)
574             def.addNamespace(namespaces.getCreatePrefix(qName.getNamespaceURI()),
575                     qName.getNamespaceURI());
576
577       }
578    }
579
580    /**
581     * Return the QName of the specified javaType
582     *
583     * @param javaType input javaType Class
584     * @return QName
585     */

586    public QName JavaDoc getTypeQName(Class JavaDoc javaType)
587    {
588       QName JavaDoc qName = null;
589
590       // Use the typeMapping information to lookup the qName.
591
QName JavaDoc dQName = null;
592       if (defaultTM != null)
593       {
594          dQName = defaultTM.getTypeQName(javaType);
595       }
596       if (tm != null)
597       {
598          qName = tm.getTypeQName(javaType);
599       }
600       if (qName == null)
601       {
602          qName = dQName;
603       }
604       else if (qName != null && qName != dQName)
605       {
606          // If the TM and default TM resulted in different
607
// names, choose qName unless it is a schema namespace.
608
// (i.e. prefer soapenc primitives over schema primitives)
609
if (Constants.isSchemaXSD(qName.getNamespaceURI()))
610          {
611             qName = dQName;
612          }
613       }
614
615       // If the javaType is an array and the qName is
616
// SOAP_ARRAY, construct the QName using the
617
// QName of the component type
618
if (javaType.isArray() &&
619               qName != null &&
620               Constants.equals(Constants.SOAP_ARRAY, qName))
621       {
622          Class JavaDoc componentType = javaType.getComponentType();
623          // If component namespace uri == targetNamespace
624
// Construct ArrayOf<componentLocalPart>
625
// Else
626
// Construct ArrayOf_<componentPrefix>_<componentLocalPart>
627
QName JavaDoc cqName = getTypeQName(componentType);
628          if (targetNamespace.equals(cqName.getNamespaceURI()))
629          {
630             qName = new QName JavaDoc(targetNamespace,
631                     "ArrayOf" + cqName.getLocalPart());
632          }
633          else
634          {
635             String JavaDoc pre = namespaces.getCreatePrefix(cqName.getNamespaceURI());
636             qName = new QName JavaDoc(targetNamespace,
637                     "ArrayOf_" + pre + "_" + cqName.getLocalPart());
638          }
639          return qName;
640       }
641
642       // If a qName was not found construct one using the
643
// class name information.
644
if (qName == null)
645       {
646          String JavaDoc pkg = getPackageNameFromFullName(javaType.getName());
647          String JavaDoc lcl = getLocalNameFromFullName(javaType.getName());
648
649          String JavaDoc ns = namespaces.getCreate(pkg);
650          namespaces.getCreatePrefix(ns);
651          String JavaDoc localPart = lcl.replace('$', '_');
652          qName = new QName JavaDoc(ns, localPart);
653       }
654
655       return qName;
656    }
657
658    /**
659     * Return a string suitable for representing a given QName in the context
660     * of this WSDL document. If the namespace of the QName is not yet
661     * registered, we will register it up in the Definitions.
662     *
663     * @param qname a QName (typically a type)
664     * @return a String containing a standard "ns:localPart" rep of the QName
665     */

666    public String JavaDoc getQNameString(QName JavaDoc qname)
667    {
668       String JavaDoc prefix = namespaces.getCreatePrefix(qname.getNamespaceURI());
669       return prefix + ":" + qname.getLocalPart();
670    }
671
672    /**
673     * Utility method to get the package name from a fully qualified java class name
674     *
675     * @param full input class name
676     * @return package name
677     */

678    public static String JavaDoc getPackageNameFromFullName(String JavaDoc full)
679    {
680       if (full.lastIndexOf('.') < 0)
681          return "";
682       else
683          return full.substring(0, full.lastIndexOf('.'));
684    }
685
686    /**
687     * Utility method to get the local class name from a fully qualified java class name
688     *
689     * @param full input class name
690     * @return package name
691     */

692    public static String JavaDoc getLocalNameFromFullName(String JavaDoc full)
693    {
694       if (full.lastIndexOf('.') < 0)
695          return full;
696       else
697          return full.substring(full.lastIndexOf('.') + 1);
698    }
699
700    /**
701     * Write out the given Element into the appropriate schema node.
702     * If need be create the schema node as well
703     *
704     * @param qName qName to get the namespace of the schema node
705     * @param element the Element to append to the Schema node
706     */

707    public void writeSchemaElement(QName JavaDoc qName, Element JavaDoc element)
708            throws AxisFault
709    {
710       if (wsdlTypesElem == null)
711       {
712          try
713          {
714             writeWsdlTypesElement();
715          }
716          catch (Exception JavaDoc e)
717          {
718             log.error(e);
719             return;
720          }
721       }
722       String JavaDoc namespaceURI = qName.getNamespaceURI();
723       if (namespaceURI == null || namespaceURI.equals(""))
724       {
725          throw new AxisFault(Constants.FAULT_SERVER_GENERAL,
726                  Messages.getMessage("noNamespace00",
727                          qName.toString()),
728                  null, null);
729       }
730
731       Element JavaDoc schemaElem = null;
732       NodeList JavaDoc nl = wsdlTypesElem.getChildNodes();
733       for (int i = 0; i < nl.getLength(); i++)
734       {
735          NamedNodeMap JavaDoc attrs = nl.item(i).getAttributes();
736          if (attrs != null)
737          {
738             for (int n = 0; n < attrs.getLength(); n++)
739             {
740                Attr JavaDoc a = (Attr JavaDoc)attrs.item(n);
741                if (a.getName().equals("targetNamespace") &&
742                        a.getValue().equals(namespaceURI))
743                   schemaElem = (Element JavaDoc)nl.item(i);
744             }
745          }
746       }
747       if (schemaElem == null)
748       {
749          schemaElem = docHolder.createElement("schema");
750          wsdlTypesElem.appendChild(schemaElem);
751          schemaElem.setAttribute("xmlns", Constants.URI_DEFAULT_SCHEMA_XSD);
752          schemaElem.setAttribute("targetNamespace", namespaceURI);
753
754          // Add SOAP-ENC namespace import if necessary
755
if (serviceDesc.getStyle() == Style.RPC)
756          {
757             Element JavaDoc importElem = docHolder.createElement("import");
758             schemaElem.appendChild(importElem);
759             importElem.setAttribute("namespace", Constants.URI_DEFAULT_SOAP_ENC);
760          }
761
762          writeTypeNamespace(qName);
763       }
764       schemaElem.appendChild(element);
765    }
766
767    /**
768     * Get the Types element for the WSDL document. If not present, create one
769     */

770    private void writeWsdlTypesElement()
771    {
772       if (wsdlTypesElem == null)
773       {
774          // Create a <wsdl:types> element corresponding to the wsdl namespaces.
775
wsdlTypesElem =
776                  docHolder.createElementNS(Constants.NS_URI_WSDL11, "types");
777          wsdlTypesElem.setPrefix(Constants.NS_PREFIX_WSDL);
778       }
779    }
780
781    /**
782     * Write a schema representation for the given <code>Class</code>. Recurse
783     * through all the public fields as well as fields represented by java
784     * bean compliant accessor methods.
785     * <p/>
786     * Then return the qualified string representation of the generated type
787     *
788     * @param type Class for which to generate schema
789     * @return a prefixed string for the schema type
790     */

791    public String JavaDoc writeType(Class JavaDoc type) throws AxisFault
792    {
793       return writeType(type, null);
794    }
795
796    /**
797     * Write a schema representation for the given <code>Class</code>. Recurse
798     * through all the public fields as well as fields represented by java
799     * bean compliant accessor methods.
800     * <p/>
801     * Then return the qualified string representation of the generated type
802     *
803     * @param type Class for which to generate schema
804     * @param qName of the type to write
805     * @return a prefixed string for the schema type or null if problems occur
806     */

807    public String JavaDoc writeType(Class JavaDoc type, QName JavaDoc qName) throws AxisFault
808    {
809       // Get a corresponding QName if one is not provided
810
if (qName == null ||
811               Constants.equals(Constants.SOAP_ARRAY, qName))
812       {
813          qName = getTypeQName(type);
814       }
815
816       if (!makeTypeElement(type, qName, null))
817       {
818          return null;
819       }
820       return getQNameString(qName);
821    }
822
823    public Element JavaDoc createArrayElement(String JavaDoc componentTypeName)
824    {
825       // ComplexType representation of array
826
Element JavaDoc complexType = docHolder.createElement("complexType");
827
828       Element JavaDoc complexContent = docHolder.createElement("complexContent");
829       complexType.appendChild(complexContent);
830
831       Element JavaDoc restriction = docHolder.createElement("restriction");
832       complexContent.appendChild(restriction);
833       restriction.setAttribute("base",
834               Constants.NS_PREFIX_SOAP_ENC + ":Array");
835
836       Element JavaDoc attribute = docHolder.createElement("attribute");
837       restriction.appendChild(attribute);
838       attribute.setAttribute("ref",
839               Constants.NS_PREFIX_SOAP_ENC + ":arrayType");
840       attribute.setAttribute(Constants.NS_PREFIX_WSDL + ":arrayType",
841               componentTypeName);
842
843       return complexType;
844    }
845
846    /**
847     * Returns true if indicated type matches the JAX-RPC enumeration class.
848     * Note: supports JSR 101 version 0.6 Public Draft
849     */

850    public static boolean isEnumClass(Class JavaDoc cls)
851    {
852       try
853       {
854          java.lang.reflect.Method JavaDoc m = cls.getMethod("getValue", null);
855          java.lang.reflect.Method JavaDoc m2 = cls.getMethod("toString", null);
856          if (m != null && m2 != null)
857          {
858             java.lang.reflect.Method JavaDoc m3 =
859                     cls.getDeclaredMethod("fromString",
860                             new Class JavaDoc[]{java.lang.String JavaDoc.class});
861             java.lang.reflect.Method JavaDoc m4 =
862                     cls.getDeclaredMethod("fromValue",
863                             new Class JavaDoc[]{m.getReturnType()});
864
865             if (m3 != null &&
866                     Modifier.isStatic(m3.getModifiers()) &&
867                     Modifier.isPublic(m3.getModifiers()) &&
868                     m4 != null &&
869                     Modifier.isStatic(m4.getModifiers()) &&
870                     Modifier.isPublic(m4.getModifiers()))
871             {
872                // Return false if there is a setValue member method
873
try
874                {
875                   if (cls.getMethod("setValue",
876                           new Class JavaDoc[]{m.getReturnType()}) == null)
877                      return true;
878                   return false;
879                }
880                catch (java.lang.NoSuchMethodException JavaDoc e)
881                {
882                   return true;
883                }
884             }
885          }
886       }
887       catch (java.lang.NoSuchMethodException JavaDoc e)
888       {
889       }
890       return false;
891    }
892
893    /**
894     * Write Enumeration Complex Type
895     * (Only supports enumeration classes of string types)
896     *
897     * @param qName QName of type.
898     * @param cls class of type
899     */

900    public Element JavaDoc writeEnumType(QName JavaDoc qName, Class JavaDoc cls)
901            throws NoSuchMethodException JavaDoc, IllegalAccessException JavaDoc, AxisFault
902    {
903
904       if (!isEnumClass(cls))
905          return null;
906
907       // Get the base type of the enums class
908
java.lang.reflect.Method JavaDoc m = cls.getMethod("getValue", null);
909       Class JavaDoc base = m.getReturnType();
910
911       // Create simpleType, restriction elements
912
Element JavaDoc simpleType = docHolder.createElement("simpleType");
913       simpleType.setAttribute("name", qName.getLocalPart());
914       Element JavaDoc restriction = docHolder.createElement("restriction");
915       simpleType.appendChild(restriction);
916       String JavaDoc baseType = writeType(base, null);
917       restriction.setAttribute("base", baseType);
918
919       // Create an enumeration using the field values
920
Field JavaDoc[] fields = cls.getDeclaredFields();
921       for (int i = 0; i < fields.length; i++)
922       {
923          Field JavaDoc field = fields[i];
924          int mod = field.getModifiers();
925
926          // Inspect each public static final field of the same type
927
// as the base
928
if (Modifier.isPublic(mod) &&
929                  Modifier.isStatic(mod) &&
930                  Modifier.isFinal(mod) &&
931                  field.getType() == base)
932          {
933             // Create an enumeration using the value specified
934
Element JavaDoc enumeration = docHolder.createElement("enumeration");
935             enumeration.setAttribute("value", field.get(null).toString());
936             restriction.appendChild(enumeration);
937          }
938       }
939
940       return simpleType;
941    }
942
943    /**
944     * Create Element
945     *
946     * @param nillable nillable attribute of the element
947     * @return the created Element
948     */

949    public Element JavaDoc createElementDecl(String JavaDoc name,
950                                     Class JavaDoc javaType,
951                                     QName JavaDoc typeQName,
952                                     boolean nillable,
953                                     boolean omittable) throws AxisFault
954    {
955       Element JavaDoc element = docHolder.createElement("element");
956
957       // Generate an element name that matches the type.
958

959       element.setAttribute("name", name);
960
961       if (nillable)
962          element.setAttribute("nillable", "true");
963       if (omittable)
964       {
965          element.setAttribute("minOccurs", "0");
966          element.setAttribute("maxOccurs", "1");
967       }
968
969       // Write the type for this element, handling anonymous or named
970
// types appropriately.
971
makeTypeElement(javaType, typeQName, element);
972       return element;
973    }
974
975    /**
976     * Create Element with a given name and type
977     *
978     * @param elementName the name of the created element
979     * @param elementType schema type representation of the element
980     * @param nullable nullable attribute of the element
981     * @return the created Element
982     */

983    public Element JavaDoc createElement(String JavaDoc elementName,
984                                 String JavaDoc elementType,
985                                 boolean nullable,
986                                 boolean omittable,
987                                 Document JavaDoc docHolder)
988    {
989       Element JavaDoc element = docHolder.createElement("element");
990       element.setAttribute("name", elementName);
991       if (nullable)
992          element.setAttribute("nillable", "true");
993       if (omittable)
994       {
995          element.setAttribute("minOccurs", "0");
996          element.setAttribute("maxOccurs", "1");
997       }
998       if (elementType != null)
999          element.setAttribute("type", elementType);
1000      return element;
1001   }
1002
1003
1004   /**
1005    * Create Attribute Element with a given name and type
1006    *
1007    * @param elementName the name of the created element
1008    * @param nullable nullable attribute of the element
1009    * @return the created Element
1010    */

1011   public Element JavaDoc createAttributeElement(String JavaDoc elementName,
1012                                         Class JavaDoc javaType,
1013                                         QName JavaDoc xmlType,
1014                                         boolean nullable,
1015                                         Document JavaDoc docHolder) throws AxisFault
1016   {
1017      Element JavaDoc element = docHolder.createElement("attribute");
1018      element.setAttribute("name", elementName);
1019      if (nullable)
1020         element.setAttribute("nillable", "true");
1021
1022      makeTypeElement(javaType, xmlType, element);
1023      return element;
1024   }
1025
1026   /**
1027    * Is the given class one of the simple types? In other words,
1028    * do we have a mapping for this type which is in the xsd or
1029    * soap-enc namespaces?
1030    *
1031    * @param type input Class
1032    * @return true if the type is a simple type
1033    */

1034   boolean isSimpleType(Class JavaDoc type)
1035   {
1036      QName JavaDoc qname = tm.getTypeQName(type);
1037      if (qname == null)
1038         return false; // No mapping
1039

1040      String JavaDoc nsURI = qname.getNamespaceURI();
1041      return (Constants.isSchemaXSD(nsURI) ||
1042              Constants.isSOAP_ENC(nsURI));
1043   }
1044
1045   /**
1046    * Is the given class acceptable as an attribute
1047    *
1048    * @param type input Class
1049    * @return true if the type is a simple, enums type or extends SimpleType
1050    */

1051   public boolean isAcceptableAsAttribute(Class JavaDoc type)
1052   {
1053      return isSimpleType(type) ||
1054              isEnumClass(type) ||
1055              implementsSimpleType(type);
1056   }
1057
1058   /**
1059    * Does the class implement SimpleType
1060    *
1061    * @param type input Class
1062    * @return true if the type implements SimpleType
1063    */

1064   boolean implementsSimpleType(Class JavaDoc type)
1065   {
1066      Class JavaDoc[] impls = type.getInterfaces();
1067      for (int i = 0; i < impls.length; i++)
1068      {
1069         if (impls[i] == SimpleType.class)
1070         {
1071            return true;
1072         }
1073      }
1074      return false;
1075   }
1076   /**
1077    * Generates a unique element name for a given namespace of the form
1078    * el0, el1 ....
1079    *
1080    * @param qName the namespace for the generated element
1081    * @return elementname
1082    */

1083// *** NOT USED? ***
1084
//
1085
// private String generateUniqueElementName(QName qName) {
1086
// Integer count = (Integer)schemaUniqueElementNames.get(qName.getNamespaceURI());
1087
// if (count == null)
1088
// count = new Integer(0);
1089
// else
1090
// count = new Integer(count.intValue() + 1);
1091
// schemaUniqueElementNames.put(qName.getNamespaceURI(), count);
1092
// return "el" + count.intValue();
1093
// }
1094

1095   /**
1096    * Add the type to an ArrayList and return true if the Schema node
1097    * needs to be generated
1098    * If the type already exists, just return false to indicate that the type is already
1099    * generated in a previous iteration
1100    *
1101    * @param qName of the type.
1102    * @return if the type is added returns true,
1103    * else if the type is already present returns false
1104    */

1105   private boolean addToTypesList(QName JavaDoc qName)
1106   {
1107      boolean added = false;
1108      ArrayList JavaDoc types = (ArrayList JavaDoc)schemaTypes.get(qName.getNamespaceURI());
1109
1110      // Quick return if schema type (will never add these ourselves)
1111
if (Constants.isSchemaXSD(qName.getNamespaceURI()) ||
1112              (Constants.isSOAP_ENC(qName.getNamespaceURI()) &&
1113              !"Array".equals(qName.getLocalPart())))
1114      {
1115         // Make sure we do have the namespace declared, though...
1116
writeTypeNamespace(qName);
1117         return false;
1118      }
1119
1120      if (types == null)
1121      {
1122         types = new ArrayList JavaDoc();
1123         types.add(qName.getLocalPart());
1124         schemaTypes.put(qName.getNamespaceURI(), types);
1125         added = true;
1126      }
1127      else
1128      {
1129         if (!types.contains(qName.getLocalPart()))
1130         {
1131            types.add(qName.getLocalPart());
1132            added = true;
1133         }
1134      }
1135
1136      // If addded, look at the namespace uri to see if the schema element should be
1137
// generated.
1138
if (added)
1139      {
1140         String JavaDoc prefix = namespaces.getCreatePrefix(qName.getNamespaceURI());
1141         if (prefix.equals(Constants.NS_PREFIX_SOAP_ENV) ||
1142                 prefix.equals(Constants.NS_PREFIX_SOAP_ENC) ||
1143                 prefix.equals(Constants.NS_PREFIX_SCHEMA_XSD) ||
1144                 prefix.equals(Constants.NS_PREFIX_WSDL) ||
1145                 prefix.equals(Constants.NS_PREFIX_WSDL_SOAP))
1146            return false;
1147         else
1148            return true;
1149      }
1150      return false;
1151   }
1152
1153   /**
1154    * Add the element to an ArrayList and return true if the Schema element
1155    * needs to be generated
1156    * If the element already exists, just return false to indicate that the type is already
1157    * generated in a previous iteration
1158    *
1159    * @param qName the name space of the element
1160    * @return if the type is added returns true, else if the type is already present returns false
1161    */

1162   private boolean addToElementsList(QName JavaDoc qName)
1163   {
1164      if (qName == null)
1165      {
1166         return false;
1167      }
1168
1169      boolean added = false;
1170      ArrayList JavaDoc elements = (ArrayList JavaDoc)schemaElementNames.get(qName.getNamespaceURI());
1171      if (elements == null)
1172      {
1173         elements = new ArrayList JavaDoc();
1174         elements.add(qName.getLocalPart());
1175         schemaElementNames.put(qName.getNamespaceURI(), elements);
1176         added = true;
1177      }
1178      else
1179      {
1180         if (!elements.contains(qName.getLocalPart()))
1181         {
1182            elements.add(qName.getLocalPart());
1183            added = true;
1184         }
1185      }
1186      return added;
1187   }
1188
1189
1190   /**
1191    * Determines if the field is nullable. All non-primitives except
1192    * for byte[] are nillable.
1193    *
1194    * @param type input Class
1195    * @return true if nullable
1196    */

1197   public boolean isNullable(Class JavaDoc type)
1198   {
1199      if (type.isPrimitive() ||
1200              (type.isArray() && type.getComponentType() == byte.class))
1201         return false;
1202      else
1203         return true;
1204   }
1205
1206
1207   /**
1208    * todo ravi: Get rid of Doccument fragment and import node stuuf,
1209    * once I have a handle on the wsdl4j mechanism to get at types.
1210    * <p/>
1211    * Switch over notes: remove docHolder, docFragment in favor of wsdl4j Types
1212    */

1213   //DocumentFragment docFragment;
1214
Document JavaDoc docHolder;
1215
1216   private void createDocumentFragment()
1217   {
1218      try
1219      {
1220         this.docHolder = XMLUtils.newDocument();
1221      }
1222      catch (ParserConfigurationException JavaDoc e)
1223      {
1224         // This should not occur
1225
throw new InternalException(e);
1226      }
1227   }
1228
1229   public void updateNamespaces()
1230   {
1231      Namespaces namespaces = getNamespaces();
1232      Iterator JavaDoc nspIterator = namespaces.getNamespaces();
1233      while (nspIterator.hasNext())
1234      {
1235         String JavaDoc nsp = (String JavaDoc)nspIterator.next();
1236         String JavaDoc pref = def.getPrefix(nsp);
1237         if (pref == null)
1238         {
1239            def.addNamespace(namespaces.getCreatePrefix(nsp), nsp);
1240         }
1241      }
1242   }
1243
1244   /**
1245    * Inserts the type fragment into the given wsdl document
1246    *
1247    * @param doc
1248    */

1249   public void insertTypesFragment(Document JavaDoc doc)
1250   {
1251      updateNamespaces();
1252      if (wsdlTypesElem != null)
1253      {
1254         // Import the wsdlTypesElement into the doc.
1255
org.w3c.dom.Node JavaDoc node = doc.importNode(wsdlTypesElem, true);
1256         // Insert the imported element at the beginning of the document
1257
doc.getDocumentElement().
1258                 insertBefore(node,
1259                         doc.getDocumentElement().getFirstChild());
1260      }
1261   }
1262
1263   /**
1264    * Return the list of classes that we should not emit WSDL for.
1265    */

1266   public List JavaDoc getStopClasses()
1267   {
1268      return stopClasses;
1269   }
1270
1271   /**
1272    * Create a DOM Element in this context
1273    */

1274   public Element JavaDoc createElement(String JavaDoc elementName)
1275   {
1276      return docHolder.createElement(elementName);
1277   }
1278
1279   /**
1280    * Write an &lt;element&gt; with an anonymous internal ComplexType
1281    *
1282    * @param elementName
1283    * @param fieldType
1284    * @param omittable
1285    * @param ownerDocument
1286    */

1287   public Element JavaDoc createElementWithAnonymousType(String JavaDoc elementName,
1288                                                 Class JavaDoc fieldType,
1289                                                 boolean omittable,
1290                                                 Document JavaDoc ownerDocument) throws AxisFault
1291   {
1292      Element JavaDoc element = docHolder.createElement("element");
1293      element.setAttribute("name", elementName);
1294      if (isNullable(fieldType))
1295         element.setAttribute("nillable", "true");
1296      if (omittable)
1297      {
1298         element.setAttribute("minOccurs", "0");
1299         element.setAttribute("maxOccurs", "1");
1300      }
1301
1302      makeTypeElement(fieldType, null, element);
1303
1304      return element;
1305   }
1306
1307   /**
1308    * Create a schema type element (either simpleType or complexType) for
1309    * the particular type/qName combination. If the type is named, we
1310    * handle inserting the new type into the appropriate &lt;schema&gt;
1311    * in the WSDL types section. If the type is anonymous, we append the
1312    * definition underneath the Element which was passed as the container
1313    * (typically a field of a higher-level type or a parameter in a wrapped
1314    * operation).
1315    *
1316    * @param type Java type to write
1317    * @param qName the desired type QName
1318    * @param containingElement a schema element ("element" or "attribute")
1319    * which should either receive a type="" attribute decoration
1320    * (for named types) or a child element defining an anonymous
1321    * type
1322    * @return true if the type was already present or was added, false if there was a problem
1323    * @throws AxisFault
1324    */

1325   private boolean makeTypeElement(Class JavaDoc type,
1326                                   QName JavaDoc qName,
1327                                   Element JavaDoc containingElement) throws AxisFault
1328   {
1329      // Get a corresponding QName if one is not provided
1330
if (qName == null ||
1331              Constants.equals(Constants.SOAP_ARRAY, qName))
1332      {
1333         qName = getTypeQName(type);
1334      }
1335
1336      boolean anonymous = isAnonymousType(qName);
1337
1338      // Can't have an anonymous type outside of a containing element
1339
if (anonymous && containingElement == null)
1340      {
1341         throw new AxisFault(Messages.getMessage("noContainerForAnonymousType",
1342                 qName.toString()));
1343      }
1344
1345      // If we've already got this type (because it's a native type or
1346
// because we've already written it), just add the type="" attribute
1347
// (if appropriate) and return.
1348
if (!addToTypesList(qName))
1349      {
1350         if (containingElement != null)
1351            containingElement.setAttribute("type", getQNameString(qName));
1352         return true;
1353      }
1354
1355      // look up the serializer in the TypeMappingRegistry
1356
Serializer ser = null;
1357      SerializerFactory factory = null;
1358      if (tm != null)
1359      {
1360         factory = (SerializerFactory)tm.getSerializer(type);
1361      }
1362      else
1363      {
1364         factory = (SerializerFactory)defaultTM.getSerializer(type);
1365      }
1366
1367      // If no factory is found, use the BeanSerializerFactory
1368
// if applicable, otherwise issue errors and treat as an anyType
1369
if (factory == null)
1370      {
1371         if (isEnumClass(type))
1372         {
1373            factory = new EnumSerializerFactory(type, qName);
1374         }
1375         else if (JavaUtils.isBeanCompatible(type))
1376         {
1377            factory = new BeanSerializerFactory(type, qName);
1378         }
1379         else
1380         {
1381            return false;
1382         }
1383      }
1384
1385      if (factory != null)
1386      {
1387         ser = (Serializer)factory.getSerializerAs(Constants.AXIS_SAX);
1388      }
1389
1390      // if we can't get a serializer, that is bad.
1391
if (ser == null)
1392      {
1393         throw new AxisFault(Messages.getMessage("NoSerializer00", type.getName()));
1394      }
1395
1396      Element JavaDoc typeEl;
1397      try
1398      {
1399         typeEl = ser.writeSchema(type, this);
1400      }
1401      catch (Exception JavaDoc e)
1402      {
1403         throw AxisFault.makeFault(e);
1404      }
1405
1406      // If this is an anonymous type, just make the type element a child
1407
// of containingElement. If not, set the "type" attribute of
1408
// containingElement to the right QName, and make sure the type is
1409
// correctly written into the appropriate <schema> element.
1410
if (anonymous)
1411      {
1412         containingElement.appendChild(typeEl);
1413      }
1414      else
1415      {
1416         if (typeEl != null)
1417         {
1418            typeEl.setAttribute("name", qName.getLocalPart());
1419
1420            // Write the type in the appropriate <schema>
1421
writeSchemaElement(qName, typeEl);
1422         }
1423
1424         if (containingElement != null)
1425            containingElement.setAttribute("type", getQNameString(qName));
1426      }
1427      return true;
1428   }
1429}
1430
Popular Tags