Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/axis/wsdl/symbolTable/SymbolTable.java


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  package org.apache.axis.wsdl.symbolTable;
17  
18  import org.apache.axis.Constants;
19  import org.apache.axis.constants.Style;
20  import org.apache.axis.constants.Use;
21  import org.apache.axis.utils.Messages;
22  import org.apache.axis.utils.URLHashSet;
23  import org.apache.axis.utils.XMLUtils;
24  import org.w3c.dom.Document;
25  import org.w3c.dom.NamedNodeMap;
26  import org.w3c.dom.Node;
27  import org.w3c.dom.NodeList;
28  import org.xml.sax.SAXException;
29  
30  import javax.wsdl.Binding;
31  import javax.wsdl.BindingFault;
32  import javax.wsdl.BindingInput;
33  import javax.wsdl.BindingOperation;
34  import javax.wsdl.BindingOutput;
35  import javax.wsdl.Definition;
36  import javax.wsdl.Fault;
37  import javax.wsdl.Import;
38  import javax.wsdl.Input;
39  import javax.wsdl.Message;
40  import javax.wsdl.Operation;
41  import javax.wsdl.Output;
42  import javax.wsdl.Part;
43  import javax.wsdl.Port;
44  import javax.wsdl.PortType;
45  import javax.wsdl.Service;
46  import javax.wsdl.WSDLException;
47  import javax.wsdl.extensions.ExtensibilityElement;
48  import javax.wsdl.extensions.UnknownExtensibilityElement;
49  import javax.wsdl.extensions.http.HTTPBinding;
50  import javax.wsdl.extensions.mime.MIMEContent;
51  import javax.wsdl.extensions.mime.MIMEMultipartRelated;
52  import javax.wsdl.extensions.mime.MIMEPart;
53  import javax.wsdl.extensions.soap.SOAPBinding;
54  import javax.wsdl.extensions.soap.SOAPBody;
55  import javax.wsdl.extensions.soap.SOAPFault;
56  import javax.wsdl.extensions.soap.SOAPHeader;
57  import javax.wsdl.extensions.soap.SOAPHeaderFault;
58  import javax.wsdl.factory.WSDLFactory;
59  import javax.wsdl.xml.WSDLReader;
60  import javax.xml.namespace.QName;
61  import javax.xml.parsers.ParserConfigurationException;
62  import javax.xml.rpc.holders.BooleanHolder;
63  import javax.xml.rpc.holders.IntHolder;
64  import javax.xml.rpc.holders.QNameHolder;
65  import java.io.File;
66  import java.io.IOException;
67  import java.net.MalformedURLException;
68  import java.net.URL;
69  import java.util.ArrayList;
70  import java.util.Collection;
71  import java.util.Collections;
72  import java.util.HashMap;
73  import java.util.HashSet;
74  import java.util.Iterator;
75  import java.util.List;
76  import java.util.Map;
77  import java.util.Set;
78  import java.util.Vector;
79  
80  /**
81   * This class represents a table of all of the top-level symbols from a set of WSDL Definitions and
82   * DOM Documents:  XML types; WSDL messages, portTypes, bindings, and services.
83   * <p/>
84   * This symbolTable contains entries of the form <key, value> where key is of type QName and value is
85   * of type Vector.  The Vector's elements are all of the objects that have the given QName.  This is
86   * necessary since names aren't unique among the WSDL types.  message, portType, binding, service,
87   * could all have the same QName and are differentiated merely by type.  SymbolTable contains
88   * type-specific getters to bypass the Vector layer:
89   * public PortTypeEntry getPortTypeEntry(QName name), etc.
90   */
91  public class SymbolTable {
92  
93      // used to cache dervied types
94      protected HashMap derivedTypes = new HashMap();
95  
96      // Should the contents of imported files be added to the symbol table?
97  
98      /** Field addImports */
99      private boolean addImports;
100 
101     // The actual symbol table.  This symbolTable contains entries of the form
102     // <key, value> where key is of type QName and value is of type Vector.  The
103     // Vector's elements are all of the objects that have the given QName.  This
104     // is necessary since names aren't unique among the WSDL types.  message,
105     // portType, binding, service, could all have the same QName and are
106     // differentiated merely by type.  SymbolTable contains type-specific
107     // getters to bypass the Vector layer:
108     // public PortTypeEntry getPortTypeEntry(QName name), etc.
109 
110     /** Field symbolTable */
111     private HashMap symbolTable = new HashMap();
112 
113     // a map of qnames -> Elements in the symbol table
114 
115     /** Field elementTypeEntries */
116     private final Map elementTypeEntries = new HashMap();
117 
118     // an unmodifiable wrapper so that we can share the index with others, safely
119 
120     /** Field elementIndex */
121     private final Map elementIndex =
122             Collections.unmodifiableMap(elementTypeEntries);
123 
124     // a map of qnames -> Types in the symbol table
125 
126     /** Field typeTypeEntries */
127     private final Map typeTypeEntries = new HashMap();
128 
129     // an unmodifiable wrapper so that we can share the index with others, safely
130 
131     /** Field typeIndex */
132     private final Map typeIndex = Collections.unmodifiableMap(typeTypeEntries);
133 
134     /**
135      * cache of nodes -> base types for complexTypes.  The cache is
136      * built on nodes because multiple TypeEntry objects may use the
137      * same node.
138      */
139     protected final Map node2ExtensionBase =
140             new HashMap();    // allow friendly access
141 
142     /** Field verbose */
143     private boolean verbose;
144 
145     /** Field quiet */
146     protected boolean quiet;
147 
148     /** Field btm */
149     private BaseTypeMapping btm = null;
150 
151     // should we attempt to treat document/literal WSDL as "rpc-style"
152 
153     /** Field nowrap */
154     private boolean nowrap;
155 
156     // Did we encounter wraped mode WSDL
157 
158     /** Field wrapped */
159     private boolean wrapped = false;
160 
161     /** Field ANON_TOKEN */
162     public static final String ANON_TOKEN = ">";
163 
164     /** Field def */
165     private Definition def = null;
166 
167     /** Field wsdlURI */
168     private String wsdlURI = null;
169 
170     /** If this is false, we will "unwrap" literal arrays, generating a plan "String[]" instead
171      * of "ArrayOfString" when encountering an element containing a single maxOccurs="unbounded"
172      * inner element.
173      */
174     private boolean wrapArrays;
175 
176     Set arrayTypeQNames = new HashSet();
177 
178     /** Field elementFormDefaults */
179     private final Map elementFormDefaults = new HashMap();
180     /**
181      * Construct a symbol table with the given Namespaces.
182      * 
183      * @param btm        
184      * @param addImports 
185      * @param verbose    
186      * @param nowrap     
187      */
188     public SymbolTable(BaseTypeMapping btm, boolean addImports,
189                        boolean verbose, boolean nowrap) {
190 
191         this.btm = btm;
192         this.addImports = addImports;
193         this.verbose = verbose;
194         this.nowrap = nowrap;
195     }    // ctor
196 
197     /**
198      * Method isQuiet
199      * 
200      * @return 
201      */
202     public boolean isQuiet() {
203         return quiet;
204     }    
205 
206     /**
207      * Method setQuiet
208      * 
209      * @param quiet
210      */
211     public void setQuiet(boolean quiet) {
212         this.quiet = quiet;
213     }   
214 
215     /**
216      * Get the raw symbol table HashMap.
217      * 
218      * @return 
219      */
220     public HashMap getHashMap() {
221         return symbolTable;
222     }    // getHashMap
223 
224     /**
225      * Get the list of entries with the given QName.  Since symbols can share QNames, this list is
226      * necessary.  This list will not contain any more than one element of any given SymTabEntry.
227      * 
228      * @param qname 
229      * @return 
230      */
231     public Vector getSymbols(QName qname) {
232         return (Vector) symbolTable.get(qname);
233     }    // get
234 
235     /**
236      * Get the entry with the given QName of the given class.  If it does not exist, return null.
237      * 
238      * @param qname 
239      * @param cls   
240      * @return 
241      */
242     public SymTabEntry get(QName qname, Class cls) {
243 
244         Vector v = (Vector) symbolTable.get(qname);
245 
246         if (v == null) {
247             return null;
248         } else {
249             for (int i = 0; i < v.size(); ++i) {
250                 SymTabEntry entry = (SymTabEntry) v.elementAt(i);
251 
252                 if (cls.isInstance(entry)) {
253                     return entry;
254                 }
255             }
256 
257             return null;
258         }
259     }    // get
260 
261     /**
262      * Get the type entry for the given qname.
263      * 
264      * @param qname           
265      * @param wantElementType boolean that indicates type or element (for type= or ref=)
266      * @return 
267      */
268     public TypeEntry getTypeEntry(QName qname, boolean wantElementType) {
269 
270         if (wantElementType) {
271             return getElement(qname);
272         } else {
273             return getType(qname);
274         }
275     }    // getTypeEntry
276 
277     /**
278      * Get the Type TypeEntry with the given QName.  If it doesn't
279      * exist, return null.
280      * 
281      * @param qname 
282      * @return 
283      */
284     public Type getType(QName qname) {
285         return (Type) typeTypeEntries.get(qname);
286     }    // getType
287 
288     /**
289      * Get the Element TypeEntry with the given QName.  If it doesn't
290      * exist, return null.
291      * 
292      * @param qname 
293      * @return 
294      */
295     public Element getElement(QName qname) {
296         return (Element) elementTypeEntries.get(qname);
297     }    // getElement
298 
299     /**
300      * Get the MessageEntry with the given QName.  If it doesn't exist, return null.
301      * 
302      * @param qname 
303      * @return 
304      */
305     public MessageEntry getMessageEntry(QName qname) {
306         return (MessageEntry) get(qname, MessageEntry.class);
307     }    // getMessageEntry
308 
309     /**
310      * Get the PortTypeEntry with the given QName.  If it doesn't exist, return null.
311      * 
312      * @param qname 
313      * @return 
314      */
315     public PortTypeEntry getPortTypeEntry(QName qname) {
316         return (PortTypeEntry) get(qname, PortTypeEntry.class);
317     }    // getPortTypeEntry
318 
319     /**
320      * Get the BindingEntry with the given QName.  If it doesn't exist, return null.
321      * 
322      * @param qname 
323      * @return 
324      */
325     public BindingEntry getBindingEntry(QName qname) {
326         return (BindingEntry) get(qname, BindingEntry.class);
327     }    // getBindingEntry
328 
329     /**
330      * Get the ServiceEntry with the given QName.  If it doesn't exist, return null.
331      * 
332      * @param qname 
333      * @return 
334      */
335     public ServiceEntry getServiceEntry(QName qname) {
336         return (ServiceEntry) get(qname, ServiceEntry.class);
337     }    // getServiceEntry
338 
339     /**
340      * Get the list of all the XML schema types in the symbol table.  In other words, all entries
341      * that are instances of TypeEntry.
342      * 
343      * @return 
344      * @deprecated use specialized get{Element,Type}Index() methods instead
345      */
346     public Vector getTypes() {
347 
348         Vector v = new Vector();
349 
350         v.addAll(elementTypeEntries.values());
351         v.addAll(typeTypeEntries.values());
352 
353         return v;
354     }    // getTypes
355 
356     /**
357      * Return an unmodifiable map of qnames -> Elements in the symbol
358      * table.
359      * 
360      * @return an unmodifiable <code>Map</code> value
361      */
362     public Map getElementIndex() {
363         return elementIndex;
364     }
365 
366     /**
367      * Return an unmodifiable map of qnames -> Elements in the symbol
368      * table.
369      * 
370      * @return an unmodifiable <code>Map</code> value
371      */
372     public Map getTypeIndex() {
373         return typeIndex;
374     }
375 
376     /**
377      * Return the count of TypeEntries in the symbol table.
378      * 
379      * @return an <code>int</code> value
380      */
381     public int getTypeEntryCount() {
382         return elementTypeEntries.size() + typeTypeEntries.size();
383     }
384 
385     /**
386      * Get the Definition.  The definition is null until
387      * populate is called.
388      * 
389      * @return 
390      */
391     public Definition getDefinition() {
392         return def;
393     }    // getDefinition
394 
395     /**
396      * Get the WSDL URI.  The WSDL URI is null until populate
397      * is called, and ONLY if a WSDL URI is provided.
398      * 
399      * @return 
400      */
401     public String getWSDLURI() {
402         return wsdlURI;
403     }    // getWSDLURI
404 
405     /**
406      * Are we wrapping literal soap body elements.
407      * 
408      * @return 
409      */
410     public boolean isWrapped() {
411         return wrapped;
412     }
413 
414     /**
415      * Turn on/off element wrapping for literal soap body's.
416      * 
417      * @param wrapped 
418      */
419     public void setWrapped(boolean wrapped) {
420         this.wrapped = wrapped;
421     }
422 
423     /**
424      * Dump the contents of the symbol table.  For debugging purposes only.
425      * 
426      * @param out 
427      */
428     public void dump(java.io.PrintStream out) {
429 
430         out.println();
431         out.println(Messages.getMessage("symbolTable00"));
432         out.println("-----------------------");
433 
434         Iterator it = symbolTable.values().iterator();
435 
436         while (it.hasNext()) {
437             Vector v = (Vector) it.next();
438 
439             for (int i = 0; i < v.size(); ++i) {
440                 out.println(v.elementAt(i).getClass().getName());
441                 out.println(v.elementAt(i));
442             }
443         }
444 
445         out.println("-----------------------");
446     }    // dump
447 
448     /**
449      * Call this method if you have a uri for the WSDL document
450      * 
451      * @param uri wsdlURI the location of the WSDL file.
452      * @throws IOException                  
453      * @throws WSDLException                
454      * @throws SAXException                 
455      * @throws ParserConfigurationException 
456      */
457     public void populate(String uri)
458             throws IOException, WSDLException, SAXException,
459             ParserConfigurationException {
460         populate(uri, null, null);
461     }    // populate
462 
463     /**
464      * Method populate
465      * 
466      * @param uri      
467      * @param username 
468      * @param password 
469      * @throws IOException                  
470      * @throws WSDLException                
471      * @throws SAXException                 
472      * @throws ParserConfigurationException 
473      */
474     public void populate(String uri, String username, String password)
475             throws IOException, WSDLException, SAXException,
476             ParserConfigurationException {
477 
478         if (verbose) {
479             System.out.println(Messages.getMessage("parsing00", uri));
480         }
481 
482         Document doc = XMLUtils.newDocument(uri, username, password);
483 
484         this.wsdlURI = uri;
485 
486         try {
487             File f = new File(uri);
488 
489             if (f.exists()) {
490                 uri = f.toURL().toString();
491             }
492         } catch (Exception e) {
493         }
494 
495         populate(uri, doc);
496     }    // populate
497 
498     /**
499      * Call this method if your WSDL document has already been parsed as an XML DOM document.
500      * 
501      * @param context context This is directory context for the Document.  If the Document were from file "/x/y/z.wsdl" then the context could be "/x/y" (even "/x/y/z.wsdl" would work).  If context is null, then the context becomes the current directory.
502      * @param doc     doc This is the XML Document containing the WSDL.
503      * @throws IOException                  
504      * @throws SAXException                 
505      * @throws WSDLException                
506      * @throws ParserConfigurationException 
507      */
508     public void populate(String context, Document doc)
509             throws IOException, SAXException, WSDLException,
510             ParserConfigurationException {
511 
512         WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
513 
514         reader.setFeature("javax.wsdl.verbose", verbose);
515 
516         this.def = reader.readWSDL(context, doc);
517 
518         add(context, def, doc);
519     }    // populate
520 
521     /**
522      * Add the given Definition and Document information to the symbol table (including imported
523      * symbols), populating it with SymTabEntries for each of the top-level symbols.  When the
524      * symbol table has been populated, iterate through it, setting the isReferenced flag
525      * appropriately for each entry.
526      * 
527      * @param context 
528      * @param def     
529      * @param doc     
530      * @throws IOException                  
531      * @throws SAXException                 
532      * @throws WSDLException                
533      * @throws ParserConfigurationException 
534      */
535     protected void add(String context, Definition def, Document doc)
536             throws IOException, SAXException, WSDLException,
537             ParserConfigurationException {
538 
539         URL contextURL = (context == null)
540                 ? null
541                 : getURL(null, context);
542 
543         populate(contextURL, def, doc, null);
544         processTypes();
545         checkForUndefined();
546         populateParameters();
547         setReferences(def, doc);    // uses wrapped flag set in populateParameters
548     }    // add
549 
550     /**
551      * Scan the Definition for undefined objects and throw an error.
552      * 
553      * @param def      
554      * @param filename 
555      * @throws IOException 
556      */
557     private void checkForUndefined(Definition def, String filename)
558             throws IOException {
559 
560         if (def != null) {
561 
562             // Bindings
563             Iterator ib = def.getBindings().values().iterator();
564 
565             while (ib.hasNext()) {
566                 Binding binding = (Binding) ib.next();
567 
568                 if (binding.isUndefined()) {
569                     if (filename == null) {
570                         throw new IOException(
571                                 Messages.getMessage(
572                                         "emitFailtUndefinedBinding01",
573                                         binding.getQName().getLocalPart()));
574                     } else {
575                         throw new IOException(
576                                 Messages.getMessage(
577                                         "emitFailtUndefinedBinding02",
578                                         binding.getQName().getLocalPart(), filename));
579                     }
580                 }
581             }
582 
583             // portTypes
584             Iterator ip = def.getPortTypes().values().iterator();
585 
586             while (ip.hasNext()) {
587                 PortType portType = (PortType) ip.next();
588 
589                 if (portType.isUndefined()) {
590                     if (filename == null) {
591                         throw new IOException(
592                                 Messages.getMessage(
593                                         "emitFailtUndefinedPort01",
594                                         portType.getQName().getLocalPart()));
595                     } else {
596                         throw new IOException(
597                                 Messages.getMessage(
598                                         "emitFailtUndefinedPort02",
599                                         portType.getQName().getLocalPart(), filename));
600                     }
601                 }
602             }
603 
604             /*
605              * tomj: This is a bad idea, faults seem to be undefined
606              * / RJB reply:  this MUST be done for those systems that do something with
607              * / messages.  Perhaps we have to do an extra step for faults?  I'll leave
608              * / this commented for now, until someone uses this generator for something
609              * / other than WSDL2Java.
610              *           // Messages
611              *           Iterator i = def.getMessages().values().iterator();
612              *           while (i.hasNext()) {
613              *               Message message = (Message) i.next();
614              *               if (message.isUndefined()) {
615              *                   throw new IOException(
616              *                           Messages.getMessage("emitFailtUndefinedMessage01",
617              *                                   message.getQName().getLocalPart()));
618              *               }
619              *           }
620              */
621         }
622     }
623 
624     /**
625      * Scan the symbol table for undefined types and throw an exception.
626      * 
627      * @throws IOException 
628      */
629     private void checkForUndefined() throws IOException {
630 
631         Iterator it = symbolTable.values().iterator();
632 
633         while (it.hasNext()) {
634             Vector v = (Vector) it.next();
635 
636             for (int i = 0; i < v.size(); ++i) {
637                 SymTabEntry entry = (SymTabEntry) v.get(i);
638 
639                 // Report undefined types
640                 if (entry instanceof UndefinedType) {
641                     QName qn = entry.getQName();
642 
643                     // Special case dateTime/timeInstant that changed
644                     // from version to version.
645                     if ((qn.getLocalPart().equals(
646                             "dateTime") && !qn.getNamespaceURI().equals(
647                                     Constants.URI_2001_SCHEMA_XSD)) || (qn.getLocalPart().equals(
648                                             "timeInstant") && qn.getNamespaceURI().equals(
649                                                     Constants.URI_2001_SCHEMA_XSD))) {
650                         throw new IOException(
651                                 Messages.getMessage(
652                                         "wrongNamespace00", qn.getLocalPart(),
653                                         qn.getNamespaceURI()));
654                     }
655 
656                     // Check for a undefined XSD Schema Type and throw
657                     // an unsupported message instead of undefined
658                     if (SchemaUtils.isSimpleSchemaType(qn)) {
659                         throw new IOException(
660                                 Messages.getMessage(
661                                         "unsupportedSchemaType00", qn.getLocalPart()));
662                     }
663 
664                     // last case, its some other undefined thing
665                     throw new IOException(
666                             Messages.getMessage(
667                                     "undefined00", qn.toString()));
668                 }    // if undefined
669                 else if (entry instanceof UndefinedElement) {
670                     throw new IOException(
671                             Messages.getMessage(
672                                     "undefinedElem00", entry.getQName().toString()));
673                 }
674             }
675         }
676     }                // checkForUndefined
677 
678     /**
679      * Add the given Definition and Document information to the symbol table (including imported
680      * symbols), populating it with SymTabEntries for each of the top-level symbols.
681      * NOTE:  filename is used only by checkForUndefined so that it can report which WSDL file
682      * has the problem.  If we're on the primary WSDL file, then we don't know the name and
683      * filename will be null.  But we know the names of all imported files.
684      */
685     private URLHashSet importedFiles = new URLHashSet();
686 
687     /**
688      * Method populate
689      * 
690      * @param context  
691      * @param def      
692      * @param doc      
693      * @param filename 
694      * @throws IOException                  
695      * @throws ParserConfigurationException 
696      * @throws SAXException                 
697      * @throws WSDLException                
698      */
699     private void populate(
700             URL context, Definition def, Document doc, String filename)
701             throws IOException, ParserConfigurationException, SAXException,
702             WSDLException {
703 
704         if (doc != null) {
705             populateTypes(context, doc);
706 
707             if (addImports) {
708 
709                 // Add the symbols from any xsd:import'ed documents.
710                 lookForImports(context, doc);
711             }
712         }
713 
714         if (def != null) {
715             checkForUndefined(def, filename);
716 
717             if (addImports) {
718 
719                 // Add the symbols from the wsdl:import'ed WSDL documents
720                 Map imports = def.getImports();
721                 Object[] importKeys = imports.keySet().toArray();
722 
723                 for (int i = 0; i < importKeys.length; ++i) {
724                     Vector v = (Vector) imports.get(importKeys[i]);
725 
726                     for (int j = 0; j < v.size(); ++j) {
727                         Import imp = (Import) v.get(j);
728 
729                         if (!importedFiles.contains(imp.getLocationURI())) {
730                             importedFiles.add(imp.getLocationURI());
731 
732                             URL url = getURL(context, imp.getLocationURI());
733 
734                             populate(url, imp.getDefinition(),
735                                     XMLUtils.newDocument(url.toString()),
736                                     url.toString());
737                         }
738                     }
739                 }
740             }
741 
742             populateMessages(def);
743             populatePortTypes(def);
744             populateBindings(def);
745             populateServices(def);
746         }
747     }    // populate
748 
749     /**
750      * This is essentially a call to "new URL(contextURL, spec)" with extra handling in case spec is
751      * a file.
752      * 
753      * @param contextURL 
754      * @param spec       
755      * @return 
756      * @throws IOException 
757      */
758     private static URL getURL(URL contextURL, String spec) throws IOException {
759 
760         // First, fix the slashes as windows filenames may have backslashes
761         // in them, but the URL class wont do the right thing when we later
762         // process this URL as the contextURL.
763         String path = spec.replace('\\', '/');
764 
765         // See if we have a good URL.
766         URL url = null;
767 
768         try {
769 
770             // first, try to treat spec as a full URL
771             url = new URL(contextURL, path);
772 
773             // if we are deail with files in both cases, create a url
774             // by using the directory of the context URL.
775             if ((contextURL != null) && url.getProtocol().equals("file")
776                     && contextURL.getProtocol().equals("file")) {
777                 url = getFileURL(contextURL, path);
778             }
779         } catch (MalformedURLException me) {
780 
781             // try treating is as a file pathname
782             url = getFileURL(contextURL, path);
783         }
784 
785         // Everything is OK with this URL, although a file url constructed
786         // above may not exist.  This will be caught later when the URL is
787         // accessed.
788         return url;
789     }    // getURL
790 
791     /**
792      * Method getFileURL
793      * 
794      * @param contextURL 
795      * @param path       
796      * @return 
797      * @throws IOException 
798      */
799     private static URL getFileURL(URL contextURL, String path)
800             throws IOException {
801 
802         if (contextURL != null) {
803 
804             // get the parent directory of the contextURL, and append
805             // the spec string to the end.
806             String contextFileName = contextURL.getFile();
807             URL parent = null;
808             File parentFile = new File(contextFileName).getParentFile(); 
809             if ( parentFile != null ) {
810                 parent = parentFile.toURL(); 
811             }
812             if (parent != null) {
813                 return new URL(parent, path);
814             }
815         }
816 
817         return new URL("file", "", path);
818     }    // getFileURL
819 
820     /**
821      * Recursively find all xsd:import'ed objects and call populate for each one.
822      * 
823      * @param context 
824      * @param node    
825      * @throws IOException                  
826      * @throws ParserConfigurationException 
827      * @throws SAXException                 
828      * @throws WSDLException                
829      */
830     private void lookForImports(URL context, Node node)
831             throws IOException, ParserConfigurationException, SAXException,
832             WSDLException {
833 
834         NodeList children = node.getChildNodes();
835 
836         for (int i = 0; i < children.getLength(); i++) {
837             Node child = children.item(i);
838 
839             if ("import".equals(child.getLocalName())) {
840                 NamedNodeMap attributes = child.getAttributes();
841                 Node namespace = attributes.getNamedItem("namespace");
842 
843                 // skip XSD import of soap encoding
844                 if ((namespace != null)
845                         && isKnownNamespace(namespace.getNodeValue())) {
846                     continue;
847                 }
848 
849                 Node importFile = attributes.getNamedItem("schemaLocation");
850 
851                 if (importFile != null) {
852                     URL url = getURL(context, importFile.getNodeValue());
853 
854                     if (!importedFiles.contains(url)) {
855                         importedFiles.add(url);
856 
857                         String filename = url.toString();
858 
859                         populate(url, null, XMLUtils.newDocument(filename),
860                                 filename);
861                     }
862                 }
863             }
864 
865             lookForImports(context, child);
866         }
867     }    // lookForImports
868 
869     /**
870      * Check if this is a known namespace (soap-enc or schema xsd or schema xsi or xml)
871      * 
872      * @param namespace 
873      * @return true if this is a know namespace.
874      */
875     public boolean isKnownNamespace(String namespace) {
876 
877         if (Constants.isSOAP_ENC(namespace)) {
878             return true;
879         }
880 
881         if (Constants.isSchemaXSD(namespace)) {
882             return true;
883         }
884 
885         if (Constants.isSchemaXSI(namespace)) {
886             return true;
887         }
888 
889         if (namespace.equals(Constants.NS_URI_XML)) {
890             return true;
891         }
892 
893         return false;
894     }
895 
896     /**
897      * Populate the symbol table with all of the Types from the Document.
898      * 
899      * @param context 
900      * @param doc     
901      * @throws IOException                  
902      * @throws SAXException                 
903      * @throws WSDLException                
904      * @throws ParserConfigurationException 
905      */
906     public void populateTypes(URL context, Document doc)
907             throws IOException, SAXException, WSDLException,
908             ParserConfigurationException {
909         addTypes(context, doc, ABOVE_SCHEMA_LEVEL);
910     }    // populateTypes
911 
912     /**
913      * Utility method which walks the Document and creates Type objects for
914      * each complexType, simpleType, attributeGroup or element referenced or defined.
915      * <p/>
916      * What goes into the symbol table?  In general, only the top-level types
917      * (ie., those just below
918      * the schema tag).  But base types and references can
919      * appear below the top level.  So anything
920      * at the top level is added to the symbol table,
921      * plus non-Element types (ie, base and refd)
922      * that appear deep within other types.
923      */
924     private static final int ABOVE_SCHEMA_LEVEL = -1;
925 
926     /** Field SCHEMA_LEVEL */
927     private static final int SCHEMA_LEVEL = 0;
928 
929     /**
930      * Method addTypes
931      * 
932      * @param context 
933      * @param node    
934      * @param level   
935      * @throws IOException                  
936      * @throws ParserConfigurationException 
937      * @throws WSDLException                
938      * @throws SAXException                 
939      */
940     private void addTypes(URL context, Node node, int level)
941             throws IOException, ParserConfigurationException, WSDLException,
942             SAXException {
943 
944         if (node == null) {
945             return;
946         }
947 
948         // Get the kind of node (complexType, wsdl:part, etc.)
949         String localPart = node.getLocalName();
950 
951         if (localPart != null) {
952             boolean isXSD =
953                     Constants.isSchemaXSD(node.getNamespaceURI());
954 
955             if (((isXSD && localPart.equals("complexType"))
956                     || localPart.equals("simpleType"))) {
957 
958                 // If an extension or restriction is present,
959                 // create a type for the reference
960                 Node re = SchemaUtils.getRestrictionOrExtensionNode(node);
961 
962                 if ((re != null) && (Utils.getAttribute(re, "base") != null)) {
963                     createTypeFromRef(re);
964                 }
965 
966                 Node list = SchemaUtils.getListNode(node);
967                 if (list != null && Utils.getAttribute(list,"itemType") != null) {
968                     createTypeFromRef(list);
969                 }
970 
971                 Node union = SchemaUtils.getUnionNode(node);
972                 if (union != null) {
973                     QName [] memberTypes = Utils.getMemberTypeQNames(union);
974                     if (memberTypes != null) {
975                         for (int i=0;i<memberTypes.length;i++) {
976                             if (SchemaUtils.isSimpleSchemaType(memberTypes[i]) &&
977                                 getType(memberTypes[i]) == null) {
978                                 symbolTablePut(new BaseType(memberTypes[i]));
979                             }
980                         }
981                     }
982                 }
983 
984                 // This is a definition of a complex type.
985                 // Create a Type.
986                 createTypeFromDef(node, false, false);
987             } else if (isXSD && localPart.equals("element")) {
988 
989                 // Create a type entry for the referenced type
990                 createTypeFromRef(node);
991 
992                 // If an extension or restriction is present,
993                 // create a type for the reference
994                 Node re = SchemaUtils.getRestrictionOrExtensionNode(node);
995 
996                 if ((re != null) && (Utils.getAttribute(re, "base") != null)) {
997                     createTypeFromRef(re);
998                 }
999 
1000                // Create a type representing an element.  (This may
1001                // seem like overkill, but is necessary to support ref=
1002                // and element=.
1003                createTypeFromDef(node, true, level > SCHEMA_LEVEL);
1004            } else if (isXSD && localPart.equals("attributeGroup")) {
1005
1006                // bug 23145: support attributeGroup (Brook Richan)
1007                // Create a type entry for the referenced type
1008                createTypeFromRef(node);
1009
1010                // Create a type representing an attributeGroup.
1011                createTypeFromDef(node, false, level > SCHEMA_LEVEL);
1012            }  else if (isXSD && localPart.equals("group")) {
1013                // Create a type entry for the referenced type
1014                createTypeFromRef(node);
1015                // Create a type representing an group
1016                createTypeFromDef(node, false, level > SCHEMA_LEVEL);
1017            } else if (isXSD && localPart.equals("attribute")) {
1018
1019                // Create a type entry for the referenced type
1020                BooleanHolder forElement = new BooleanHolder();
1021                QName refQName = Utils.getTypeQName(node, forElement,
1022                        false);
1023
1024                if ((refQName != null) && !forElement.value) {
1025                    createTypeFromRef(node);
1026
1027                    // Get the symbol table entry and make sure it is a simple
1028                    // type
1029                    if (refQName != null) {
1030                        TypeEntry refType = getTypeEntry(refQName, false);
1031
1032                        if ((refType != null)
1033                                && (refType instanceof Undefined)) {
1034
1035                            // Don't know what the type is.
1036                            // It better be simple so set it as simple
1037                            refType.setSimpleType(true);
1038                        } else if ((refType == null)
1039                                || (!(refType instanceof BaseType)
1040                                && !refType.isSimpleType())) {
1041
1042                            // Problem if not simple
1043                            throw new IOException(
1044                                    Messages.getMessage(
1045                                            "AttrNotSimpleType01",
1046                                            refQName.toString()));
1047                        }
1048                    }
1049                }
1050                createTypeFromDef(node, true, level > SCHEMA_LEVEL);
1051            } else if (isXSD && localPart.equals("any")) {
1052
1053                // Map xsd:any element to special xsd:any "type"
1054                if (getType(Constants.XSD_ANY) == null) {
1055                    Type type = new BaseType(Constants.XSD_ANY);
1056
1057                    symbolTablePut(type);
1058                }
1059            } else if (localPart.equals("part")
1060                    && Constants.isWSDL(node.getNamespaceURI())) {
1061
1062                // This is a wsdl part.  Create an TypeEntry representing the reference
1063                createTypeFromRef(node);
1064            } else if (isXSD && localPart.equals("include")) {
1065                String includeName = Utils.getAttribute(node, "schemaLocation");
1066
1067                if (includeName != null) {
1068                    URL url = getURL(context, includeName);
1069                    Document includeDoc = XMLUtils.newDocument(url.toString());
1070
1071                    // Vidyanand : Fix for Bug #15124
1072                    org.w3c.dom.Element schemaEl =
1073                            includeDoc.getDocumentElement();
1074
1075                    if (!schemaEl.hasAttribute("targetNamespace")) {
1076                        org.w3c.dom.Element parentSchemaEl =
1077                                (org.w3c.dom.Element) node.getParentNode();
1078
1079                        if (parentSchemaEl.hasAttribute("targetNamespace")) {
1080
1081                            // we need to set two things in here
1082                            // 1. targetNamespace
1083                            // 2. setup the xmlns=<targetNamespace> attribute
1084                            String tns =
1085                                    parentSchemaEl.getAttribute("targetNamespace");
1086
1087                            schemaEl.setAttribute("targetNamespace", tns);
1088                            schemaEl.setAttribute("xmlns", tns);
1089                        }
1090                    }
1091
1092                    populate(url, null, includeDoc, url.toString());
1093                }
1094            }
1095        }
1096
1097        if (level == ABOVE_SCHEMA_LEVEL) {
1098            if ((localPart != null)
1099                && localPart.equals("schema")) {
1100                level = SCHEMA_LEVEL;
1101                String targetNamespace = ((org.w3c.dom.Element) node).getAttribute("targetNamespace");
1102                String elementFormDefault = ((org.w3c.dom.Element) node).getAttribute("elementFormDefault");
1103                if (targetNamespace != null && targetNamespace.length() > 0) {
1104                    elementFormDefault = (elementFormDefault == null || elementFormDefault.length() == 0) ?
1105                            "unqualified" : elementFormDefault;
1106                    if(elementFormDefaults.get(targetNamespace)==null) {
1107                        elementFormDefaults.put(targetNamespace, elementFormDefault);
1108                    }
1109                }
1110            }
1111        } else {
1112            ++level;
1113        }
1114
1115        // Recurse through children nodes
1116        NodeList children = node.getChildNodes();
1117
1118        for (int i = 0; i < children.getLength(); i++) {
1119            addTypes(context, children.item(i), level);
1120        }
1121    }    // addTypes
1122
1123    /**
1124     * Create a TypeEntry from the indicated node, which defines a type
1125     * that represents a complexType, simpleType or element (for ref=).
1126     * 
1127     * @param node             
1128     * @param isElement        
1129     * @param belowSchemaLevel 
1130     * @throws IOException 
1131     */
1132    private void createTypeFromDef(
1133            Node node, boolean isElement, boolean belowSchemaLevel)
1134            throws IOException {
1135
1136        // Get the QName of the node's name attribute value
1137        QName qName = Utils.getNodeNameQName(node);
1138
1139        if (qName != null) {
1140
1141            // If the qname is already registered as a base type,
1142            // don't create a defining type/element.
1143            if (!isElement && (btm.getBaseName(qName) != null)) {
1144                return;
1145            }
1146
1147            // If the node has a type or ref attribute, get the
1148            // qname representing the type
1149            BooleanHolder forElement = new BooleanHolder();
1150            QName refQName = Utils.getTypeQName(node, forElement,
1151                    false);
1152
1153            if (refQName != null) {
1154
1155                // Error check - bug 12362
1156                if (qName.getLocalPart().length() == 0) {
1157                    String name = Utils.getAttribute(node, "name");
1158
1159                    if (name == null) {
1160                        name = "unknown";
1161                    }
1162
1163                    throw new IOException(Messages.getMessage("emptyref00",
1164                            name));
1165                }
1166
1167                // Now get the TypeEntry
1168                TypeEntry refType = getTypeEntry(refQName, forElement.value);
1169
1170                if (!belowSchemaLevel) {
1171                    if (refType == null) {
1172                        throw new IOException(
1173                                Messages.getMessage(
1174                                        "absentRef00", refQName.toString(),
1175                                        qName.toString()));
1176                    }
1177
1178                    symbolTablePut(new DefinedElement(qName, refType, node,
1179                            ""));
1180                }
1181            } else {
1182
1183                // Flow to here indicates no type= or ref= attribute.
1184                // See if this is an array or simple type definition.
1185                IntHolder numDims = new IntHolder();
1186                BooleanHolder underlTypeNillable = new BooleanHolder();
1187
1188                // If we're supposed to unwrap arrays, supply someplace to put the "inner" QName
1189                // so we can propagate it into the appropriate metadata container.
1190                QNameHolder itemQName = wrapArrays ? null : new QNameHolder();
1191
1192                numDims.value = 0;
1193
1194                QName arrayEQName = 
1195                        SchemaUtils.getArrayComponentQName(node,
1196                                                           numDims,
1197                                                           underlTypeNillable,
1198                                                           itemQName,
1199                                                           this);
1200
1201                if (arrayEQName != null) {
1202
1203                    // Get the TypeEntry for the array element type
1204                    refQName = arrayEQName;
1205
1206                    TypeEntry refType = getTypeEntry(refQName, false);
1207
1208                    if (refType == null) {
1209//                        arrayTypeQNames.add(refQName);
1210
1211                        // Not defined yet, add one
1212                        String baseName = btm.getBaseName(refQName);
1213
1214                        if (baseName != null) {
1215                            refType = new BaseType(refQName);
1216                        } else {
1217                            refType = new UndefinedType(refQName);
1218                        }
1219
1220                        symbolTablePut(refType);
1221                    }
1222
1223                    // Create a defined type or element that references refType
1224                    String dims = "";
1225
1226                    while (numDims.value > 0) {
1227                        dims += "[]";
1228
1229                        numDims.value--;
1230                    }
1231
1232                    TypeEntry defType = null;
1233
1234                    if (isElement) {
1235                        if (!belowSchemaLevel) {
1236                            defType =
1237                               new DefinedElement(qName, refType, node, dims);
1238                            // Save component type for ArraySerializer
1239                            defType.setComponentType(arrayEQName);
1240                            if (itemQName != null)
1241                                defType.setItemQName(itemQName.value);
1242                        }
1243                    } else {
1244                        defType = new DefinedType(qName, refType, node, dims);
1245                        // Save component type for ArraySerializer
1246                        defType.setComponentType(arrayEQName);
1247                        defType.setUnderlTypeNillable(underlTypeNillable.value);
1248                        if (itemQName != null)
1249                            defType.setItemQName(itemQName.value);
1250                    }
1251
1252                    if (defType != null) {
1253                        symbolTablePut(defType);
1254                    }
1255                } else {
1256
1257                    // Create a TypeEntry representing this  type/element
1258                    String baseName = btm.getBaseName(qName);
1259
1260                    if (baseName != null) {
1261                        symbolTablePut(new BaseType(qName));
1262                    } else {
1263
1264                        // Create a type entry, set whether it should
1265                        // be mapped as a simple type, and put it in the
1266                        // symbol table.
1267                        TypeEntry te = null;
1268                        TypeEntry parentType = null;
1269
1270                        if (!isElement) {
1271                            te = new DefinedType(qName, node);
1272
1273                            // check if we are an anonymous type underneath
1274                            // an element.  If so, we point the refType of the
1275                            // element to us (the real type).
1276                            if (qName.getLocalPart().indexOf(ANON_TOKEN) >= 0) {
1277                                Node parent = node.getParentNode();
1278                                QName parentQName =
1279                                        Utils.getNodeNameQName(parent);
1280                                parentType = getElement(parentQName);
1281                            }
1282                        } else {
1283                            if (!belowSchemaLevel) {
1284                                te = new DefinedElement(qName, node);
1285                            }
1286                        }
1287
1288                        if (te != null) {
1289                            if (SchemaUtils.isSimpleTypeOrSimpleContent(node)) {
1290                                te.setSimpleType(true);
1291                            }
1292                            te = (TypeEntry)symbolTablePut(te);
1293
1294                            if (parentType != null) {
1295                                parentType.setRefType(te);
1296                            }
1297                        }
1298                    }
1299                }
1300            }
1301        }
1302    }    // createTypeFromDef
1303
1304    /**
1305     * Node may contain a reference (via type=, ref=, or element= attributes) to
1306     * another type.  Create a Type object representing this referenced type.
1307     * 
1308     * @param node 
1309     * @throws IOException 
1310     */
1311    private void createTypeFromRef(Node node) throws IOException {
1312
1313        // Get the QName of the node's type attribute value
1314        BooleanHolder forElement = new BooleanHolder();
1315        QName qName = Utils.getTypeQName(node, forElement, false);
1316
1317        if (qName == null || (Constants.isSchemaXSD(qName.getNamespaceURI()) &&
1318                qName.getLocalPart().equals("simpleRestrictionModel"))) {
1319            return;
1320        }
1321
1322        // Error check - bug 12362
1323        if (qName.getLocalPart().length() == 0) {
1324            String name = Utils.getAttribute(node, "name");
1325
1326            if (name == null) {
1327                name = "unknown";
1328            }
1329
1330            throw new IOException(Messages.getMessage("emptyref00", name));
1331        }
1332
1333        // Get Type or Element depending on whether type attr was used.
1334        TypeEntry type = getTypeEntry(qName, forElement.value);
1335
1336        // A symbol table entry is created if the TypeEntry is not found
1337        if (type == null) {
1338
1339            // See if this is a special QName for collections
1340            if (qName.getLocalPart().indexOf("[") > 0) {
1341                QName containedQName = Utils.getTypeQName(node,
1342                        forElement, true);
1343                TypeEntry containedTE = getTypeEntry(containedQName,
1344                        forElement.value);
1345
1346                if (!forElement.value) {
1347
1348                    // Case of type and maxOccurs
1349                    if (containedTE == null) {
1350
1351                        // Collection Element Type not defined yet, add one.
1352                        String baseName = btm.getBaseName(containedQName);
1353
1354                        if (baseName != null) {
1355                            containedTE = new BaseType(containedQName);
1356                        } else {
1357                            containedTE = new UndefinedType(containedQName);
1358                        }
1359
1360                        symbolTablePut(containedTE);
1361                    }
1362                    symbolTablePut(new CollectionType(qName, containedTE,
1363                            node, "[]"));
1364                } else {
1365
1366                    // Case of ref and maxOccurs
1367                    if (containedTE == null) {
1368                        containedTE = new UndefinedElement(containedQName);
1369
1370                        symbolTablePut(containedTE);
1371                    }
1372
1373                    symbolTablePut(new CollectionElement(qName,
1374                            containedTE, node,
1375                            "[]"));
1376                }
1377            } else {
1378
1379                // Add a BaseType or Undefined Type/Element
1380                String baseName = btm.getBaseName(qName);
1381
1382                if (baseName != null) {
1383                    symbolTablePut(new BaseType(qName));
1384
1385                    // bugzilla 23145: handle attribute groups
1386                    // soap/encoding is treated as a "known" schema
1387                    // so now let's act like we know it
1388                } else if (qName.equals(Constants.SOAP_COMMON_ATTRS11)) {
1389                    symbolTablePut(new BaseType(qName));
1390
1391                    // the 1.1 commonAttributes type contains two attributes
1392                    // make sure those attributes' types are in the symbol table
1393                    // attribute name = "id" type = "xsd:ID"
1394                    if (getTypeEntry(Constants.XSD_ID, false) == null) {
1395                        symbolTablePut(new BaseType(Constants.XSD_ID));
1396                    }
1397
1398                    // attribute name = "href" type = "xsd:anyURI"
1399                    if (getTypeEntry(Constants.XSD_ANYURI, false) == null) {
1400                        symbolTablePut(new BaseType(Constants.XSD_ANYURI));
1401                    }
1402                } else if (qName.equals(Constants.SOAP_COMMON_ATTRS12)) {
1403                    symbolTablePut(new BaseType(qName));
1404
1405                    // the 1.2 commonAttributes type contains one attribute
1406                    // make sure the attribute's type is in the symbol table
1407                    // attribute name = "id" type = "xsd:ID"
1408                    if (getTypeEntry(Constants.XSD_ID, false) == null) {
1409                        symbolTablePut(new BaseType(Constants.XSD_ID));
1410                    }
1411                } else if (qName.equals(Constants.SOAP_ARRAY_ATTRS11)) {
1412                    symbolTablePut(new BaseType(qName));
1413
1414                    // the 1.1 arrayAttributes type contains two attributes
1415                    // make sure the attributes' types are in the symbol table
1416                    // attribute name = "arrayType" type = "xsd:string"
1417                    if (getTypeEntry(Constants.XSD_STRING, false) == null) {
1418                        symbolTablePut(new BaseType(Constants.XSD_STRING));
1419                    }
1420
1421                    // attribute name = "offset" type = "soapenc:arrayCoordinate"
1422                    // which is really an xsd:string
1423                } else if (qName.equals(Constants.SOAP_ARRAY_ATTRS12)) {
1424                    symbolTablePut(new BaseType(qName));
1425
1426                    // the 1.2 arrayAttributes type contains two attributes
1427                    // make sure the attributes' types are in the symbol table
1428                    // attribute name = "arraySize" type = "2003soapenc:arraySize"
1429                    // which is really a hairy beast that is not
1430                    // supported, yet; so let's just use string
1431                    if (getTypeEntry(Constants.XSD_STRING, false) == null) {
1432                        symbolTablePut(new BaseType(Constants.XSD_STRING));
1433                    }
1434
1435                    // attribute name = "itemType" type = "xsd:QName"
1436                    if (getTypeEntry(Constants.XSD_QNAME, false) == null) {
1437                        symbolTablePut(new BaseType(Constants.XSD_QNAME));
1438                    }
1439                } else if (forElement.value == false) {
1440                    symbolTablePut(new UndefinedType(qName));
1441                } else {
1442                    symbolTablePut(new UndefinedElement(qName));
1443                }
1444            }
1445        }
1446    }    // createTypeFromRef
1447
1448    /**
1449     * Populate the symbol table with all of the MessageEntry's from the Definition.
1450     * 
1451     * @param def 
1452     * @throws IOException 
1453     */
1454    private void populateMessages(Definition def) throws IOException {
1455
1456        Iterator i = def.getMessages().values().iterator();
1457
1458        while (i.hasNext()) {
1459            Message message = (Message) i.next();
1460            MessageEntry mEntry = new MessageEntry(message);
1461
1462            symbolTablePut(mEntry);
1463        }
1464    }    // populateMessages
1465
1466    /**
1467     * ensures that a message in a <code>&lt;input&gt;</code>, <code>&lt;output&gt;</code>,
1468     * or <code>&lt;fault&gt;</fault> element in an <code>&lt;operation&gt;</code>
1469     * element is valid. In particular, ensures that
1470     * <ol>
1471     * <li>an attribute <code>message</code> is present (according to the
1472     * XML Schema for WSDL 1.1 <code>message</code> is <strong>required</strong>
1473     * <p/>
1474     * <li>the value of attribute <code>message</code> (a QName) refers to
1475     * an already defined message
1476     * </ol>
1477     * <p/>
1478     * <strong>Note</strong>: this method should throw a <code>javax.wsdl.WSDLException</code> rather than
1479     * a <code>java.io.IOException</code>
1480     * 
1481     * @param message the message object
1482     * @throws IOException thrown, if the message is not valid
1483     */
1484    protected void ensureOperationMessageValid(Message message)
1485            throws IOException {
1486
1487        // make sure the message is not null (i.e. there is an
1488        // attribute 'message ')
1489        // 
1490        if (message == null) {
1491            throw new IOException(
1492                    "<input>,<output>, or <fault> in <operation ..> without attribute 'message' found. Attribute 'message' is required.");
1493        }
1494
1495        // make sure the value of the attribute refers to an
1496        // already defined message
1497        // 
1498        if (message.isUndefined()) {
1499            throw new IOException(
1500                    "<input ..>, <output ..> or <fault ..> in <portType> with undefined message found. message name is '"
1501                    + message.getQName().toString() + "'");
1502        }
1503    }
1504
1505    /**
1506     * ensures that an an element <code>&lt;operation&gt;</code> within
1507     * an element <code>&lt;portType&gt;<code> is valid. Throws an exception
1508     * if the operation is not valid.
1509     * <p/>
1510     * <strong>Note</strong>: this method should throw a <code>javax.wsdl.WSDLException</code>
1511     * rather than a <code>java.io.IOException</code>
1512     * 
1513     * @param operation the operation element
1514     * @throws IOException              thrown, if the element is not valid.
1515     * @throws IllegalArgumentException thrown, if operation is null
1516     */
1517    protected void ensureOperationValid(Operation operation)
1518            throws IOException {
1519
1520        if (operation == null) {
1521            throw new IllegalArgumentException(
1522                    "parameter 'operation' must not be null");
1523        }
1524
1525        Input input = operation.getInput();
1526        Message message;
1527        
1528        if (input != null) {
1529            message = input.getMessage();
1530            if (message == null) {
1531                throw new IOException(
1532                        "No 'message' attribute in <input> for operation '" +
1533                        operation.getName() + "'");
1534            }
1535            ensureOperationMessageValid(message);
1536        }
1537
1538        Output output = operation.getOutput();
1539
1540        if (output != null) {
1541            message = output.getMessage();
1542            if (message == null) {
1543                throw new IOException(
1544                        "No 'message' attribute in <output> for operation '" +
1545                        operation.getName() + "'");
1546            }
1547            ensureOperationMessageValid(output.getMessage());
1548        }
1549
1550        Map faults = operation.getFaults();
1551
1552        if (faults != null) {
1553            Iterator it = faults.values().iterator();
1554
1555            while (it.hasNext()) {
1556                Fault fault = (Fault)it.next();
1557                message = fault.getMessage();
1558                if (message == null) {
1559                    throw new IOException(
1560                            "No 'message' attribute in <fault> named '" + 
1561                            fault.getName() + "' for operation '" +
1562                            operation.getName() + "'");
1563                }
1564                ensureOperationMessageValid(message);
1565            }
1566        }
1567    }
1568
1569    /**
1570     * ensures that an an element <code>&lt;portType&gt;</code>
1571     * is valid. Throws an exception if the portType is not valid.
1572     * <p/>
1573     * <strong>Note</strong>: this method should throw a <code>javax.wsdl.WSDLException</code>
1574     * rather than a <code>java.io.IOException</code>
1575     * 
1576     * @param portType the portType element
1577     * @throws IOException              thrown, if the element is not valid.
1578     * @throws IllegalArgumentException thrown, if operation is null
1579     */
1580    protected void ensureOperationsOfPortTypeValid(PortType portType)
1581            throws IOException {
1582
1583        if (portType == null) {
1584            throw new IllegalArgumentException(
1585                    "parameter 'portType' must not be null");
1586        }
1587
1588        List operations = portType.getOperations();
1589
1590        // no operations defined ? -> valid according to the WSDL 1.1 schema
1591        // 
1592        if ((operations == null) || (operations.size() == 0)) {
1593            return;
1594        }
1595
1596        // check operations defined in this portType
1597        // 
1598        Iterator it = operations.iterator();
1599
1600        while (it.hasNext()) {
1601            Operation operation = (Operation) it.next();
1602
1603            ensureOperationValid(operation);
1604        }
1605    }
1606
1607    /**
1608     * Populate the symbol table with all of the PortTypeEntry's from the Definition.
1609     * 
1610     * @param def 
1611     * @throws IOException 
1612     */
1613    private void populatePortTypes(Definition def) throws IOException {
1614
1615        Iterator i = def.getPortTypes().values().iterator();
1616
1617        while (i.hasNext()) {
1618            PortType portType = (PortType) i.next();
1619
1620            // If the portType is undefined, then we're parsing a Definition
1621            // that didn't contain a portType, merely a binding that referred
1622            // to a non-existent port type.  Don't bother with it.
1623            if (!portType.isUndefined()) {
1624                ensureOperationsOfPortTypeValid(portType);
1625
1626                PortTypeEntry ptEntry = new PortTypeEntry(portType);
1627
1628                symbolTablePut(ptEntry);
1629            }
1630        }
1631    }    // populatePortTypes
1632
1633    /**
1634     * Create the parameters and store them in the bindingEntry.
1635     * 
1636     * @throws IOException 
1637     */
1638    private void populateParameters() throws IOException {
1639
1640        Iterator it = symbolTable.values().iterator();
1641
1642        while (it.hasNext()) {
1643            Vector v = (Vector) it.next();
1644
1645            for (int i = 0; i < v.size(); ++i) {
1646                if (v.get(i) instanceof BindingEntry) {
1647                    BindingEntry bEntry = (BindingEntry) v.get(i);
1648
1649                    // Skip non-soap bindings
1650                    if (bEntry.getBindingType() != BindingEntry.TYPE_SOAP) {
1651                        continue;
1652                    }
1653
1654                    Binding binding = bEntry.getBinding();
1655                    Collection bindOperations = bEntry.getOperations();
1656                    PortType portType = binding.getPortType();
1657                    HashMap parameters = new HashMap();
1658                    Iterator operations =
1659                            portType.getOperations().iterator();
1660
1661                    // get parameters
1662                    while (operations.hasNext()) {
1663                        Operation operation = (Operation) operations.next();
1664
1665                        // See if the PortType operation has a corresponding
1666                        // Binding operation and report an error if it doesn't.
1667                        if (!bindOperations.contains(operation)) {
1668                            throw new IOException(
1669                                    Messages.getMessage(
1670                                            "emitFailNoMatchingBindOperation01",
1671                                            operation.getName(),
1672                                            portType.getQName().getLocalPart()));
1673                        }
1674
1675                        String namespace =
1676                                portType.getQName().getNamespaceURI();
1677                        Parameters parms = getOperationParameters(operation,
1678                                namespace, bEntry);
1679                        parameters.put(operation, parms);
1680                    }
1681
1682                    bEntry.setParameters(parameters);
1683                }
1684            }
1685        }
1686    }    // populateParameters
1687
1688    /**
1689     * For the given operation, this method returns the parameter info conveniently collated.
1690     * There is a bit of processing that is needed to write the interface, stub, and skeleton.
1691     * Rather than do that processing 3 times, it is done once, here, and stored in the
1692     * Parameters object.
1693     * 
1694     * @param operation    
1695     * @param namespace    
1696     * @param bindingEntry 
1697     * @return 
1698     * @throws IOException 
1699     */
1700    public Parameters getOperationParameters(
1701            Operation operation, String namespace, BindingEntry bindingEntry)
1702            throws IOException {
1703
1704        Parameters parameters = new Parameters();
1705
1706        // The input and output Vectors of Parameters
1707        Vector inputs = new Vector();
1708        Vector outputs = new Vector();
1709        List parameterOrder = operation.getParameterOrdering();
1710
1711        // Handle parameterOrder="", which is techinically illegal
1712        if ((parameterOrder != null) && parameterOrder.isEmpty()) {
1713            parameterOrder = null;
1714        }
1715
1716        Input input = operation.getInput();
1717        Output output = operation.getOutput();
1718        
1719        parameters.mep = operation.getStyle();
1720        
1721        // All input parts MUST be in the parameterOrder list.  It is an error otherwise.
1722        if (parameterOrder != null && !wrapped) {
1723            if (input != null) {
1724                Message inputMsg = input.getMessage();
1725                Map allInputs = inputMsg.getParts();
1726                Collection orderedInputs =
1727                        inputMsg.getOrderedParts(parameterOrder);
1728
1729                if (allInputs.size() != orderedInputs.size()) {
1730                    throw new IOException(
1731                            Messages.getMessage("emitFail00", operation.getName()));
1732                }
1733            }
1734        }
1735
1736        boolean literalInput = false;
1737        boolean literalOutput = false;
1738
1739        if (bindingEntry != null) {
1740            literalInput = (bindingEntry.getInputBodyType(operation)
1741                    == Use.LITERAL);
1742            literalOutput = (bindingEntry.getOutputBodyType(operation)
1743                    == Use.LITERAL);
1744        }
1745
1746        // Collect all the input parameters
1747        if ((input != null) && (input.getMessage() != null)) {
1748            getParametersFromParts(inputs,
1749                    input.getMessage().getOrderedParts(null),
1750                    literalInput, operation.getName(),
1751                    bindingEntry);
1752        }
1753
1754        // Collect all the output parameters
1755        if ((output != null) && (output.getMessage() != null)) {
1756            getParametersFromParts(outputs,
1757                    output.getMessage().getOrderedParts(null),
1758                    literalOutput, operation.getName(),
1759                    bindingEntry);
1760        }
1761
1762        if (parameterOrder != null && !wrapped) {
1763
1764            // Construct a list of the parameters in the parameterOrder list, determining the
1765            // mode of each parameter and preserving the parameterOrder list.
1766            for (int i = 0; i < parameterOrder.size(); ++i) {
1767                String name = (String) parameterOrder.get(i);
1768
1769                // index in the inputs Vector of the given name, -1 if it doesn't exist.
1770                int index = getPartIndex(name, inputs);
1771
1772                // index in the outputs Vector of the given name, -1 if it doesn't exist.
1773                int outdex = getPartIndex(name, outputs);
1774
1775                if (index >= 0) {
1776
1777                    // The mode of this parameter is either in or inout
1778                    addInishParm(inputs, outputs, index, outdex, parameters,
1779                            true);
1780                } else if (outdex >= 0) {
1781                    addOutParm(outputs, outdex, parameters, true);
1782                } else {
1783                    System.err.println(Messages.getMessage("noPart00", name));
1784                }
1785            }
1786        }
1787
1788        // Some special case logic for JAX-RPC, but also to make things
1789        // nicer for the user.
1790        // If we have a single input and output with the same name
1791        // instead of: void echo(StringHolder inout)
1792        // Do this:  string echo(string in)
1793        if (wrapped && (inputs.size() == 1) && (outputs.size() == 1)
1794                && 
1795                Utils.getLastLocalPart(((Parameter) inputs.get(0)).getName()).equals(
1796                Utils.getLastLocalPart(((Parameter) outputs.get(0)).getName()))
1797                ) {
1798
1799            // add the input and make sure its a IN not an INOUT
1800            addInishParm(inputs, null, 0, -1, parameters, false);
1801        } else {
1802
1803            // Get the mode info about those parts that aren't in the
1804            // parameterOrder list. Since they're not in the parameterOrder list,
1805            // the order is, first all in (and inout) parameters, then all out
1806            // parameters, in the order they appear in the messages.
1807            for (int i = 0; i < inputs.size(); i++) {
1808                Parameter p = (Parameter) inputs.get(i);
1809                int outdex = getPartIndex(p.getName(), outputs);
1810
1811                addInishParm(inputs, outputs, i, outdex, parameters, false);
1812            }
1813        }
1814
1815        // Now that the remaining in and inout parameters are collected,
1816        // determine the status of outputs.  If there is only 1, then it
1817        // is the return value.  If there are more than 1, then they are
1818        // out parameters.
1819        if (outputs.size() == 1) {
1820            parameters.returnParam = (Parameter) outputs.get(0);
1821
1822            parameters.returnParam.setMode(Parameter.OUT);
1823
1824            if (parameters.returnParam.getType() instanceof DefinedElement) {
1825                parameters.returnParam.setQName(
1826                        parameters.returnParam.getType().getQName());
1827            }
1828
1829            ++parameters.outputs;
1830        } else {
1831            for (int i = 0; i < outputs.size(); i++) {
1832                addOutParm(outputs, i, parameters, false);
1833            }
1834        }
1835
1836        parameters.faults = operation.getFaults();
1837
1838        // before we return the paramters,
1839        // make sure we dont have a duplicate name
1840        Vector used = new Vector(parameters.list.size());
1841        Iterator i = parameters.list.iterator();
1842
1843        while (i.hasNext()) {
1844            Parameter parameter = (Parameter) i.next();
1845            int count = 2;
1846
1847            while (used.contains(parameter.getName())) {
1848
1849                // duplicate, add a suffix and try again
1850                parameter.setName(parameter.getName()
1851                        + Integer.toString(count++));
1852            }
1853
1854            used.add(parameter.getName());
1855        }
1856
1857        return parameters;
1858    }    // parameters
1859
1860    /**
1861     * Return the index of the given name in the given Vector, -1 if it doesn't exist.
1862     * 
1863     * @param name 
1864     * @param v    
1865     * @return 
1866     */
1867    private int getPartIndex(String name, Vector v) {
1868        name = Utils.getLastLocalPart(name);
1869        for (int i = 0; i < v.size(); i++) {
1870            String paramName = ((Parameter) v.get(i)).getName();
1871            paramName = Utils.getLastLocalPart(paramName);
1872            if (name.equals(paramName)) {
1873                return i;
1874            }
1875        }
1876
1877        return -1;
1878    }    // getPartIndex
1879
1880    /**
1881     * Add an in or inout parameter to the parameters object.
1882     * 
1883     * @param inputs     
1884     * @param outputs    
1885     * @param index      
1886     * @param outdex     
1887     * @param parameters 
1888     * @param trimInput  
1889     */
1890    private void addInishParm(Vector inputs, Vector outputs, int index,
1891                              int outdex, Parameters parameters,
1892                              boolean trimInput) {
1893
1894        Parameter p = (Parameter) inputs.get(index);
1895
1896        // If this is an element, we want the XML to reflect the element name
1897        // not the part name.  Same check is made in addOutParam below.
1898        if (p.getType() instanceof DefinedElement) {
1899            DefinedElement de = (DefinedElement) p.getType();
1900
1901            p.setQName(de.getQName());
1902        }
1903
1904        // If this is a collection we want the XML to reflect the type in
1905        // the collection, not foo[unbounded].
1906        // Same check is made in addOutParam below.
1907        if (p.getType() instanceof CollectionElement) {
1908            p.setQName(p.getType().getRefType().getQName());
1909        }
1910
1911        // Should we remove the given parameter type/name entries from the Vector?
1912        if (trimInput) {
1913            inputs.remove(index);
1914        }
1915
1916        // At this point we know the name and type of the parameter, and that it's at least an
1917        // in parameter.  Now check to see whether it's also in the outputs Vector.  If it is,
1918        // then it's an inout parameter.
1919        if (outdex >= 0) {
1920            Parameter outParam = (Parameter) outputs.get(outdex);
1921
1922            TypeEntry paramEntry = p.getType();
1923            TypeEntry outParamEntry = outParam.getType();
1924//            String paramLastLocalPart = Utils.getLastLocalPart(paramEntry.getQName().getLocalPart());
1925//            String outParamLastLocalPart = Utils.getLastLocalPart(outParamEntry.getQName().getLocalPart());
1926            if (paramEntry.equals(outParamEntry)) {
1927                outputs.remove(outdex);
1928                p.setMode(Parameter.INOUT);
1929
1930                ++parameters.inouts;
1931            } 
1932            /*
1933            else if (paramLastLocalPart.equals(outParamLastLocalPart)) {
1934                outputs.remove(outdex);
1935                p.setMode(Parameter.INOUT);
1936
1937                ++parameters.inouts;
1938                if (paramEntry.isBaseType()) {
1939                    if (paramEntry.getBaseType().equals(outParamEntry.getBaseType())) {
1940                        outputs.remove(outdex);
1941                        p.setMode(Parameter.INOUT);
1942
1943                        ++parameters.inouts;
1944                    }
1945                }
1946                else if (paramEntry.getRefType() != null) {
1947                    if (paramEntry.getRefType().equals(outParamEntry.getRefType())) {
1948                        outputs.remove(outdex);
1949                        p.setMode(Parameter.INOUT);
1950
1951                        ++parameters.inouts;
1952                    }
1953                }
1954                else {
1955                    ++parameters.inputs;
1956                }
1957            }
1958        */
1959            else {
1960                
1961                // If we're here, we have both an input and an output
1962                // part with the same name but different types.... guess
1963                // it's not really an inout....
1964                // 
1965                // throw new IOException(Messages.getMessage("differentTypes00",
1966                // new String[] { p.getName(),
1967                // p.getType().getQName().toString(),
1968                // outParam.getType().getQName().toString()
1969                // }
1970                // ));
1971                // There is some controversy about this, and the specs are
1972                // a bit vague about what should happen if the types don't
1973                // agree.  Throwing an error is not correct with document/lit
1974                // operations, as part names get resused (i.e. "body").
1975                // See WSDL 1.1 section 2.4.6,
1976                // WSDL 1.2 working draft 9 July 2002 section 2.3.1
1977                ++parameters.inputs;
1978            }
1979        } else {
1980            ++parameters.inputs;
1981        }
1982
1983        parameters.list.add(p);
1984    }    // addInishParm
1985
1986    /**
1987     * Add an output parameter to the parameters object.
1988     * 
1989     * @param outputs    
1990     * @param outdex     
1991     * @param parameters 
1992     * @param trim       
1993     */
1994    private void addOutParm(Vector outputs, int outdex, Parameters parameters,
1995                            boolean trim) {
1996
1997        Parameter p = (Parameter) outputs.get(outdex);
1998
1999        // If this is an element, we want the XML to reflect the element name
2000        // not the part name.  Same check is made in addInishParam above.
2001        if (p.getType() instanceof DefinedElement) {
2002            DefinedElement de = (DefinedElement) p.getType();
2003
2004            p.setQName(de.getQName());
2005        }
2006
2007        // If this is a collection we want the XML to reflect the type in
2008        // the collection, not foo[unbounded].
2009        // Same check is made in addInishParam above.
2010        if (p.getType() instanceof CollectionElement) {
2011            p.setQName(p.getType().getRefType().getQName());
2012        }
2013
2014        if (trim) {
2015            outputs.remove(outdex);
2016        }
2017
2018        p.setMode(Parameter.OUT);
2019
2020        ++parameters.outputs;
2021
2022        parameters.list.add(p);
2023    }    // addOutParm
2024
2025    /**
2026     * This method returns a vector containing Parameters which represent
2027     * each Part (shouldn't we call these "Parts" or something?)
2028     *
2029     * This routine does the wrapped doc/lit processing.
2030     * It is also used for generating Faults, and this really confuses things
2031     * but we need to do the same processing for the fault messages.
2032     *
2033     * This whole method is waaaay too complex.
2034     * It needs rewriting (for instance, we sometimes new up
2035     * a Parameter, then ignore it in favor of another we new up.)
2036     *
2037     * @param v       The output vector of parameters
2038     * @param parts   The parts of the message
2039     * @param literal Are we in a literal operation (or fault)?
2040     * @param opName  The operation (or fault) name
2041     * @param bindingEntry The binding for this operation - can be NULL if we are looking at a fault
2042     * @throws IOException when encountering an error in the WSDL
2043     */
2044    public void getParametersFromParts(Vector v,
2045                                       Collection parts,
2046                                       boolean literal,
2047                                       String opName,
2048                                       BindingEntry bindingEntry)
2049            throws IOException {
2050
2051        // Determine if there's only one element.  For wrapped
2052        // style, we normally only have 1 part which is an
2053        // element.  But with MIME we could have any number of
2054        // types along with that single element.  As long as
2055        // there's only ONE element, and it's the same name as
2056        // the operation, we can unwrap it.
2057        int numberOfElements = 0;
2058        boolean possiblyWrapped = false;
2059        Iterator i = parts.iterator();
2060
2061        while (i.hasNext()) {
2062            Part part = (Part) i.next();
2063
2064            if (part.getElementName() != null) {
2065                ++numberOfElements;
2066
2067                if (part.getElementName().getLocalPart().equals(opName)) {
2068                    possiblyWrapped = true;
2069                }
2070            }
2071        }
2072
2073        // Try to sense "wrapped" document literal mode
2074        // if we haven't been told not to.
2075        // Criteria:
2076        // - If there is a single element part,
2077        // - That part is an element
2078        // - That element has the same name as the operation
2079        // - That element has no attributes (check done below)
2080        
2081        if (!nowrap && literal && (numberOfElements == 1) && possiblyWrapped) {
2082            wrapped = true;
2083        }
2084
2085        i = parts.iterator();
2086
2087        while (i.hasNext()) {
2088            Parameter param = new Parameter();
2089            Part part = (Part) i.next();
2090            QName elementName = part.getElementName();
2091            QName typeName = part.getTypeName();
2092            String partName = part.getName();
2093
2094            // if we are either:
2095            //   1. encoded
2096            //   2. literal & not wrapped.
2097            if (!literal || !wrapped || (elementName == null)) {
2098                param.setName(partName);
2099
2100                // Add this type or element name
2101                if (typeName != null) {
2102                    param.setType(getType(typeName));
2103                } else if (elementName != null) {
2104
2105                    // Just an FYI: The WSDL spec says that for use=encoded
2106                    // that parts reference an abstract type using the type attr
2107                    // but we kinda do the right thing here, so let it go.
2108                    // if (!literal)
2109                    // error...
2110                    param.setType(getElement(elementName));
2111                } else {
2112
2113                    // no type or element
2114                    throw new IOException(
2115                            Messages.getMessage(
2116                                    "noTypeOrElement00", new String[]{partName,
2117                                                                      opName}));
2118                }
2119
2120                fillParamInfo(param, bindingEntry, opName, partName);
2121                v.add(param);
2122
2123                continue;    // next part
2124            }
2125
2126            // flow to here means wrapped literal !
2127            // See if we can map all the XML types to java(?) types
2128            // if we can, we use these as the types
2129            Node node = null;
2130            TypeEntry typeEntry = null;
2131
2132            if ((typeName != null)
2133                    && (bindingEntry == null || bindingEntry.getMIMETypes().size() == 0)) {
2134
2135                // Since we can't (yet?) make the Axis engine generate the right
2136                // XML for literal parts that specify the type attribute,
2137                // (unless they're MIME types) abort processing with an
2138                // error if we encounter this case
2139                // 
2140                // node = getTypeEntry(typeName, false).getNode();
2141                String bindingName = (bindingEntry == null)
2142                        ? "unknown"
2143                        : bindingEntry.getBinding().getQName().toString();
2144
2145                throw new IOException(Messages.getMessage("literalTypePart00",
2146                        new String[]{
2147                            partName,
2148                            opName,
2149                            bindingName}));
2150            }
2151
2152            // Get the node which corresponds to the type entry for this
2153            // element.  i.e.:
2154            // <part name="part" element="foo:bar"/>
2155            // ...
2156            // <schema targetNamespace="foo">
2157            // <element name="bar"...>  <--- This one
2158            typeEntry = getTypeEntry(elementName, true);
2159            node = typeEntry.getNode();
2160
2161            // Check if this element is of the form:
2162            // <element name="foo" type="tns:foo_type"/>
2163            BooleanHolder forElement = new BooleanHolder();
2164            QName type = Utils.getTypeQName(node, forElement,
2165                    false);
2166            if ((type != null) && !forElement.value) {
2167
2168                // If in fact we have such a type, go get the node that
2169                // corresponds to THAT definition.
2170                typeEntry = getTypeEntry(type, false);
2171                node = typeEntry.getNode();
2172            }
2173
2174            Vector vTypes = null;
2175            
2176            // If we have nothing at this point, we're in trouble.
2177            if (node == null) {
2178              // If node is null, that means the element in question has no type declaration, 
2179              // therefore is not a wrapper element.
2180              wrapped = false;
2181            } else {
2182
2183                // check for attributes
2184                if (typeEntry.getContainedAttributes() != null) {
2185                    // can't do wrapped mode
2186                    wrapped = false;
2187                }
2188                
2189                if (!SchemaUtils.isWrappedType(node)) {
2190                    // mark the type entry as not just literal referenced
2191                    // This doesn't work, but it may help in the future.
2192                    // The problem is "wrapped" is a symbol table wide flag,
2193                    // which means if one operation breaks the rules
2194                    // implemented in isWrappedType(), then everything goes bad
2195                    // For example, see bug Axis-1900.
2196                    typeEntry.setOnlyLiteralReference(false);
2197                    wrapped = false;
2198                }
2199
2200                // Get the nested type entries.
2201                // TODO - If we are unable to represent any of the types in the
2202                // element, we need to use SOAPElement/SOAPBodyElement.
2203                // I don't believe getContainedElementDecl does the right thing yet.
2204                vTypes = typeEntry.getContainedElements();
2205            }
2206
2207            // IF we got the type entries and we didn't find attributes
2208            // THEN use the things in this element as the parameters
2209            if ((vTypes != null) && wrapped) {
2210
2211                // add the elements in this list
2212                for (int j = 0; j < vTypes.size(); j++) {
2213                    ElementDecl elem = (ElementDecl) vTypes.elementAt(j);
2214                    Parameter p = new Parameter();
2215
2216                    p.setQName(elem.getQName());
2217                    // If the parameter is a anonymous complex type, the parameter
2218                    // name should just be the name of the element, not >foo>element
2219                    String paramName = p.getName();
2220                    final int gt = paramName.lastIndexOf(ANON_TOKEN);
2221                    if (gt != 1) {
2222                        paramName = paramName.substring(gt+1);
2223                    }
2224                    p.setName(paramName);
2225                    p.setType(elem.getType());
2226                    p.setOmittable(elem.getMinOccursIs0());
2227                    fillParamInfo(p, bindingEntry, opName, partName);
2228                    v.add(p);
2229                }
2230            } else {
2231
2232                // - we were unable to get the types OR
2233                // - we found attributes
2234                // so we can't use wrapped mode.
2235                param.setName(partName);
2236
2237                if (typeName != null) {
2238                    param.setType(getType(typeName));
2239                } else if (elementName != null) {
2240                    param.setType(getElement(elementName));
2241                }
2242
2243                fillParamInfo(param, bindingEntry, opName, partName);
2244                v.add(param);
2245            }
2246        }                    // while
2247    }                        // getParametersFromParts
2248
2249    /**
2250     * Set the header information for this paramter
2251     * 
2252     * @param param        Parameter to modify
2253     * @param bindingEntry Binding info for this operation/parameter
2254     * @param opName       the operation we are processing
2255     * @param partName     the part we are processing
2256     */
2257    private void fillParamInfo(Parameter param, BindingEntry bindingEntry,
2258                               String opName, String partName) {
2259
2260        // If we don't have a binding, can't do anything
2261        if (bindingEntry == null)
2262            return;
2263
2264        setMIMEInfo(param, bindingEntry.getMIMEInfo(opName, partName));
2265
2266        boolean isHeader = false;
2267
2268        // Is this parameter in an Input header?
2269        if (bindingEntry.isInHeaderPart(opName, partName)) {
2270            isHeader = true;
2271            param.setInHeader(true);
2272        }
2273
2274        // Is this parameter in an Output header?
2275        if (bindingEntry.isOutHeaderPart(opName, partName)) {
2276            isHeader = true;
2277            param.setOutHeader(true);
2278        }
2279
2280        // If this parameter is part of a header, find the binding operation
2281        // that we are processing and get the QName of the parameter.
2282        if (isHeader && (bindingEntry.getBinding() != null)) {
2283            List list = bindingEntry.getBinding().getBindingOperations();
2284
2285            for (int i = 0; (list != null) && (i < list.size()); i++) {
2286                BindingOperation operation = (BindingOperation) list.get(i);
2287
2288                if (operation.getName().equals(opName)) {
2289                    if (param.isInHeader()) {
2290                        QName qName = getBindedParameterName(
2291                                operation.getBindingInput().getExtensibilityElements(),
2292                                param);
2293
2294                        if(qName!= null) {
2295                            param.setQName(qName);
2296                        }
2297                    } else if (param.isOutHeader()) {
2298                        QName qName = getBindedParameterName(
2299                                operation.getBindingOutput().getExtensibilityElements(),
2300                                param);
2301
2302                        if(qName!= null) {
2303                            param.setQName(qName);
2304                        }
2305                    }
2306                }
2307            }
2308        }
2309    }
2310
2311    /**
2312     * Method getBindedParameterName
2313     * 
2314     * @param elements 
2315     * @param p        
2316     * @return 
2317     */
2318    private QName getBindedParameterName(List elements, Parameter p) {
2319
2320        // If the parameter can either be in the message header or in the
2321        // message body.
2322        // When it is in the header, there may be a SOAPHeader (soap:header)
2323        // with its part name. The namespace used is the one of the soap:header.
2324        // When it is in the body, if there is a SOAPBody with its part name,
2325        // the namespace used is the one of this soap:body.
2326        // 
2327        // If the parameter is in the body and there is a soap:body with no parts,
2328        // its namespace is used for the parameter.
2329        QName paramName = null;
2330        String defaultNamespace = null;
2331        String parameterPartName = p.getName();
2332
2333        for (Iterator k = elements.iterator(); k.hasNext();) {
2334            ExtensibilityElement element = (ExtensibilityElement) k.next();
2335
2336            if (element instanceof SOAPBody) {
2337                SOAPBody bodyElement = (SOAPBody) element;
2338                List parts = bodyElement.getParts();
2339
2340                if ((parts == null) || (parts.size() == 0)) {
2341                    defaultNamespace = bodyElement.getNamespaceURI();
2342                } else {
2343                    boolean found = false;
2344
2345                    for (Iterator l = parts.iterator(); l.hasNext();) {
2346                        Object o = l.next();
2347
2348                        if(o instanceof String) {
2349                            if (parameterPartName.equals((String)o)) {
2350                                paramName =
2351                                        new QName(bodyElement.getNamespaceURI(),
2352                                                parameterPartName);
2353                                found = true;
2354                                break;
2355                            }
2356                        }
2357                    }
2358
2359                    if (found) {
2360                        break;
2361                    }
2362                }
2363            } else if (element instanceof SOAPHeader) {
2364                SOAPHeader headerElement = (SOAPHeader) element;
2365                String part = headerElement.getPart();
2366
2367                if (parameterPartName.equals(part)) {
2368                    paramName = new QName(headerElement.getNamespaceURI(),
2369                            parameterPartName);
2370                    break;
2371                }
2372            }
2373        }
2374
2375        if ((paramName == null) && (!p.isInHeader()) && (!p.isOutHeader())) {
2376            if (defaultNamespace != null) {
2377                paramName = new QName(defaultNamespace, parameterPartName);
2378            } else {
2379                paramName = p.getQName();
2380            }
2381        }
2382
2383        return paramName;
2384    }
2385
2386    /**
2387     * Set the MIME type.  This can be determine in one of two ways:
2388     * 1.  From WSDL 1.1 MIME constructs on the binding (passed in);
2389     * 2.  From AXIS-specific xml MIME types.
2390     * 
2391     * @param p        
2392     * @param mimeInfo 
2393     */
2394    private void setMIMEInfo(Parameter p, MimeInfo mimeInfo) {
2395
2396        // If there is no binding MIME construct (ie., the mimeType parameter is
2397        // null), then get the MIME type from the AXIS-specific xml MIME type.
2398        if (mimeInfo == null && p.getType() != null) {
2399            QName mimeQName = p.getType().getQName();
2400
2401            if (mimeQName.getNamespaceURI().equals(Constants.NS_URI_XMLSOAP)) {
2402                if (Constants.MIME_IMAGE.equals(mimeQName)) {
2403                    mimeInfo = new MimeInfo("image/jpeg", "");
2404                } else if (Constants.MIME_PLAINTEXT.equals(mimeQName)) {
2405                    mimeInfo = new MimeInfo("text/plain", "");
2406                } else if (Constants.MIME_MULTIPART.equals(mimeQName)) {
2407                    mimeInfo = new MimeInfo("multipart/related", "");
2408                } else if (Constants.MIME_SOURCE.equals(mimeQName)) {
2409                    mimeInfo = new MimeInfo("text/xml", "");
2410                } else if (Constants.MIME_OCTETSTREAM.equals(mimeQName)) {
2411                    mimeInfo = new MimeInfo("application/octet-stream", "");
2412                }
2413            }
2414        }
2415
2416        p.setMIMEInfo(mimeInfo);
2417    }    // setMIMEType
2418
2419    /**
2420     * Populate the symbol table with all of the BindingEntry's from the Definition.
2421     * 
2422     * @param def 
2423     * @throws IOException 
2424     */
2425    private void populateBindings(Definition def) throws IOException {
2426
2427        Iterator i = def.getBindings().values().iterator();
2428
2429        while (i.hasNext()) {
2430            Binding binding = (Binding) i.next();
2431            BindingEntry bEntry = new BindingEntry(binding);
2432
2433            symbolTablePut(bEntry);
2434
2435            Iterator extensibilityElementsIterator =
2436                    binding.getExtensibilityElements().iterator();
2437
2438            while (extensibilityElementsIterator.hasNext()) {
2439                Object obj = extensibilityElementsIterator.next();
2440
2441                if (obj instanceof SOAPBinding) {
2442                    bEntry.setBindingType(BindingEntry.TYPE_SOAP);
2443
2444                    SOAPBinding sb = (SOAPBinding) obj;
2445                    String style = sb.getStyle();
2446
2447                    if ("rpc".equalsIgnoreCase(style)) {
2448                        bEntry.setBindingStyle(Style.RPC);
2449                    }
2450                } else if (obj instanceof HTTPBinding) {
2451                    HTTPBinding hb = (HTTPBinding) obj;
2452
2453                    if (hb.getVerb().equalsIgnoreCase("post")) {
2454                        bEntry.setBindingType(BindingEntry.TYPE_HTTP_POST);
2455                    } else {
2456                        bEntry.setBindingType(BindingEntry.TYPE_HTTP_GET);
2457                    }
2458                } else if (obj instanceof UnknownExtensibilityElement) {
2459
2460                    // TODO: After WSDL4J supports soap12, change this code
2461                    UnknownExtensibilityElement unkElement =
2462                            (UnknownExtensibilityElement) obj;
2463                    QName name =
2464                            unkElement.getElementType();
2465
2466                    if (name.getNamespaceURI().equals(Constants.URI_WSDL12_SOAP)
2467                            && name.getLocalPart().equals("binding")) {
2468                        bEntry.setBindingType(BindingEntry.TYPE_SOAP);
2469
2470                        String style =
2471                                unkElement.getElement().getAttribute("style");
2472
2473                        if ("rpc".equalsIgnoreCase(style)) {
2474                            bEntry.setBindingStyle(Style.RPC);
2475                        }
2476                    }
2477                }
2478            }
2479
2480            // Step through the binding operations, setting the following as appropriate:
2481            // - hasLiteral
2482            // - body types
2483            // - mimeTypes
2484            // - headers
2485            HashMap attributes = new HashMap();
2486            List bindList = binding.getBindingOperations();
2487            HashMap faultMap = new HashMap();    // name to SOAPFault from WSDL4J
2488
2489            for (Iterator opIterator = bindList.iterator();
2490                 opIterator.hasNext();) {
2491                BindingOperation bindOp =
2492                        (BindingOperation) opIterator.next();
2493                Operation operation = bindOp.getOperation();
2494                BindingInput bindingInput = bindOp.getBindingInput();
2495                BindingOutput bindingOutput = bindOp.getBindingOutput();
2496                String opName = bindOp.getName();
2497
2498                // First, make sure the binding operation matches a portType operation
2499                String inputName = (bindingInput == null)
2500                        ? null
2501                        : bindingInput.getName();
2502                String outputName = (bindingOutput == null)
2503                        ? null
2504                        : bindingOutput.getName();
2505
2506                if (binding.getPortType().getOperation(
2507                        opName, inputName, outputName) == null) {
2508                    throw new IOException(Messages.getMessage("unmatchedOp",
2509                            new String[]{
2510                                opName,
2511                                inputName,
2512                                outputName}));
2513                }
2514
2515                ArrayList faults = new ArrayList();
2516
2517                // input
2518                if (bindingInput != null) {
2519                    if (bindingInput.getExtensibilityElements() != null) {
2520                        Iterator inIter =
2521                                bindingInput.getExtensibilityElements().iterator();
2522
2523                        fillInBindingInfo(bEntry, operation, inIter, faults,
2524                                true);
2525                    }
2526                }
2527
2528                // output
2529                if (bindingOutput != null) {
2530                    if (bindingOutput.getExtensibilityElements() != null) {
2531                        Iterator outIter =
2532                                bindingOutput.getExtensibilityElements().iterator();
2533
2534                        fillInBindingInfo(bEntry, operation, outIter, faults,
2535                                false);
2536                    }
2537                }
2538
2539                // faults
2540                faultsFromSOAPFault(binding, bindOp, operation, faults);
2541
2542                // Add this fault name and info to the map
2543                faultMap.put(bindOp, faults);
2544
2545                Use inputBodyType = bEntry.getInputBodyType(operation);
2546                Use outputBodyType = bEntry.getOutputBodyType(operation);
2547
2548                // Associate the portType operation that goes with this binding
2549                // with the body types.
2550                attributes.put(bindOp.getOperation(),
2551                        new BindingEntry.OperationAttr(inputBodyType,
2552                                outputBodyType, faultMap));
2553
2554                // If the input or output body uses literal, flag the binding as using literal.
2555                // NOTE:  should I include faultBodyType in this check?
2556                if ((inputBodyType == Use.LITERAL)
2557                        || (outputBodyType == Use.LITERAL)) {
2558                    bEntry.setHasLiteral(true);
2559                }
2560
2561                bEntry.setFaultBodyTypeMap(operation, faultMap);
2562            }    // binding operations
2563
2564            bEntry.setFaults(faultMap);
2565        }
2566    }            // populateBindings
2567
2568    /**
2569     * Fill in some binding information:  bodyType, mimeType, header info.
2570     * 
2571     * @param bEntry    
2572     * @param operation 
2573     * @param it        
2574     * @param faults    
2575     * @param input     
2576     * @throws IOException 
2577     */
2578    private void fillInBindingInfo(
2579            BindingEntry bEntry, Operation operation, Iterator it, ArrayList faults, boolean input)
2580            throws IOException {
2581
2582        for (; it.hasNext();) {
2583            Object obj = it.next();
2584
2585            if (obj instanceof SOAPBody) {
2586                setBodyType(((SOAPBody) obj).getUse(), bEntry, operation,
2587                        input);
2588            } else if (obj instanceof SOAPHeader) {
2589                SOAPHeader header = (SOAPHeader) obj;
2590
2591                setBodyType(header.getUse(), bEntry, operation, input);
2592
2593                // Note, this only works for explicit headers - those whose
2594                // parts come from messages used in the portType's operation
2595                // input/output clauses - it does not work for implicit
2596                // headers - those whose parts come from messages not used in
2597                // the portType's operation's input/output clauses.  I don't
2598                // know what we're supposed to emit for implicit headers.
2599                bEntry.setHeaderPart(operation.getName(), header.getPart(),
2600                        input
2601                        ? BindingEntry.IN_HEADER
2602                        : BindingEntry.OUT_HEADER);
2603
2604                // Add any soap:headerFault info to the faults array
2605                Iterator headerFaults = header.getSOAPHeaderFaults().iterator();
2606
2607                while (headerFaults.hasNext()) {
2608                    SOAPHeaderFault headerFault =
2609                            (SOAPHeaderFault) headerFaults.next();
2610
2611                    faults.add(new FaultInfo(headerFault, this));
2612                }
2613            } else if (obj instanceof MIMEMultipartRelated) {
2614                bEntry.setBodyType(
2615                        operation,
2616                        addMIMETypes(
2617                                bEntry, (MIMEMultipartRelated) obj, operation), input);
2618            } else if (obj instanceof UnknownExtensibilityElement) {
2619                UnknownExtensibilityElement unkElement =
2620                        (UnknownExtensibilityElement) obj;
2621                QName name =
2622                        unkElement.getElementType();
2623
2624                if (name.getNamespaceURI().equals(Constants.URI_DIME_WSDL)
2625                        && name.getLocalPart().equals("message")) {
2626                    fillInDIMEInformation(unkElement, input, operation, bEntry);
2627                }
2628
2629                // TODO: After WSDL4J supports soap12, change this code
2630                if (name.getNamespaceURI().equals(Constants.URI_WSDL12_SOAP)
2631                        && name.getLocalPart().equals("body")) {
2632                    setBodyType(unkElement.getElement().getAttribute("use"),
2633                            bEntry, operation, input);
2634                }
2635
2636                // TODO: After WSDL4J supports soap12, change this code
2637                if (name.getNamespaceURI().equals(Constants.URI_WSDL12_SOAP)
2638                        && name.getLocalPart().equals("header")) {
2639                    setBodyType(unkElement.getElement().getAttribute("use"),
2640                            bEntry, operation, input);
2641
2642                    // Note, this only works for explicit headers - those whose
2643                    // parts come from messages used in the portType's operation
2644                    // input/output clauses - it does not work for implicit
2645                    // headers - those whose parts come from messages not used in
2646                    // the portType's operation's input/output clauses.  I don't
2647                    // know what we're supposed to emit for implicit headers.
2648                    bEntry.setHeaderPart(
2649                            operation.getName(),
2650                            unkElement.getElement().getAttribute("part"), input
2651                            ? BindingEntry.IN_HEADER
2652                            : BindingEntry.OUT_HEADER);
2653
2654                    // Add any soap12:headerFault info to the faults array
2655                    NodeList headerFaults =
2656                            unkElement.getElement().getChildNodes();
2657
2658                    for (int i = 0; i < headerFaults.getLength(); i++) {
2659                        String faultMessage =
2660                                unkElement.getElement().getAttribute("message");
2661                        String faultPart =
2662                                unkElement.getElement().getAttribute("part");
2663                        String faultUse =
2664                                unkElement.getElement().getAttribute("use");
2665                        String faultNamespaceURI =
2666                                unkElement.getElement().getAttribute("namespace");
2667                        QName faultMessageQName = null;
2668                        int sep = faultMessage.indexOf(':');
2669
2670                        if (sep == -1) {
2671                            faultMessageQName = new QName(faultMessage);
2672                        } else {
2673                            faultMessageQName =
2674                                    new QName(faultMessage.substring(0, sep),
2675                                            faultMessage.substring(sep + 1));
2676                        }
2677
2678                        faults.add(new FaultInfo(faultMessageQName, faultPart,
2679                                faultUse, faultNamespaceURI,
2680                                this));
2681                    }
2682                }
2683            }
2684        }
2685    }    // fillInBindingInfo
2686
2687    /**
2688     * Fill in DIME information
2689     * 
2690     * @param unkElement 
2691     * @param input      
2692     * @param operation  
2693     * @param bEntry     
2694     */
2695    private void fillInDIMEInformation(UnknownExtensibilityElement unkElement,
2696                                       boolean input, Operation operation,
2697                                       BindingEntry bEntry) {
2698
2699        String layout = unkElement.getElement().getAttribute("layout");
2700
2701        // TODO: what to do with layout info?
2702        if (layout.equals(Constants.URI_DIME_CLOSED_LAYOUT)) {
2703        } else if (layout.equals(Constants.URI_DIME_OPEN_LAYOUT)) {
2704        }
2705
2706        Map parts = null;
2707
2708        if (input) {
2709            parts = operation.getInput().getMessage().getParts();
2710        } else {
2711            parts = operation.getOutput().getMessage().getParts();
2712        }
2713
2714        if (parts != null) {
2715            Iterator iterator = parts.values().iterator();
2716
2717            while (iterator.hasNext()) {
2718                Part part = (Part) iterator.next();
2719
2720                if (part != null) {
2721                    String dims = "";
2722                    org.w3c.dom.Element element = null;
2723
2724                    if (part.getTypeName() != null) {
2725                        TypeEntry partType = getType(part.getTypeName());
2726
2727                        if (partType.getDimensions().length() > 0) {
2728                            dims = partType.getDimensions();
2729                            partType = partType.getRefType();
2730                        }
2731
2732                        element = (org.w3c.dom.Element) partType.getNode();
2733                    } else if (part.getElementName() != null) {
2734                        TypeEntry partElement =
2735                                getElement(part.getElementName()).getRefType();
2736
2737                        element = (org.w3c.dom.Element) partElement.getNode();
2738
2739                        QName name = getInnerCollectionComponentQName(element);
2740
2741                        if (name != null) {
2742                            dims += "[]";
2743                            partElement = getType(name);
2744                            element =
2745                                    (org.w3c.dom.Element) partElement.getNode();
2746                        } else {
2747                            name = getInnerTypeQName(element);
2748
2749                            if (name != null) {
2750                                partElement = getType(name);
2751                                element =
2752                                        (org.w3c.dom.Element) partElement.getNode();
2753                            }
2754                        }
2755                    }
2756
2757                    if (element != null) {
2758                        org.w3c.dom.Element e =
2759                                (org.w3c.dom.Element) XMLUtils.findNode(
2760                                        element,
2761                                        new QName(
2762                                                Constants.URI_DIME_CONTENT, "mediaType"));
2763
2764                        if (e != null) {
2765                            String value = e.getAttribute("value");
2766
2767                            bEntry.setOperationDIME(operation.getName());
2768                            bEntry.setMIMEInfo(operation.getName(),
2769                                    part.getName(), value, dims);
2770                        }
2771                    }
2772                }
2773            }
2774        }
2775    }
2776
2777    /**
2778     * Get the faults from the soap:fault clause.
2779     * 
2780     * @param binding   
2781     * @param bindOp    
2782     * @param operation 
2783     * @param faults    
2784     * @throws IOException 
2785     */
2786    private void faultsFromSOAPFault(
2787            Binding binding, BindingOperation bindOp, Operation operation, ArrayList faults)
2788            throws IOException {
2789
2790        Iterator faultMapIter = bindOp.getBindingFaults().values().iterator();
2791
2792        for (; faultMapIter.hasNext();) {
2793            BindingFault bFault = (BindingFault) faultMapIter.next();
2794
2795            // Set default entry for this fault
2796            String faultName = bFault.getName();
2797
2798            // Check to make sure this fault is named
2799            if ((faultName == null) || (faultName.length() == 0)) {
2800                throw new IOException(
2801                        Messages.getMessage(
2802                                "unNamedFault00", bindOp.getName(),
2803                                binding.getQName().toString()));
2804            }
2805
2806            boolean foundSOAPFault = false;
2807            String soapFaultUse = "";
2808            String soapFaultNamespace = "";
2809            Iterator faultIter =
2810                    bFault.getExtensibilityElements().iterator();
2811
2812            for (; faultIter.hasNext();) {
2813                Object obj = faultIter.next();
2814
2815                if (obj instanceof SOAPFault) {
2816                    foundSOAPFault = true;
2817                    soapFaultUse = ((SOAPFault) obj).getUse();
2818                    soapFaultNamespace = ((SOAPFault) obj).getNamespaceURI();
2819
2820                    break;
2821                } else if (obj instanceof UnknownExtensibilityElement) {
2822
2823                    // TODO: After WSDL4J supports soap12, change this code
2824                    UnknownExtensibilityElement unkElement =
2825                            (UnknownExtensibilityElement) obj;
2826                    QName name =
2827                            unkElement.getElementType();
2828
2829                    if (name.getNamespaceURI().equals(Constants.URI_WSDL12_SOAP)
2830                            && name.getLocalPart().equals("fault")) {
2831                        if (unkElement.getElement().getAttribute("use")
2832                                != null) {
2833                            soapFaultUse =
2834                                    unkElement.getElement().getAttribute("use");
2835                        }
2836
2837                        if (unkElement.getElement().getAttribute("namespace")
2838                                != null) {
2839                            soapFaultNamespace =
2840                                    unkElement.getElement().getAttribute(
2841                                            "namespace");
2842                        }
2843                    }
2844                }
2845            }
2846
2847            // Check to make sure we have a soap:fault element
2848            if (!foundSOAPFault) {
2849                throw new IOException(
2850                        Messages.getMessage(
2851                                "missingSoapFault00", faultName, bindOp.getName(),
2852                                binding.getQName().toString()));
2853            }
2854
2855            // TODO error checking:
2856            // if use=literal, no use of namespace on the soap:fault
2857            // if use=encoded, no use of element on the part
2858            // Check this fault to make sure it matches the one
2859            // in the matching portType Operation
2860            Fault opFault = operation.getFault(bFault.getName());
2861
2862            if (opFault == null) {
2863                throw new IOException(Messages.getMessage("noPortTypeFault",
2864                        new String[]{
2865                            bFault.getName(),
2866                            bindOp.getName(),
2867                            binding.getQName().toString()}));
2868            }
2869
2870            // put the updated entry back in the map
2871            faults.add(new FaultInfo(opFault, Use.getUse(soapFaultUse),
2872                    soapFaultNamespace, this));
2873        }
2874    }    // faultsFromSOAPFault
2875
2876    /**
2877     * Set the body type.
2878     * 
2879     * @param use       
2880     * @param bEntry    
2881     * @param operation 
2882     * @param input     
2883     */
2884    private void setBodyType(String use,
2885                             BindingEntry bEntry,
2886                             Operation operation,
2887                             boolean input)
2888    {
2889
2890        if (use == null) {
2891            // Deprecated 
2892            // throw new IOException(Messages.getMessage("noUse",
2893            //        operation.getName()));
2894            // for WS-I BP 1.0 R2707.
2895            // Set default of use to literal.
2896            use = "literal";
2897        }
2898
2899        if (use.equalsIgnoreCase("literal")) {
2900            bEntry.setBodyType(operation, Use.LITERAL, input);
2901        }
2902    }    // setBodyType
2903
2904    /**
2905     * Add the parts that are really MIME types as MIME types.
2906     * A side effect is to return the body Type of the given
2907     * MIMEMultipartRelated object.
2908     * 
2909     * @param bEntry 
2910     * @param mpr    
2911     * @param op     
2912     * @return 
2913     * @throws IOException 
2914     */
2915    private Use addMIMETypes(
2916            BindingEntry bEntry, MIMEMultipartRelated mpr, Operation op)
2917            throws IOException {
2918
2919        Use bodyType = Use.ENCODED;
2920        List parts = mpr.getMIMEParts();
2921        Iterator i = parts.iterator();
2922
2923        while (i.hasNext()) {
2924            MIMEPart part = (MIMEPart) i.next();
2925            List elems = part.getExtensibilityElements();
2926            Iterator j = elems.iterator();
2927
2928            while (j.hasNext()) {
2929                Object obj = j.next();
2930
2931                if (obj instanceof MIMEContent) {
2932                    MIMEContent content = (MIMEContent) obj;
2933                    TypeEntry typeEntry = findPart(op, content.getPart());
2934                    if (typeEntry == null) {
2935                        throw new RuntimeException(Messages.getMessage("cannotFindPartForOperation00", content.getPart(),
2936                                op.getName(), content.getType()));
2937                    }
2938                    String dims = typeEntry.getDimensions();
2939
2940                    if ((dims.length() <= 0)
2941                            && (typeEntry.getRefType() != null)) {
2942                        Node node = typeEntry.getRefType().getNode();
2943
2944                        if (getInnerCollectionComponentQName(node) != null) {
2945                            dims += "[]";
2946                        }
2947                    }
2948
2949                    String type = content.getType();
2950
2951                    if ((type == null) || (type.length() == 0)) {
2952                        type = "text/plain";
2953                    }
2954
2955                    bEntry.setMIMEInfo(op.getName(), content.getPart(), type,
2956                            dims);
2957                } else if (obj instanceof SOAPBody) {
2958                    String use = ((SOAPBody) obj).getUse();
2959
2960                    if (use == null) {
2961                        throw new IOException(
2962                                Messages.getMessage("noUse", op.getName()));
2963                    }
2964
2965                    if (use.equalsIgnoreCase("literal")) {
2966                        bodyType = Use.LITERAL;
2967                    }
2968                } else if (obj instanceof UnknownExtensibilityElement) {
2969
2970                    // TODO: After WSDL4J supports soap12, change this code
2971                    UnknownExtensibilityElement unkElement =
2972                            (UnknownExtensibilityElement) obj;
2973                    QName name =
2974                            unkElement.getElementType();
2975
2976                    if (name.getNamespaceURI().equals(Constants.URI_WSDL12_SOAP)
2977                            && name.getLocalPart().equals("body")) {
2978                        String use =
2979                                unkElement.getElement().getAttribute("use");
2980
2981                        if (use == null) {
2982                            throw new IOException(
2983                                    Messages.getMessage("noUse", op.getName()));
2984                        }
2985
2986                        if (use.equalsIgnoreCase("literal")) {
2987                            bodyType = Use.LITERAL;
2988                        }
2989                    }
2990                }
2991            }
2992        }
2993
2994        return bodyType;
2995    }    // addMIMETypes
2996
2997    /**
2998     * Method findPart
2999     * 
3000     * @param operation 
3001     * @param partName  
3002     * @return 
3003     */
3004    private TypeEntry findPart(Operation operation, String partName) {
3005
3006        Map parts = operation.getInput().getMessage().getParts();
3007        Iterator iterator = parts.values().iterator();
3008        TypeEntry part = findPart(iterator, partName);
3009
3010        if (part == null) {
3011            parts = operation.getOutput().getMessage().getParts();
3012            iterator = parts.values().iterator();
3013            part = findPart(iterator, partName);
3014        }
3015
3016        return part;
3017    }
3018
3019    /**
3020     * Method findPart
3021     * 
3022     * @param iterator 
3023     * @param partName 
3024     * @return 
3025     */
3026    private TypeEntry findPart(Iterator iterator, String partName) {
3027
3028        while (iterator.hasNext()) {
3029            Part part = (Part) iterator.next();
3030
3031            if (part != null) {
3032                String typeName = part.getName();
3033
3034                if (partName.equals(typeName)) {
3035                    if (part.getTypeName() != null) {
3036                        return getType(part.getTypeName());
3037                    } else if (part.getElementName() != null) {
3038                        return getElement(part.getElementName());
3039                    }
3040                }
3041            }
3042        }
3043
3044        return null;
3045    }
3046
3047    /**
3048     * Populate the symbol table with all of the ServiceEntry's from the Definition.
3049     * 
3050     * @param def 
3051     * @throws IOException 
3052     */
3053    private void populateServices(Definition def) throws IOException {
3054
3055        Iterator i = def.getServices().values().iterator();
3056
3057        while (i.hasNext()) {
3058            Service service = (Service) i.next();
3059
3060            // do a bit of name validation
3061            if ((service.getQName() == null)
3062                    || (service.getQName().getLocalPart() == null)
3063                    || service.getQName().getLocalPart().equals("")) {
3064                throw new IOException(Messages.getMessage("BadServiceName00"));
3065            }
3066
3067            ServiceEntry sEntry = new ServiceEntry(service);
3068
3069            symbolTablePut(sEntry);
3070            populatePorts(service.getPorts());
3071        }
3072    }    // populateServices
3073
3074    /**
3075     * populates the symbol table with port elements defined within a &lt;service&gt;
3076     * element.
3077     * 
3078     * @param ports a map of name->port pairs (i.e. what is returned by service.getPorts()
3079     * @throws IOException thrown, if an IO or WSDL error is detected
3080     * @see javax.wsdl.Service#getPorts()
3081     * @see javax.wsdl.Port
3082     */
3083    private void populatePorts(Map ports) throws IOException {
3084
3085        if (ports == null) {
3086            return;
3087        }
3088
3089        Iterator it = ports.values().iterator();
3090
3091        while (it.hasNext()) {
3092            Port port = (Port) it.next();
3093            String portName = port.getName();
3094            Binding portBinding = port.getBinding();
3095
3096            // make sure there is a port name. The 'name' attribute for WSDL ports is
3097            // mandatory
3098            // 
3099            if (portName == null) {
3100
3101                // REMIND: should rather be a javax.wsdl.WSDLException ?
3102                throw new IOException(
3103                        Messages.getMessage("missingPortNameException"));
3104            }
3105
3106            // make sure there is a binding for the port. The 'binding' attribute for
3107            // WSDL ports is mandatory
3108            // 
3109            if (portBinding == null) {
3110
3111                // REMIND: should rather be a javax.wsdl.WSDLException ?
3112                throw new IOException(
3113                        Messages.getMessage("missingBindingException"));
3114            }
3115
3116            // make sure the port name is unique among all port names defined in this
3117            // WSDL document.
3118            // 
3119            // NOTE: there's a flaw in com.ibm.wsdl.xml.WSDLReaderImpl#parsePort() and
3120            // com.ibm.wsdl.xml.WSDLReaderImpl#addPort(). These methods do not enforce
3121            // the port name exists and is unique. Actually, if two port definitions with
3122            // the same name exist within the same service element, only *one* port
3123            // element is present after parsing and the following exception is not thrown.
3124            // 
3125            // If two ports with the same name exist in different service elements,
3126            // the exception below is thrown. This is conformant to the WSDL 1.1 spec (sec 2.6)
3127            // , which states: "The name attribute provides a unique name among all ports
3128            // defined within in the enclosing WSDL document."
3129            // 
3130            // 
3131            if (existsPortWithName(new QName(portName))) {
3132
3133                // REMIND: should rather be a javax.wsdl.WSDLException ?
3134                throw new IOException(
3135                        Messages.getMessage("twoPortsWithSameName", portName));
3136            }
3137
3138            PortEntry portEntry = new PortEntry(port);
3139
3140            symbolTablePut(portEntry);
3141        }
3142    }
3143
3144    /**
3145     * Set each SymTabEntry's isReferenced flag.  The default is false.  If no other symbol
3146     * references this symbol, then leave it false, otherwise set it to true.
3147     * (An exception to the rule is that derived types are set as referenced if
3148     * their base type is referenced.  This is necessary to support generation and
3149     * registration of derived types.)
3150     * 
3151     * @param def 
3152     * @param doc 
3153     */
3154    private void setReferences(Definition def, Document doc) {
3155
3156        Map stuff = def.getServices();
3157
3158        if (stuff.isEmpty()) {
3159            stuff = def.getBindings();
3160
3161            if (stuff.isEmpty()) {
3162                stuff = def.getPortTypes();
3163
3164                if (stuff.isEmpty()) {
3165                    stuff = def.getMessages();
3166
3167                    if (stuff.isEmpty()) {
3168                        for (Iterator i = elementTypeEntries.values().iterator();
3169                             i.hasNext();) {
3170                            setTypeReferences((TypeEntry) i.next(), doc, false);
3171                        }
3172
3173                        for (Iterator i = typeTypeEntries.values().iterator();
3174                             i.hasNext();) {
3175                            setTypeReferences((TypeEntry) i.next(), doc, false);
3176                        }
3177                    } else {
3178                        Iterator i = stuff.values().iterator();
3179
3180                        while (i.hasNext()) {
3181                            Message message = (Message) i.next();
3182                            MessageEntry mEntry =
3183                                    getMessageEntry(message.getQName());
3184
3185                            setMessageReferences(mEntry, def, doc, false);
3186                        }
3187                    }
3188                } else {
3189                    Iterator i = stuff.values().iterator();
3190
3191                    while (i.hasNext()) {
3192                        PortType portType = (PortType) i.next();
3193                        PortTypeEntry ptEntry =
3194                                getPortTypeEntry(portType.getQName());
3195
3196                        setPortTypeReferences(ptEntry, null, def, doc);
3197                    }
3198                }
3199            } else {
3200                Iterator i = stuff.values().iterator();
3201
3202                while (i.hasNext()) {
3203                    Binding binding = (Binding) i.next();
3204                    BindingEntry bEntry = getBindingEntry(binding.getQName());
3205
3206                    setBindingReferences(bEntry, def, doc);
3207                }
3208            }
3209        } else {
3210            Iterator i = stuff.values().iterator();
3211
3212            while (i.hasNext()) {
3213                Service service = (Service) i.next();
3214                ServiceEntry sEntry = getServiceEntry(service.getQName());
3215
3216                setServiceReferences(sEntry, def, doc);
3217            }
3218        }
3219    }    // setReferences
3220
3221    /**
3222     * Set the isReferenced flag to true on the given TypeEntry and all
3223     * SymTabEntries that it refers to.
3224     * 
3225     * @param entry   
3226     * @param doc     
3227     * @param literal 
3228     */
3229    private void setTypeReferences(TypeEntry entry, Document doc,
3230                                   boolean literal) {
3231
3232        // Check to see if already processed.
3233        if ((entry.isReferenced() && !literal)
3234                || (entry.isOnlyLiteralReferenced() && literal)) {
3235            return;
3236        }
3237
3238        if (wrapped) {
3239
3240            // If this type is ONLY referenced from a literal usage in a binding,
3241            // then isOnlyLiteralReferenced should return true.
3242            if (!entry.isReferenced() && literal) {
3243                entry.setOnlyLiteralReference(true);
3244            }
3245
3246            // If this type was previously only referenced as a literal type,
3247            // but now it is referenced in a non-literal manner, turn off the
3248            // onlyLiteralReference flag.
3249            else if (entry.isOnlyLiteralReferenced() && !literal) {
3250                entry.setOnlyLiteralReference(false);
3251            }
3252        }
3253
3254        // If we don't want to emit stuff from imported files, only set the
3255        // isReferenced flag if this entry exists in the immediate WSDL file.
3256        Node node = entry.getNode();
3257
3258        if (addImports || (node == null) || (node.getOwnerDocument() == doc)) {
3259            entry.setIsReferenced(true);
3260
3261            if (entry instanceof DefinedElement) {
3262                BooleanHolder forElement = new BooleanHolder();
3263                QName referentName = Utils.getTypeQName(node,
3264                        forElement, false);
3265
3266                if (referentName != null) {
3267                    TypeEntry referent = getTypeEntry(referentName,
3268                            forElement.value);
3269
3270                    if (referent != null) {
3271                        setTypeReferences(referent, doc, literal);
3272                    }
3273                }
3274
3275                // If the Defined Element has an anonymous type,
3276                // process it with the current literal flag setting.
3277                QName anonQName =
3278                        SchemaUtils.getElementAnonQName(entry.getNode());
3279
3280                if (anonQName != null) {
3281                    TypeEntry anonType = getType(anonQName);
3282
3283                    if (anonType != null) {
3284                        setTypeReferences(anonType, doc, literal);
3285
3286                        return;
3287                    }
3288                }
3289            }
3290        }
3291
3292        HashSet nestedTypes = entry.getNestedTypes(this, true);
3293        Iterator it = nestedTypes.iterator();
3294
3295        while (it.hasNext()) {
3296            TypeEntry nestedType = (TypeEntry) it.next();
3297            TypeEntry refType = entry.getRefType();
3298
3299            if (nestedType == null) {
3300              continue;
3301            }
3302
3303            // If this entry has a referenced type that isn't
3304            // the same as the nested type
3305            // AND the OnlyLiteral reference switch is on
3306            // THEN turn the OnlyLiteral reference switch off.
3307            // If only someone had put a comment here saying why we do this...
3308            if ((refType != null)
3309                    && !refType.equals(nestedType)
3310                    && nestedType.isOnlyLiteralReferenced()) {
3311                nestedType.setOnlyLiteralReference(false);
3312            }
3313
3314            if (!nestedType.isReferenced()) {
3315
3316                // setTypeReferences(nestedType, doc, literal);
3317                if (nestedType != entry) {
3318                    setTypeReferences(nestedType, doc, false);
3319                }
3320            }
3321        }
3322    }    // setTypeReferences
3323
3324    /**
3325     * Set the isReferenced flag to true on the given MessageEntry and all
3326     * SymTabEntries that it refers to.
3327     * 
3328     * @param entry   
3329     * @param def     
3330     * @param doc     
3331     * @param literal 
3332     */
3333    private void setMessageReferences(MessageEntry entry, Definition def,
3334                                      Document doc, boolean literal) {
3335
3336        // If we don't want to emit stuff from imported files, only set the
3337        // isReferenced flag if this entry exists in the immediate WSDL file.
3338        Message message = entry.getMessage();
3339
3340        if (addImports) {
3341            entry.setIsReferenced(true);
3342        } else {
3343
3344            // NOTE:  I thought I could have simply done:
3345            // if (def.getMessage(message.getQName()) != null)
3346            // but that method traces through all imported messages.
3347            Map messages = def.getMessages();
3348
3349            if (messages.containsValue(message)) {
3350                entry.setIsReferenced(true);
3351            }
3352        }
3353
3354        // Set all the message's types
3355        Iterator parts = message.getParts().values().iterator();
3356
3357        while (parts.hasNext()) {
3358            Part part = (Part) parts.next();
3359            TypeEntry type = getType(part.getTypeName());
3360
3361            if (type != null) {
3362                setTypeReferences(type, doc, literal);
3363            }
3364
3365            type = getElement(part.getElementName());
3366
3367            if (type != null) {
3368                setTypeReferences(type, doc, literal);
3369
3370                TypeEntry refType = type.getRefType();
3371
3372                if (refType != null) {
3373                    setTypeReferences(refType, doc, literal);
3374                }
3375            }
3376        }
3377    }    // setMessageReference
3378
3379    /**
3380     * Set the isReferenced flag to true on the given PortTypeEntry and all
3381     * SymTabEntries that it refers to.
3382     * 
3383     * @param entry  
3384     * @param bEntry 
3385     * @param def    
3386     * @param doc    
3387     */
3388    private void setPortTypeReferences(PortTypeEntry entry,
3389                                       BindingEntry bEntry, Definition def,
3390                                       Document doc) {
3391
3392        // If we don't want to emit stuff from imported files, only set the
3393        // isReferenced flag if this entry exists in the immediate WSDL file.
3394        PortType portType = entry.getPortType();
3395
3396        if (addImports) {
3397            entry.setIsReferenced(true);
3398        } else {
3399
3400            // NOTE:  I thought I could have simply done:
3401            // if (def.getPortType(portType.getQName()) != null)
3402            // but that method traces through all imported portTypes.
3403            Map portTypes = def.getPortTypes();
3404
3405            if (portTypes.containsValue(portType)) {
3406                entry.setIsReferenced(true);
3407            }
3408        }
3409
3410        // Set all the portType's messages
3411        Iterator operations = portType.getOperations().iterator();
3412
3413        // For each operation, query its input, output, and fault messages
3414        while (operations.hasNext()) {
3415            Operation operation = (Operation) operations.next();
3416            Input input = operation.getInput();
3417            Output output = operation.getOutput();
3418
3419            // Find out if this reference is a literal reference or not.
3420            boolean literalInput = false;
3421            boolean literalOutput = false;
3422
3423            if (bEntry != null) {
3424                literalInput = bEntry.getInputBodyType(operation)
3425                        == Use.LITERAL;
3426                literalOutput = bEntry.getOutputBodyType(operation)
3427                        == Use.LITERAL;
3428            }
3429
3430            // Query the input message
3431            if (input != null) {
3432                Message message = input.getMessage();
3433
3434                if (message != null) {
3435                    MessageEntry mEntry = getMessageEntry(message.getQName());
3436
3437                    if (mEntry != null) {
3438                        setMessageReferences(mEntry, def, doc, literalInput);
3439                    }
3440                }
3441            }
3442
3443            // Query the output message
3444            if (output != null) {
3445                Message message = output.getMessage();
3446
3447                if (message != null) {
3448                    MessageEntry mEntry = getMessageEntry(message.getQName());
3449
3450                    if (mEntry != null) {
3451                        setMessageReferences(mEntry, def, doc, literalOutput);
3452                    }
3453                }
3454            }
3455
3456            // Query the fault messages
3457            Iterator faults = operation.getFaults().values().iterator();
3458
3459            while (faults.hasNext()) {
3460                Message message = ((Fault) faults.next()).getMessage();
3461
3462                if (message != null) {
3463                    MessageEntry mEntry = getMessageEntry(message.getQName());
3464
3465                    if (mEntry != null) {
3466                        setMessageReferences(mEntry, def, doc, false);
3467                    }
3468                }
3469            }
3470        }
3471    }    // setPortTypeReferences
3472
3473    /**
3474     * Set the isReferenced flag to true on the given BindingEntry and all
3475     * SymTabEntries that it refers to ONLY if this binding is a SOAP binding.
3476     * 
3477     * @param entry 
3478     * @param def   
3479     * @param doc   
3480     */
3481    private void setBindingReferences(BindingEntry entry, Definition def,
3482                                      Document doc) {
3483
3484        if (entry.getBindingType() == BindingEntry.TYPE_SOAP) {
3485
3486            // If we don't want to emit stuff from imported files, only set the
3487            // isReferenced flag if this entry exists in the immediate WSDL file.
3488            Binding binding = entry.getBinding();
3489
3490            if (addImports) {
3491                entry.setIsReferenced(true);
3492            } else {
3493
3494                // NOTE:  I thought I could have simply done:
3495                // if (def.getBindng(binding.getQName()) != null)
3496                // but that method traces through all imported bindings.
3497                Map bindings = def.getBindings();
3498
3499                if (bindings.containsValue(binding)) {
3500                    entry.setIsReferenced(true);
3501                }
3502            }
3503
3504            // Set all the binding's portTypes
3505            PortType portType = binding.getPortType();
3506            PortTypeEntry ptEntry = getPortTypeEntry(portType.getQName());
3507
3508            if (ptEntry != null) {
3509                setPortTypeReferences(ptEntry, entry, def, doc);
3510            }
3511        }
3512    }    // setBindingReferences
3513
3514    /**
3515     * Set the isReferenced flag to true on the given ServiceEntry and all
3516     * SymTabEntries that it refers to.
3517     * 
3518     * @param entry 
3519     * @param def   
3520     * @param doc   
3521     */
3522    private void setServiceReferences(ServiceEntry entry, Definition def,
3523                                      Document doc) {
3524
3525        // If we don't want to emit stuff from imported files, only set the
3526        // isReferenced flag if this entry exists in the immediate WSDL file.
3527        Service service = entry.getService();
3528
3529        if (addImports) {
3530            entry.setIsReferenced(true);
3531        } else {
3532
3533            // NOTE:  I thought I could have simply done:
3534            // if (def.getService(service.getQName()) != null)
3535            // but that method traces through all imported services.
3536            Map services = def.getServices();
3537
3538            if (services.containsValue(service)) {
3539                entry.setIsReferenced(true);
3540            }
3541        }
3542
3543        // Set all the service's bindings
3544        Iterator ports = service.getPorts().values().iterator();
3545
3546        while (ports.hasNext()) {
3547            Port port = (Port) ports.next();
3548            Binding binding = port.getBinding();
3549
3550            if (binding != null) {
3551                BindingEntry bEntry = getBindingEntry(binding.getQName());
3552
3553                if (bEntry != null) {
3554                    setBindingReferences(bEntry, def, doc);
3555                }
3556            }
3557        }
3558    }    // setServiceReferences
3559
3560    /**
3561     * Put the given SymTabEntry into the symbol table, if appropriate.
3562     * 
3563     * @param entry 
3564     * @throws IOException 
3565     */
3566    private SymTabEntry symbolTablePut(SymTabEntry entry) throws IOException {
3567
3568        QName name = entry.getQName();
3569
3570        SymTabEntry e = get(name, entry.getClass());
3571
3572        if (e == null) {
3573            e = entry;
3574
3575            // An entry of the given qname of the given type doesn't exist yet.
3576            if ((entry instanceof Type)
3577                    && (get(name, UndefinedType.class) != null)) {
3578
3579                // A undefined type exists in the symbol table, which means
3580                // that the type is used, but we don't yet have a definition for
3581                // the type.  Now we DO have a definition for the type, so
3582                // replace the existing undefined type with the real type.
3583                if (((TypeEntry) get(name, UndefinedType.class)).isSimpleType()
3584                        && !((TypeEntry) entry).isSimpleType()) {
3585
3586                    // Problem if the undefined type was used in a
3587                    // simple type context.
3588                    throw new IOException(
3589                            Messages.getMessage(
3590                                    "AttrNotSimpleType01", name.toString()));
3591                }
3592
3593                Vector v = (Vector) symbolTable.get(name);
3594
3595                for (int i = 0; i < v.size(); ++i) {
3596                    Object oldEntry = v.elementAt(i);
3597
3598                    if (oldEntry instanceof UndefinedType) {
3599
3600                        // Replace it in the symbol table
3601                        v.setElementAt(entry, i);
3602
3603                        // Replace it in the types index
3604                        typeTypeEntries.put(name, entry);
3605
3606                        // Update all of the entries that refer to the unknown type
3607                        ((UndefinedType) oldEntry).update((Type) entry);
3608                    }
3609                }
3610            } else if ((entry instanceof Element)
3611                    && (get(name, UndefinedElement.class) != null)) {
3612
3613                // A undefined element exists in the symbol table, which means
3614                // that the element is used, but we don't yet have a definition for
3615                // the element.  Now we DO have a definition for the element, so
3616                // replace the existing undefined element with the real element.
3617                Vector v = (Vector) symbolTable.get(name);
3618
3619                for (int i = 0; i < v.size(); ++i) {
3620                    Object oldEntry = v.elementAt(i);
3621
3622                    if (oldEntry instanceof UndefinedElement) {
3623
3624                        // Replace it in the symbol table
3625                        v.setElementAt(entry, i);
3626
3627                        // Replace it in the elements index
3628                        elementTypeEntries.put(name, entry);
3629
3630                        // Update all of the entries that refer to the unknown type
3631                        ((Undefined) oldEntry).update((Element) entry);
3632                    }
3633                }
3634            } else {
3635
3636                // Add this entry to the symbol table
3637                Vector v = (Vector) symbolTable.get(name);
3638
3639                if (v == null) {
3640                    v = new Vector();
3641
3642                    symbolTable.put(name, v);
3643                }
3644
3645                v.add(entry);
3646
3647                // add TypeEntries to specialized indices for
3648                // fast lookups during reference resolution.
3649                if (entry instanceof Element) {
3650                    elementTypeEntries.put(name, entry);
3651                } else if (entry instanceof Type) {
3652                    typeTypeEntries.put(name, entry);
3653                }
3654            }
3655        } else {
3656            if (!quiet) {
3657                System.out.println(Messages.getMessage("alreadyExists00",
3658                                                       "" + name));
3659            }
3660        }
3661
3662        return e;
3663    }    // symbolTablePut
3664
3665    /**
3666     * checks whether there exists a WSDL port with a given name in the current
3667     * symbol table
3668     * 
3669     * @param name the QName of the port. Note: only the local part of the qname is relevant,
3670     *             since port names are not qualified with a namespace. They are of type nmtoken in WSDL 1.1
3671     *             and of type ncname in WSDL 1.2
3672     * @return true, if there is a port element with the specified name; false, otherwise
3673     */
3674    protected boolean existsPortWithName(QName name) {
3675
3676        Vector v = (Vector) symbolTable.get(name);
3677
3678        if (v == null) {
3679            return false;
3680        }
3681
3682        Iterator it = v.iterator();
3683
3684        while (it.hasNext()) {
3685            Object o = it.next();
3686
3687            if (o instanceof PortEntry) {
3688                return true;
3689            }
3690        }
3691
3692        return false;
3693    }
3694
3695    /**
3696     * Method getInnerCollectionComponentQName
3697     * 
3698     * @param node 
3699     * @return 
3700     */
3701    private static QName getInnerCollectionComponentQName(Node node) {
3702
3703        if (node == null) {
3704            return null;
3705        }
3706
3707        QName name = SchemaUtils.getCollectionComponentQName(node, new QNameHolder());
3708
3709        if (name != null) {
3710            return name;
3711        }
3712
3713        // Dive into the node if necessary
3714        NodeList children = node.getChildNodes();
3715
3716        for (int i = 0; i < children.getLength(); i++) {
3717            name = getInnerCollectionComponentQName(children.item(i));
3718
3719            if (name != null) {
3720                return name;
3721            }
3722        }
3723
3724        return null;
3725    }
3726
3727    /**
3728     * Method getInnerTypeQName
3729     * 
3730     * @param node 
3731     * @return 
3732     */
3733    private static QName getInnerTypeQName(Node node) {
3734
3735        if (node == null) {
3736            return null;
3737        }
3738
3739        BooleanHolder forElement = new BooleanHolder();
3740        QName name = Utils.getTypeQName(node, forElement, true);
3741
3742        if (name != null) {
3743            return name;
3744        }
3745
3746        // Dive into the node if necessary
3747        NodeList children = node.getChildNodes();
3748
3749        for (int i = 0; i < children.getLength(); i++) {
3750            name = getInnerTypeQName(children.item(i));
3751
3752            if (name != null) {
3753                return name;
3754            }
3755        }
3756
3757        return null;
3758    }
3759    
3760    protected void processTypes() {
3761        for (Iterator i = typeTypeEntries.values().iterator(); i.hasNext(); ) {
3762            Type type = (Type) i.next();
3763            Node node = type.getNode();            
3764            
3765            // Process the attributes
3766            Vector attributes = 
3767                    SchemaUtils.getContainedAttributeTypes(node, this);
3768
3769            if (attributes != null) {
3770                type.setContainedAttributes(attributes);
3771            }
3772
3773            // Process the elements
3774            Vector elements =
3775                    SchemaUtils.getContainedElementDeclarations(node, this);
3776
3777            if (elements != null) {
3778                type.setContainedElements(elements);
3779            }
3780        }
3781    }
3782    
3783    public List getMessageEntries() {
3784        List messageEntries = new ArrayList();
3785        Iterator iter = symbolTable.values().iterator();
3786        while (iter.hasNext()) {
3787            Vector v = (Vector)iter.next();
3788            for (int i = 0; i < v.size(); ++i) {
3789                SymTabEntry entry = (SymTabEntry)v.elementAt(i);
3790                if (entry instanceof MessageEntry) {
3791                    messageEntries.add(entry);
3792                }
3793            }
3794        }
3795
3796        return messageEntries;
3797    }
3798
3799    public void setWrapArrays(boolean wrapArrays) {
3800        this.wrapArrays = wrapArrays;
3801    }
3802
3803    public Map getElementFormDefaults() {
3804        return elementFormDefaults;
3805    }
3806}