KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > wsdl > symbolTable > SymbolTable


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 JavaDoc;
25 import org.w3c.dom.NamedNodeMap JavaDoc;
26 import org.w3c.dom.Node JavaDoc;
27 import org.w3c.dom.NodeList JavaDoc;
28 import org.xml.sax.SAXException JavaDoc;
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 JavaDoc;
61 import javax.xml.parsers.ParserConfigurationException JavaDoc;
62 import javax.xml.rpc.holders.BooleanHolder JavaDoc;
63 import javax.xml.rpc.holders.IntHolder JavaDoc;
64 import javax.xml.rpc.holders.QNameHolder JavaDoc;
65 import java.io.File JavaDoc;
66 import java.io.IOException JavaDoc;
67 import java.net.MalformedURLException JavaDoc;
68 import java.net.URL JavaDoc;
69 import java.util.ArrayList JavaDoc;
70 import java.util.Collection JavaDoc;
71 import java.util.Collections JavaDoc;
72 import java.util.HashMap JavaDoc;
73 import java.util.HashSet JavaDoc;
74 import java.util.Iterator JavaDoc;
75 import java.util.List JavaDoc;
76 import java.util.Map JavaDoc;
77 import java.util.Set JavaDoc;
78 import java.util.Vector JavaDoc;
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 JavaDoc derivedTypes = new HashMap JavaDoc();
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 JavaDoc symbolTable = new HashMap JavaDoc();
112
113     // a map of qnames -> Elements in the symbol table
114

115     /** Field elementTypeEntries */
116     private final Map JavaDoc elementTypeEntries = new HashMap JavaDoc();
117
118     // an unmodifiable wrapper so that we can share the index with others, safely
119

120     /** Field elementIndex */
121     private final Map JavaDoc elementIndex =
122             Collections.unmodifiableMap(elementTypeEntries);
123
124     // a map of qnames -> Types in the symbol table
125

126     /** Field typeTypeEntries */
127     private final Map JavaDoc typeTypeEntries = new HashMap JavaDoc();
128
129     // an unmodifiable wrapper so that we can share the index with others, safely
130

131     /** Field typeIndex */
132     private final Map JavaDoc 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 JavaDoc node2ExtensionBase =
140             new HashMap JavaDoc(); // 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 JavaDoc ANON_TOKEN = ">";
163
164     /** Field def */
165     private Definition def = null;
166
167     /** Field wsdlURI */
168     private String JavaDoc 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 JavaDoc elementFormDefaults = new HashMap JavaDoc();
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 JavaDoc 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 JavaDoc getSymbols(QName JavaDoc qname) {
232         return (Vector JavaDoc) 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 JavaDoc qname, Class JavaDoc cls) {
243
244         Vector JavaDoc v = (Vector JavaDoc) 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc getTypes() {
347
348         Vector JavaDoc v = new Vector JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc out) {
429
430         out.println();
431         out.println(Messages.getMessage("symbolTable00"));
432         out.println("-----------------------");
433
434         Iterator JavaDoc it = symbolTable.values().iterator();
435
436         while (it.hasNext()) {
437             Vector JavaDoc v = (Vector JavaDoc) 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 JavaDoc uri)
458             throws IOException JavaDoc, WSDLException, SAXException JavaDoc,
459             ParserConfigurationException JavaDoc {
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 JavaDoc uri, String JavaDoc username, String JavaDoc password)
475             throws IOException JavaDoc, WSDLException, SAXException JavaDoc,
476             ParserConfigurationException JavaDoc {
477
478         if (verbose) {
479             System.out.println(Messages.getMessage("parsing00", uri));
480         }
481
482         Document JavaDoc doc = XMLUtils.newDocument(uri, username, password);
483
484         this.wsdlURI = uri;
485
486         try {
487             File JavaDoc f = new File JavaDoc(uri);
488
489             if (f.exists()) {
490                 uri = f.toURL().toString();
491             }
492         } catch (Exception JavaDoc 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 JavaDoc context, Document JavaDoc doc)
509             throws IOException JavaDoc, SAXException JavaDoc, WSDLException,
510             ParserConfigurationException JavaDoc {
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 JavaDoc context, Definition def, Document JavaDoc doc)
536             throws IOException JavaDoc, SAXException JavaDoc, WSDLException,
537             ParserConfigurationException JavaDoc {
538
539         URL JavaDoc 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 JavaDoc filename)
558             throws IOException JavaDoc {
559
560         if (def != null) {
561
562             // Bindings
563
Iterator JavaDoc 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 JavaDoc(
571                                 Messages.getMessage(
572                                         "emitFailtUndefinedBinding01",
573                                         binding.getQName().getLocalPart()));
574                     } else {
575                         throw new IOException JavaDoc(
576                                 Messages.getMessage(
577                                         "emitFailtUndefinedBinding02",
578                                         binding.getQName().getLocalPart(), filename));
579                     }
580                 }
581             }
582
583             // portTypes
584
Iterator JavaDoc 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 JavaDoc(
592                                 Messages.getMessage(
593                                         "emitFailtUndefinedPort01",
594                                         portType.getQName().getLocalPart()));
595                     } else {
596                         throw new IOException JavaDoc(
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 JavaDoc {
630
631         Iterator JavaDoc it = symbolTable.values().iterator();
632
633         while (it.hasNext()) {
634             Vector JavaDoc v = (Vector JavaDoc) 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 JavaDoc 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 JavaDoc(
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 JavaDoc(
660                                 Messages.getMessage(
661                                         "unsupportedSchemaType00", qn.getLocalPart()));
662                     }
663
664                     // last case, its some other undefined thing
665
throw new IOException JavaDoc(
666                             Messages.getMessage(
667                                     "undefined00", qn.toString()));
668                 } // if undefined
669
else if (entry instanceof UndefinedElement) {
670                     throw new IOException JavaDoc(
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 JavaDoc context, Definition def, Document JavaDoc doc, String JavaDoc filename)
701             throws IOException JavaDoc, ParserConfigurationException JavaDoc, SAXException JavaDoc,
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 JavaDoc imports = def.getImports();
721                 Object JavaDoc[] importKeys = imports.keySet().toArray();
722
723                 for (int i = 0; i < importKeys.length; ++i) {
724                     Vector JavaDoc v = (Vector JavaDoc) 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 JavaDoc 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 JavaDoc getURL(URL JavaDoc contextURL, String JavaDoc spec) throws IOException JavaDoc {
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 JavaDoc path = spec.replace('\\', '/');
764
765         // See if we have a good URL.
766
URL JavaDoc url = null;
767
768         try {
769
770             // first, try to treat spec as a full URL
771
url = new URL JavaDoc(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 JavaDoc 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 JavaDoc getFileURL(URL JavaDoc contextURL, String JavaDoc path)
800             throws IOException JavaDoc {
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 JavaDoc contextFileName = contextURL.getFile();
807             URL JavaDoc parent = null;
808             File JavaDoc parentFile = new File JavaDoc(contextFileName).getParentFile();
809             if ( parentFile != null ) {
810                 parent = parentFile.toURL();
811             }
812             if (parent != null) {
813                 return new URL JavaDoc(parent, path);
814             }
815         }
816
817         return new URL JavaDoc("file", "", path);
818     } // getFileURL
819