| /******************************************************************************* |
| * Copyright (c) 2001, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.wst.wsdl.validation.internal.wsdl11; |
| |
| import java.io.Reader; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| |
| import javax.wsdl.Import; |
| import javax.wsdl.WSDLException; |
| |
| import org.apache.xerces.impl.XMLErrorReporter; |
| import org.apache.xerces.parsers.DOMParser; |
| import org.apache.xerces.parsers.StandardParserConfiguration; |
| import org.apache.xerces.xni.XNIException; |
| import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; |
| import org.eclipse.wst.wsdl.validation.internal.xml.LineNumberDOMParser; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| |
| import com.ibm.wsdl.DefinitionImpl; |
| import com.ibm.wsdl.util.StringUtils; |
| |
| /** |
| * A WSDL reader that supports cyclic WSDL imports, schema imports and inline schemas. |
| * This reader is based on the WSDLReaderImpl from WSDL4J. |
| */ |
| public class WSDLReaderImpl |
| { |
| protected MessageGenerator messagegenerator; |
| protected IWSDL11ValidationInfo wsdlvalinfo; |
| |
| /** |
| * Constructor. |
| * |
| * @param wsdlvalinfo The WSDL 1.1 validation info object to use. |
| */ |
| public WSDLReaderImpl(IWSDL11ValidationInfo wsdlvalinfo) |
| { |
| this.wsdlvalinfo = wsdlvalinfo; |
| } |
| |
| /** |
| * Parse the root document. This method will find all imports and parse them as |
| * well creating a WSDLDocument for each unique WSDL file. This method supports |
| * cyclic WSDL import statements such that file A can import file B and file B |
| * can import file A. |
| * |
| * @param documentBaseURI The base URI of the root document. |
| * @param defEl The definition element of the root document. |
| * @return An array of WSDLDocuments containing all of the unique files in the description. |
| * @throws WSDLException |
| */ |
| protected WSDLDocument[] parseDocument(String documentBaseURI, Element defEl) throws WSDLException |
| { |
| int initialImportArraySize = 20; |
| List[] filesAtDepth = new ArrayList[initialImportArraySize]; |
| Map filesImporting = new Hashtable(); |
| SortedSet parsedImports = new TreeSet(); |
| SortedSet importsToParse = new TreeSet(); |
| int maxdepth = 0; |
| |
| WSDLDocument rootdoc = new WSDLDocument(documentBaseURI, defEl, 0, messagegenerator, wsdlvalinfo); |
| String targetNamespace = rootdoc.getDefinition().getTargetNamespace(); |
| ImportHolder rootImport = new ImportHolder(targetNamespace, documentBaseURI, documentBaseURI, rootdoc, 0, null, messagegenerator, wsdlvalinfo); |
| rootImport.createWSDLImport(rootdoc); |
| parsedImports.add(rootImport); |
| List rootList = new ArrayList(); |
| filesImporting.put(rootImport.getLocation(), new ArrayList()); |
| rootList.add(rootdoc); |
| filesAtDepth[0] = rootList; |
| importsToParse.addAll(rootdoc.getImports()); |
| Set imps = rootdoc.getImports(); |
| Iterator impIter = imps.iterator(); |
| while(impIter.hasNext()) |
| { |
| ImportHolder imp = (ImportHolder)impIter.next(); |
| List tempList = new ArrayList(); |
| tempList.add(imp.getImportingDocument()); |
| filesImporting.put(imp.getLocation(), tempList); |
| } |
| |
| while(!importsToParse.isEmpty()) |
| { |
| ImportHolder imp = (ImportHolder)importsToParse.first(); |
| // It's important to initialize the import here so each import |
| // is only created once. In the case of reciprical imports this |
| // avoids an infinite loop. |
| imp.initialize(); |
| WSDLDocument impDoc = imp.getWSDLDocument(); |
| |
| importsToParse.remove(imp); |
| |
| parsedImports.add(imp); |
| |
| // Add new imports to the list of imports to parse. |
| // Remove all the imports that have already been parsed. |
| if(impDoc != null) |
| { |
| // Increate import array if necessary. |
| if(imp.getDepth() >= initialImportArraySize) |
| { |
| List[] tempArray = new List[filesAtDepth.length + initialImportArraySize]; |
| System.arraycopy(filesAtDepth, 0, tempArray, 0, filesAtDepth.length); |
| filesAtDepth = tempArray; |
| } |
| // Create the list for the depth if necessary. |
| int impDepth = imp.getDepth(); |
| if(filesAtDepth[impDepth] == null) |
| { |
| if(maxdepth < impDepth) |
| { |
| maxdepth = impDepth; |
| } |
| filesAtDepth[impDepth] = new ArrayList(); |
| } |
| filesAtDepth[imp.getDepth()].add(impDoc); |
| |
| Set imports = impDoc.getImports(); |
| ImportHolder[] importsArray = (ImportHolder[])imports.toArray(new ImportHolder[imports.size()]); |
| for(int i = 0; i < importsArray.length; i++) |
| { |
| ImportHolder ih = importsArray[i]; |
| // If already parsed, add the definition importing this file to the list. |
| if(filesImporting.containsKey(ih.getLocation())) |
| { |
| ((List)filesImporting.get(ih.getLocation())).add(ih.getImportingDocument()); |
| } |
| // Otherwise add it to the list to parse. |
| else |
| { |
| // Add this import to the list of files importing list. |
| List tempList = new ArrayList(); |
| tempList.add(ih.getImportingDocument()); |
| filesImporting.put(ih.getLocation(), tempList); |
| importsToParse.add(ih); |
| } |
| } |
| } |
| } |
| |
| // Add all of the imports to the respective documents. |
| Iterator importElementsIter = parsedImports.iterator(); |
| while(importElementsIter.hasNext()) |
| { |
| ImportHolder imp = (ImportHolder)importElementsIter.next(); |
| List files = (List)filesImporting.get(imp.getLocation()); |
| Iterator filesIter = files.iterator(); |
| while(filesIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)filesIter.next(); |
| |
| DefinitionImpl def = (DefinitionImpl)doc.getDefinition(); |
| Import impElem = imp.getImport(); |
| if(impElem != null) |
| { |
| def.addImport(impElem); |
| if(!imp.isWSDLFileImport()) |
| { |
| doc.addSchemas(imp.getSchemas()); |
| } |
| } |
| |
| } |
| } |
| |
| // Parse the WSDL documents. |
| // Parse the Messages. |
| for(int i = maxdepth; i >=0; i--) |
| { |
| List docs = filesAtDepth[i]; |
| Iterator docsIter = docs.iterator(); |
| while(docsIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)docsIter.next(); |
| doc.parseMessages(); |
| } |
| } |
| // Parse the Porttypes. |
| for(int i = maxdepth; i >=0; i--) |
| { |
| List docs = filesAtDepth[i]; |
| Iterator docsIter = docs.iterator(); |
| while(docsIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)docsIter.next(); |
| doc.parsePorttypes(); |
| } |
| } |
| // Parse the Bindings. |
| for(int i = maxdepth; i >=0; i--) |
| { |
| List docs = filesAtDepth[i]; |
| Iterator docsIter = docs.iterator(); |
| while(docsIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)docsIter.next(); |
| doc.parseBindings(); |
| } |
| } |
| // Parse the Services. |
| for(int i = maxdepth; i >=0; i--) |
| { |
| List docs = filesAtDepth[i]; |
| Iterator docsIter = docs.iterator(); |
| while(docsIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)docsIter.next(); |
| doc.parseServices(); |
| } |
| } |
| // Parse the Extensibility Elements. |
| for(int i = maxdepth; i >=0; i--) |
| { |
| List docs = filesAtDepth[i]; |
| Iterator docsIter = docs.iterator(); |
| while(docsIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)docsIter.next(); |
| doc.parseExtensibilityElements(); |
| } |
| } |
| |
| List wsdlDocs = new ArrayList(); |
| for(int i = maxdepth; i >=0; i--) |
| { |
| List docs = filesAtDepth[i]; |
| Iterator docsIter = docs.iterator(); |
| while(docsIter.hasNext()) |
| { |
| WSDLDocument doc = (WSDLDocument)docsIter.next(); |
| wsdlDocs.add(doc); |
| } |
| } |
| |
| return (WSDLDocument[])wsdlDocs.toArray(new WSDLDocument[wsdlDocs.size()]); |
| } |
| |
| /** |
| * Get the WSDL document. |
| * |
| * @param inputSource The source of the document being retrieved. |
| * @param desc The description of the document being retrieved. |
| * @return The WSDL document. |
| * @throws WSDLException |
| */ |
| public static Document getDocument(InputSource inputSource, String desc) throws WSDLException |
| { |
| try |
| { |
| StandardParserConfiguration configuration = new StandardParserConfiguration() |
| { |
| protected XMLErrorReporter createErrorReporter() |
| { |
| return new XMLErrorReporter() |
| { |
| public void reportError(String domain, String key, Object[] arguments, short severity) throws XNIException |
| { |
| boolean reportError = true; |
| if (key.equals("PrematureEOF")) |
| { |
| reportError = false; |
| } |
| |
| if (reportError) |
| { |
| super.reportError(domain, key, arguments, severity); |
| } |
| } |
| }; |
| } |
| }; |
| |
| ErrorHandler errorHandler = new ErrorHandler() |
| { |
| /* (non-Javadoc) |
| * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) |
| */ |
| public void error(SAXParseException exception) throws SAXException |
| { |
| // TODO Auto-generated method stub |
| |
| } |
| /* (non-Javadoc) |
| * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) |
| */ |
| public void fatalError(SAXParseException exception) throws SAXException |
| { |
| // TODO Auto-generated method stub |
| |
| } |
| /* (non-Javadoc) |
| * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) |
| */ |
| public void warning(SAXParseException exception) throws SAXException |
| { |
| // TODO Auto-generated method stub |
| |
| } |
| }; |
| |
| DOMParser builder = new LineNumberDOMParser(configuration); |
| builder.setErrorHandler(errorHandler); |
| builder.parse(inputSource); |
| Document doc = builder.getDocument(); |
| |
| return doc; |
| } |
| catch (Throwable t) |
| { |
| throw new WSDLException(WSDLException.PARSER_ERROR, "Problem parsing '" + desc + "'.", t); |
| } |
| } |
| |
| /** |
| * Read a WSDL document using a context URI and file URI. |
| * |
| * @param contextURI The context URI to use. |
| * @param wsdlURI The WSDL URI to use. |
| * @return An array of WSDLDocuments. |
| * @throws WSDLException |
| */ |
| public WSDLDocument[] readWSDL(String contextURI, String wsdlURI) throws WSDLException |
| { |
| try |
| { |
| URL contextURL = (contextURI != null) ? StringUtils.getURL(null, contextURI) : null; |
| URL url = StringUtils.getURL(contextURL, wsdlURI); |
| Reader reader = StringUtils.getContentAsReader(url); |
| InputSource inputSource = new InputSource(reader); |
| Document doc = getDocument(inputSource, wsdlURI); |
| reader.close(); |
| WSDLDocument[] wsdlDocs = null; |
| // only parse the document if it isn't empty |
| if(doc.getDocumentElement() != null) |
| { |
| wsdlDocs = readWSDL(url.toString(), doc); |
| } |
| return wsdlDocs; |
| } |
| catch (WSDLException e) |
| { |
| throw e; |
| } |
| catch (Throwable t) |
| { |
| throw new WSDLException( |
| WSDLException.OTHER_ERROR, |
| "Unable to resolve imported document at '" + wsdlURI + "'.", |
| t); |
| } |
| } |
| |
| /** |
| * Set the messagegenerator for the reader. |
| * |
| * @param mg The message generator to set. |
| */ |
| public void setMessageGenerator(MessageGenerator mg) |
| { |
| messagegenerator = mg; |
| } |
| |
| /** |
| * Read the WSDL document accessible via the specified |
| * URI into a WSDL definition. |
| * |
| * @param wsdlURI A URI pointing to a WSDL file. |
| * @return An array of WSDLDocuments. |
| */ |
| public WSDLDocument[] readWSDL(String wsdlURI) throws WSDLException |
| { |
| return readWSDL(null, wsdlURI); |
| } |
| |
| /** |
| * Read the WSDL document described by a URI and its definitions element. |
| * |
| * @param documentBaseURI The URI of the WSDL document. |
| * @param definitionsElement The definitions element for the WSDL document. |
| * @return An array of WSDLDocuments. |
| * @throws WSDLException |
| */ |
| protected WSDLDocument[] readWSDL(String documentBaseURI, |
| Element definitionsElement) |
| throws WSDLException |
| { |
| return parseDocument(documentBaseURI, definitionsElement); |
| } |
| |
| /** |
| * Read the specified WSDL document. |
| * |
| * @param documentBaseURI The document base URI. |
| * @param wsdlDocument The WSDL document. |
| * @return An array of WSDLDocuments. |
| */ |
| public WSDLDocument[] readWSDL(String documentBaseURI, Document wsdlDocument) |
| throws WSDLException |
| { |
| return readWSDL(documentBaseURI, wsdlDocument.getDocumentElement()); |
| } |
| |
| |
| |
| } |
| |