001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.webservices.builder;
019    
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.net.URI;
023    import java.net.URISyntaxException;
024    import java.util.ArrayList;
025    import java.util.Collection;
026    import java.util.HashMap;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Map;
030    import java.util.Stack;
031    import java.util.jar.JarFile;
032    import java.util.zip.ZipEntry;
033    import javax.wsdl.Definition;
034    import javax.wsdl.Import;
035    import javax.wsdl.Service;
036    import javax.wsdl.Types;
037    import javax.wsdl.WSDLException;
038    import javax.wsdl.extensions.ExtensibilityElement;
039    import javax.wsdl.extensions.ExtensionRegistry;
040    import javax.wsdl.extensions.UnknownExtensibilityElement;
041    import javax.wsdl.extensions.schema.Schema;
042    import javax.wsdl.factory.WSDLFactory;
043    import javax.wsdl.xml.WSDLLocator;
044    import javax.wsdl.xml.WSDLReader;
045    import javax.xml.namespace.QName;
046    
047    import com.ibm.wsdl.extensions.PopulatedExtensionRegistry;
048    import com.ibm.wsdl.extensions.schema.SchemaConstants;
049    import org.apache.commons.logging.Log;
050    import org.apache.commons.logging.LogFactory;
051    import org.apache.geronimo.webservices.WebServiceContainer;
052    import org.apache.geronimo.common.DeploymentException;
053    import org.apache.geronimo.xbeans.wsdl.DefinitionsDocument;
054    import org.apache.geronimo.xbeans.wsdl.TDefinitions;
055    import org.apache.geronimo.xbeans.wsdl.TPort;
056    import org.apache.geronimo.xbeans.wsdl.TService;
057    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
058    import org.apache.xmlbeans.SchemaField;
059    import org.apache.xmlbeans.SchemaGlobalElement;
060    import org.apache.xmlbeans.SchemaParticle;
061    import org.apache.xmlbeans.SchemaType;
062    import org.apache.xmlbeans.SchemaTypeSystem;
063    import org.apache.xmlbeans.XmlBeans;
064    import org.apache.xmlbeans.XmlCursor;
065    import org.apache.xmlbeans.XmlError;
066    import org.apache.xmlbeans.XmlException;
067    import org.apache.xmlbeans.XmlObject;
068    import org.apache.xmlbeans.XmlOptions;
069    import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument;
070    import org.w3c.dom.Element;
071    import org.xml.sax.EntityResolver;
072    import org.xml.sax.InputSource;
073    import org.xml.sax.SAXException;
074    
075    /**
076     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
077     */
078    public class SchemaInfoBuilder {
079        private static final Log log = LogFactory.getLog(SchemaInfoBuilder.class);
080        private static final SchemaTypeSystem basicTypeSystem;
081    //  private static final String[] errorNames = {"Error", "Warning", "Info"};
082        private static final String SOAP_NS = "http://schemas.xmlsoap.org/wsdl/soap/";
083        private static final QName ADDRESS_QNAME = new QName(SOAP_NS, "address");
084        private static final QName LOCATION_QNAME = new QName("", "location");
085    
086        static {
087            InputStream is = WSDescriptorParser.class.getClassLoader().getResourceAsStream("META-INF/schema/soap_encoding_1_1.xsd");
088            if (is == null) {
089                throw new RuntimeException("Could not locate soap encoding schema");
090            }
091            ArrayList errors = new ArrayList();
092            XmlOptions xmlOptions = XmlBeansUtil.createXmlOptions(errors);
093            try {
094                SchemaDocument parsed = SchemaDocument.Factory.parse(is, xmlOptions);
095                if (errors.size() != 0) {
096                    throw new XmlException(errors.toArray().toString());
097                }
098    
099                basicTypeSystem = XmlBeans.compileXsd(new XmlObject[]{parsed}, XmlBeans.getBuiltinTypeSystem(), xmlOptions);
100                if (errors.size() > 0) {
101                    throw new RuntimeException("Could not compile schema type system: errors: " + errors);
102                }
103            } catch (XmlException e) {
104                throw new RuntimeException("Could not compile schema type system", e);
105            } catch (IOException e) {
106                throw new RuntimeException("Could not compile schema type system", e);
107            } finally {
108                try {
109                    is.close();
110                } catch (IOException ignore) {
111                    // ignore
112                }
113            }
114        }
115    
116        private final JarFile moduleFile;
117        private final Definition definition;
118        private final Stack uris = new Stack();
119        private final Map wsdlMap = new HashMap();
120        private final Map schemaTypeKeyToSchemaTypeMap;
121        private final Map complexTypeMap;
122        private final Map elementMap;
123        private final Map simpleTypeMap;
124        private final Map portMap;
125    
126    
127        public SchemaInfoBuilder(JarFile moduleFile, URI wsdlUri) throws DeploymentException {
128            this(moduleFile, wsdlUri, null, null);
129        }
130    
131        public SchemaInfoBuilder(JarFile moduleFile, Definition definition) throws DeploymentException {
132            this(moduleFile, null, definition, null);
133        }
134    
135        SchemaInfoBuilder(JarFile moduleFile, URI uri, SchemaTypeSystem schemaTypeSystem) throws DeploymentException {
136            this(moduleFile, uri, null, schemaTypeSystem);
137        }
138    
139        SchemaInfoBuilder(JarFile moduleFile, URI uri, Definition definition, SchemaTypeSystem schemaTypeSystem) throws DeploymentException {
140            this.moduleFile = moduleFile;
141            if (uri != null) {
142                uris.push(uri);
143                if (definition == null && schemaTypeSystem == null) {
144                    definition = readWsdl(moduleFile, uri);
145                }
146            } else if (definition != null) {
147                try {
148                    uri = new URI(definition.getDocumentBaseURI());
149                    uris.push(uri);
150                } catch (URISyntaxException e) {
151                    throw new DeploymentException("Could not locate definition", e);
152                }
153            } else {
154                throw new DeploymentException("You must supply uri or definition");
155            }
156            if (schemaTypeSystem == null) {
157                schemaTypeSystem = compileSchemaTypeSystem(definition);
158            }
159            this.definition = definition;
160            schemaTypeKeyToSchemaTypeMap = buildSchemaTypeKeyToSchemaTypeMap(schemaTypeSystem);
161            complexTypeMap = buildComplexTypeMap();
162            simpleTypeMap = buildSimpleTypeMap();
163            elementMap = buildElementMap();
164            portMap = buildPortMap();
165        }
166    
167        public Map getSchemaTypeKeyToSchemaTypeMap() {
168            return schemaTypeKeyToSchemaTypeMap;
169        }
170    
171        public Definition getDefinition() {
172            return definition;
173        }
174    
175        public Map getWsdlMap() {
176            return wsdlMap;
177        }
178    
179        /**
180         * Find all the complex types in the previously constructed schema analysis.
181         * Put them in a map from complex type QName to schema fragment.
182         *
183         * @return map of complexType QName to schema fragment
184         */
185        public Map getComplexTypesInWsdl() {
186            return complexTypeMap;
187        }
188    
189        private Map buildComplexTypeMap() {
190            Map complexTypeMap = new HashMap();
191            for (Iterator iterator = schemaTypeKeyToSchemaTypeMap.entrySet().iterator(); iterator.hasNext();) {
192                Map.Entry entry = (Map.Entry) iterator.next();
193                SchemaTypeKey key = (SchemaTypeKey) entry.getKey();
194                if (!key.isSimpleType() && !key.isAnonymous()) {
195                    QName qName = key.getqName();
196                    SchemaType schemaType = (SchemaType) entry.getValue();
197                    complexTypeMap.put(qName, schemaType);
198                }
199            }
200            return complexTypeMap;
201        }
202    
203        public Map getElementToTypeMap() {
204            return elementMap;
205        }
206    
207        private Map buildElementMap() {
208            Map elementToTypeMap = new HashMap();
209            for (Iterator iterator = schemaTypeKeyToSchemaTypeMap.entrySet().iterator(); iterator.hasNext();) {
210                Map.Entry entry = (Map.Entry) iterator.next();
211                SchemaTypeKey key = (SchemaTypeKey) entry.getKey();
212                if (key.isElement()) {
213                    QName elementQName = key.getqName();
214                    SchemaType schemaType = (SchemaType) entry.getValue();
215                    QName typeQName = schemaType.getName();
216                    elementToTypeMap.put(elementQName, typeQName);
217                }
218            }
219            return elementToTypeMap;
220        }
221    
222        /**
223         * Gets a map of all the javax.wsdl.Port instance in the WSDL definition keyed by the port's QName
224         * <p/>
225         * WSDL 1.1 spec: 2.6 "The name attribute provides a unique name among all ports defined within in the enclosing WSDL document."
226         *
227         * @return Map of port QName to javax.wsdl.Port for that QName.
228         */
229    
230        public Map getPortMap() {
231            return portMap;
232        }
233    
234        private Map buildPortMap() {
235            HashMap ports = new HashMap();
236            if (definition != null) {
237                Collection services = definition.getServices().values();
238                for (Iterator iterator = services.iterator(); iterator.hasNext();) {
239                    Service service = (Service) iterator.next();
240                    ports.putAll(service.getPorts());
241                }
242            }
243            return ports;
244        }
245    
246        public Map getSimpleTypeMap() {
247            return simpleTypeMap;
248        }
249    
250        private Map buildSimpleTypeMap() {
251            Map simpleTypeMap = new HashMap();
252            for (Iterator iterator = schemaTypeKeyToSchemaTypeMap.entrySet().iterator(); iterator.hasNext();) {
253                Map.Entry entry = (Map.Entry) iterator.next();
254                SchemaTypeKey key = (SchemaTypeKey) entry.getKey();
255                if (key.isSimpleType() && !key.isAnonymous()) {
256                    QName qName = key.getqName();
257                    SchemaType schemaType = (SchemaType) entry.getValue();
258                    simpleTypeMap.put(qName, schemaType);
259                }
260            }
261            return simpleTypeMap;
262        }
263    
264        public SchemaTypeSystem compileSchemaTypeSystem(Definition definition) throws DeploymentException {
265            List schemaList = new ArrayList();
266            addImportsFromDefinition(definition, schemaList);
267    //        System.out.println("Schemas: " + schemaList);
268            Collection errors = new ArrayList();
269            XmlOptions xmlOptions = new XmlOptions();
270            xmlOptions.setErrorListener(errors);
271            xmlOptions.setEntityResolver(new JarEntityResolver());
272            XmlObject[] schemas = (XmlObject[]) schemaList.toArray(new XmlObject[schemaList.size()]);
273            try {
274                SchemaTypeSystem schemaTypeSystem = XmlBeans.compileXsd(schemas, basicTypeSystem, xmlOptions);
275                if (errors.size() > 0) {
276                    boolean wasError = false;
277                    for (Iterator iterator = errors.iterator(); iterator.hasNext();) {
278                        XmlError xmlError = (XmlError) iterator.next();
279                        if(xmlError.getSeverity() == XmlError.SEVERITY_ERROR) {
280                            log.error(xmlError);
281                            wasError = true;
282                        } else if(xmlError.getSeverity() == XmlError.SEVERITY_WARNING) {
283                            log.warn(xmlError);
284                        } else if(xmlError.getSeverity() == XmlError.SEVERITY_INFO) {
285                            log.debug(xmlError);
286                        }
287                    }
288                    if (wasError) {
289                        throw new DeploymentException("Could not compile schema type system, see log for errors");
290                    }
291                }
292                return schemaTypeSystem;
293            } catch (XmlException e) {
294                throw new DeploymentException("Could not compile schema type system: " + schemaList, e);
295            }
296        }
297    
298        private void addImportsFromDefinition(Definition definition, List schemaList) throws DeploymentException {
299            Map namespaceMap = definition.getNamespaces();
300            Types types = definition.getTypes();
301            if (types != null) {
302                List schemas = types.getExtensibilityElements();
303                for (Iterator iterator = schemas.iterator(); iterator.hasNext();) {
304                    Object o = iterator.next();
305                    if (o instanceof Schema) {
306                        Schema unknownExtensibilityElement = (Schema) o;
307                        QName elementType = unknownExtensibilityElement.getElementType();
308                        if (new QName("http://www.w3.org/2001/XMLSchema", "schema").equals(elementType)) {
309                            Element element = unknownExtensibilityElement.getElement();
310                            addSchemaElement(element, namespaceMap, schemaList);
311                        }
312                    } else if (o instanceof UnknownExtensibilityElement) {
313                        //This is allegedly obsolete as of axis-wsdl4j-1.2-RC3.jar which includes the Schema extension above.
314                        //The change notes imply that imported schemas should end up in Schema elements.  They don't, so this is still needed.
315                        UnknownExtensibilityElement unknownExtensibilityElement = (UnknownExtensibilityElement) o;
316                        Element element = unknownExtensibilityElement.getElement();
317                        String elementNamespace = element.getNamespaceURI();
318                        String elementLocalName = element.getNodeName();
319                        if ("http://www.w3.org/2001/XMLSchema".equals(elementNamespace) && "schema".equals(elementLocalName)) {
320                            addSchemaElement(element, namespaceMap, schemaList);
321                        }
322                    }
323                }
324            }
325            Map imports = definition.getImports();
326            if (imports != null) {
327                for (Iterator iterator = imports.entrySet().iterator(); iterator.hasNext();) {
328                    Map.Entry entry = (Map.Entry) iterator.next();
329                    String namespaceURI = (String) entry.getKey();
330                    List importList = (List) entry.getValue();
331                    for (Iterator iterator1 = importList.iterator(); iterator1.hasNext();) {
332                        Import anImport = (Import) iterator1.next();
333                        //according to the 1.1 jwsdl mr shcema imports are supposed to show up here,
334                        //but according to the 1.0 spec there is supposed to be no Definition.
335                        Definition definition1 = anImport.getDefinition();
336                        if (definition1 != null) {
337                            try {
338                                URI uri = new URI(definition1.getDocumentBaseURI());
339                                uris.push(uri);
340                            } catch (URISyntaxException e) {
341                                throw new DeploymentException("Could not locate definition", e);
342                            }
343                            try {
344                                addImportsFromDefinition(definition1, schemaList);
345                            } finally {
346                                uris.pop();
347                            }
348                        } else {
349                            log.warn("Missing definition in import for namespace " + namespaceURI);
350                        }
351                    }
352                }
353            }
354        }
355    
356        private void addSchemaElement(Element element, Map namespaceMap, List schemaList) throws DeploymentException {
357            try {
358                XmlObject xmlObject = parseWithNamespaces(element, namespaceMap);
359                schemaList.add(xmlObject);
360            } catch (XmlException e) {
361                throw new DeploymentException("Could not parse schema element", e);
362            }
363        }
364    
365        static XmlObject parseWithNamespaces(Element element, Map namespaceMap) throws XmlException {
366            ArrayList errors = new ArrayList();
367            XmlOptions xmlOptions = XmlBeansUtil.createXmlOptions(errors);
368            SchemaDocument parsed = SchemaDocument.Factory.parse(element, xmlOptions);
369            if (errors.size() != 0) {
370                throw new XmlException(errors.toArray().toString());
371            }
372            XmlCursor cursor = parsed.newCursor();
373            try {
374                cursor.toFirstContentToken();
375                for (Iterator namespaces = namespaceMap.entrySet().iterator(); namespaces.hasNext();) {
376                    Map.Entry entry = (Map.Entry) namespaces.next();
377                    cursor.insertNamespace((String) entry.getKey(), (String) entry.getValue());
378                }
379            } finally {
380                cursor.dispose();
381            }
382            return parsed;
383        }
384    
385        /**
386         * builds a map of SchemaTypeKey containing jaxrpc-style fake QName and context info to xmlbeans SchemaType object.
387         *
388         * @param schemaTypeSystem
389         * @return Map of SchemaTypeKey to xmlbeans SchemaType object.
390         */
391        private Map buildSchemaTypeKeyToSchemaTypeMap(SchemaTypeSystem schemaTypeSystem) {
392            Map qnameMap = new HashMap();
393            SchemaType[] globalTypes = schemaTypeSystem.globalTypes();
394            for (int i = 0; i < globalTypes.length; i++) {
395                SchemaType globalType = globalTypes[i];
396                QName typeQName = globalType.getName();
397                addSchemaType(typeQName, globalType, false, qnameMap);
398            }
399            SchemaGlobalElement[] globalElements = schemaTypeSystem.globalElements();
400            for (int i = 0; i < globalElements.length; i++) {
401                SchemaGlobalElement globalElement = globalElements[i];
402                addElement(globalElement, null, qnameMap);
403            }
404            return qnameMap;
405        }
406    
407        private void addElement(SchemaField element, SchemaTypeKey key, Map qnameMap) {
408            //TODO is this null if element is a ref?
409            QName elementName = element.getName();
410            String elementNamespace = elementName.getNamespaceURI();
411            //"" namespace means local element with elementFormDefault="unqualified"
412            if (elementNamespace == null || elementNamespace.equals("")) {
413                elementNamespace = key.getqName().getNamespaceURI();
414            }
415            String elementQNameLocalName;
416            SchemaTypeKey elementKey;
417            if (key == null) {
418                //top level. rule 2.a,
419                elementQNameLocalName = elementName.getLocalPart();
420                elementKey = new SchemaTypeKey(elementName, true, false, false, elementName);
421            } else {
422                //not top level. rule 2.b, key will be for enclosing Type.
423                QName enclosingTypeQName = key.getqName();
424                String enclosingTypeLocalName = enclosingTypeQName.getLocalPart();
425                elementQNameLocalName = enclosingTypeLocalName + ">" + elementName.getLocalPart();
426                QName subElementName = new QName(elementNamespace, elementQNameLocalName);
427                elementKey = new SchemaTypeKey(subElementName, true, false, true, elementName);
428            }
429            SchemaType schemaType = element.getType();
430            qnameMap.put(elementKey, schemaType);
431    //        new Exception("Adding: " + elementKey.getqName().getLocalPart()).printStackTrace();
432            //check if it's an array. maxOccurs is null if unbounded
433            //element should always be a SchemaParticle... this is a workaround for XMLBEANS-137
434            if (element instanceof SchemaParticle) {
435                addArrayForms((SchemaParticle) element, elementKey.getqName(), qnameMap, schemaType);
436            } else {
437                log.warn("element is not a schemaParticle! " + element);
438            }
439            //now, name for type.  Rule 1.b, type inside an element
440            String typeQNameLocalPart = ">" + elementQNameLocalName;
441            QName typeQName = new QName(elementNamespace, typeQNameLocalPart);
442            boolean isAnonymous = true;
443            addSchemaType(typeQName, schemaType, isAnonymous, qnameMap);
444        }
445    
446        private void addSchemaType(QName typeQName, SchemaType schemaType, boolean anonymous, Map qnameMap) {
447            SchemaTypeKey typeKey = new SchemaTypeKey(typeQName, false, schemaType.isSimpleType(), anonymous, null);
448            qnameMap.put(typeKey, schemaType);
449    //        new Exception("Adding: " + typeKey.getqName().getLocalPart()).printStackTrace();
450            //TODO xmlbeans recommends using summary info from getElementProperties and getAttributeProperties instead of traversing the content model by hand.
451            SchemaParticle schemaParticle = schemaType.getContentModel();
452            if (schemaParticle != null) {
453                addSchemaParticle(schemaParticle, typeKey, qnameMap);
454            }
455        }
456    
457    
458        private void addSchemaParticle(SchemaParticle schemaParticle, SchemaTypeKey key, Map qnameMap) {
459            if (schemaParticle.getParticleType() == SchemaParticle.ELEMENT) {
460                SchemaType elementType = schemaParticle.getType();
461                SchemaField element = elementType.getContainerField();
462                //element will be null if the type is defined elsewhere, such as a built in type.
463                if (element != null) {
464                    addElement(element, key, qnameMap);
465                } else {
466                    QName keyQName = key.getqName();
467                    //TODO I can't distinguish between 3.a and 3.b, so generate names both ways.
468                    //3.b
469                    String localPart = schemaParticle.getName().getLocalPart();
470                    QName elementName = new QName(keyQName.getNamespaceURI(), localPart);
471                    addArrayForms(schemaParticle, elementName, qnameMap, elementType);
472                    //3.a
473                    localPart = keyQName.getLocalPart() + ">" + schemaParticle.getName().getLocalPart();
474                    elementName = new QName(keyQName.getNamespaceURI(), localPart);
475                    addArrayForms(schemaParticle, elementName, qnameMap, elementType);
476                }
477            } else {
478                try {
479                    SchemaParticle[] children = schemaParticle.getParticleChildren();
480                    for (int i = 0; i < children.length; i++) {
481                        SchemaParticle child = children[i];
482                        addSchemaParticle(child, key, qnameMap);
483                    }
484                } catch (NullPointerException e) {
485                    //ignore xmlbeans bug
486                }
487            }
488        }
489    
490        private void addArrayForms(SchemaParticle schemaParticle, QName keyName, Map qnameMap, SchemaType elementType) {
491            //it may be a ref or a built in type.  If it's an array (maxOccurs >1) form a type for it.
492            if (schemaParticle.getIntMaxOccurs() > 1) {
493                String maxOccurs = schemaParticle.getMaxOccurs() == null ? "unbounded" : "" + schemaParticle.getIntMaxOccurs();
494                int minOccurs = schemaParticle.getIntMinOccurs();
495                QName elementName = schemaParticle.getName();
496                String arrayQNameLocalName = keyName.getLocalPart() + "[" + minOccurs + "," + maxOccurs + "]";
497                String elementNamespace = elementName.getNamespaceURI();
498                if (elementNamespace == null || elementNamespace.equals("")) {
499                    elementNamespace = keyName.getNamespaceURI();
500                }
501                QName arrayName = new QName(elementNamespace, arrayQNameLocalName);
502                SchemaTypeKey arrayKey = new SchemaTypeKey(arrayName, false, false, true, elementName);
503                //TODO not clear we want the schemaType as the value
504                qnameMap.put(arrayKey, elementType);
505    //            new Exception("Adding: " + arrayKey.getqName().getLocalPart()).printStackTrace();
506                if (minOccurs == 1) {
507                    arrayQNameLocalName = keyName.getLocalPart() + "[," + maxOccurs + "]";
508                    arrayName = new QName(elementNamespace, arrayQNameLocalName);
509                    arrayKey = new SchemaTypeKey(arrayName, false, false, true, elementName);
510                    //TODO not clear we want the schemaType as the value
511                    qnameMap.put(arrayKey, elementType);
512                }
513            }
514        }
515    
516    
517        public Definition readWsdl(JarFile moduleFile, URI wsdlURI) throws DeploymentException {
518            Definition definition;
519            WSDLFactory wsdlFactory;
520            try {
521                wsdlFactory = WSDLFactory.newInstance();
522            } catch (WSDLException e) {
523                throw new DeploymentException("Could not create WSDLFactory", e);
524            }
525            WSDLReader wsdlReaderNoImport = wsdlFactory.newWSDLReader();
526            wsdlReaderNoImport.setFeature("javax.wsdl.importDocuments", false);
527            ExtensionRegistry extensionRegistry = new PopulatedExtensionRegistry();
528            extensionRegistry.mapExtensionTypes(Types.class, SchemaConstants.Q_ELEM_XSD_1999,
529                    UnknownExtensibilityElement.class);
530            extensionRegistry.registerDeserializer(Types.class, SchemaConstants.Q_ELEM_XSD_1999,
531                    extensionRegistry.getDefaultDeserializer());
532            extensionRegistry.registerSerializer(Types.class, SchemaConstants.Q_ELEM_XSD_1999,
533                    extensionRegistry.getDefaultSerializer());
534    
535            extensionRegistry.mapExtensionTypes(Types.class, SchemaConstants.Q_ELEM_XSD_2000,
536                    UnknownExtensibilityElement.class);
537            extensionRegistry.registerDeserializer(Types.class, SchemaConstants.Q_ELEM_XSD_2000,
538                    extensionRegistry.getDefaultDeserializer());
539            extensionRegistry.registerSerializer(Types.class, SchemaConstants.Q_ELEM_XSD_2000,
540                    extensionRegistry.getDefaultSerializer());
541    
542            extensionRegistry.mapExtensionTypes(Types.class, SchemaConstants.Q_ELEM_XSD_2001,
543                    UnknownExtensibilityElement.class);
544            extensionRegistry.registerDeserializer(Types.class, SchemaConstants.Q_ELEM_XSD_2001,
545                    extensionRegistry.getDefaultDeserializer());
546            extensionRegistry.registerSerializer(Types.class, SchemaConstants.Q_ELEM_XSD_2001,
547                    extensionRegistry.getDefaultSerializer());
548            wsdlReaderNoImport.setExtensionRegistry(extensionRegistry);
549    
550            JarWSDLLocator wsdlLocator = new JarWSDLLocator(wsdlURI);
551            WSDLReader wsdlReader = wsdlFactory.newWSDLReader();
552    
553            Thread thread = Thread.currentThread();
554            ClassLoader oldCl = thread.getContextClassLoader();
555            thread.setContextClassLoader(this.getClass().getClassLoader());
556            try {
557                try {
558                    definition = wsdlReader.readWSDL(wsdlLocator);
559                } catch (WSDLException e) {
560                    throw new DeploymentException("Failed to read wsdl document", e);
561                }
562            } finally {
563                thread.setContextClassLoader(oldCl);
564            }
565    
566            return definition;
567        }
568    
569        public static ExtensibilityElement getExtensibilityElement(Class clazz, List extensibilityElements) throws DeploymentException {
570            for (Iterator iterator = extensibilityElements.iterator(); iterator.hasNext();) {
571                ExtensibilityElement extensibilityElement = (ExtensibilityElement) iterator.next();
572                if (clazz.isAssignableFrom(extensibilityElement.getClass())) {
573                    return extensibilityElement;
574                }
575            }
576            throw new DeploymentException("No element of class " + clazz.getName() + " found");
577        }
578    
579        public String movePortLocation(String portComponentName, String servletLocation) throws DeploymentException {
580            DefinitionsDocument doc = (DefinitionsDocument) wsdlMap.get(uris.get(0));
581            TDefinitions definitions = doc.getDefinitions();
582            TService[] services = definitions.getServiceArray();
583            for (int i = 0; i < services.length; i++) {
584                TService service = services[i];
585                TPort[] ports = service.getPortArray();
586                for (int j = 0; j < ports.length; j++) {
587                    TPort port = ports[j];
588                    if (port.getName().trim().equals(portComponentName)) {
589                        XmlCursor portCursor = port.newCursor();
590                        try {
591                            if (portCursor.toChild(ADDRESS_QNAME)) {
592                                if (servletLocation == null) {
593                                    String original = portCursor.getAttributeText(LOCATION_QNAME);
594                                    URI originalURI = new URI(original);
595                                    servletLocation = originalURI.getPath();
596                                }
597                                portCursor.setAttributeText(LOCATION_QNAME, WebServiceContainer.LOCATION_REPLACEMENT_TOKEN + servletLocation);
598                                return servletLocation;
599                            }
600                        } catch (URISyntaxException e) {
601                            throw new DeploymentException("Could not construct URI for ejb location in wsdl", e);
602                        } finally {
603                            portCursor.dispose();
604                        }
605                    }
606                }
607            }
608            throw new DeploymentException("No port found with name " + portComponentName + " expected at " + servletLocation);
609        }
610    
611        private class JarEntityResolver implements EntityResolver {
612    
613            private final static String PROJECT_URL_PREFIX = "project://local/";
614    
615            public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
616                //seems like this must be a bug in xmlbeans...
617                if (systemId.indexOf(PROJECT_URL_PREFIX) > -1) {
618                    systemId = systemId.substring(PROJECT_URL_PREFIX.length());
619                }
620                URI location = ((URI) uris.peek()).resolve(systemId);
621                InputStream wsdlInputStream;
622                try {
623                    ZipEntry entry = moduleFile.getEntry(location.toString());
624                    wsdlInputStream = moduleFile.getInputStream(entry);
625                    XmlObject xmlObject = SchemaDocument.Factory.parse(wsdlInputStream);
626                    wsdlMap.put(location, xmlObject);
627                    wsdlInputStream.close();
628                    wsdlInputStream = moduleFile.getInputStream(entry);
629                } catch (XmlException e) {
630                    throw (IOException) new IOException("Could not parse schema document").initCause(e);
631                }
632                return new InputSource(wsdlInputStream);
633            }
634        }
635    
636        class JarWSDLLocator implements WSDLLocator {
637    
638            private final List streams = new ArrayList();
639            private final URI wsdlURI;
640            private URI latestImportURI;
641    
642            public JarWSDLLocator(URI wsdlURI) {
643                this.wsdlURI = wsdlURI;
644            }
645    
646            public InputSource getBaseInputSource() {
647                InputStream wsdlInputStream;
648                try {
649                    ZipEntry entry = moduleFile.getEntry(wsdlURI.toString());
650                    wsdlInputStream = moduleFile.getInputStream(entry);
651                    DefinitionsDocument definition = DefinitionsDocument.Factory.parse(wsdlInputStream);
652                    wsdlMap.put(wsdlURI, definition);
653                    wsdlInputStream.close();
654                    wsdlInputStream = moduleFile.getInputStream(entry);
655                    streams.add(wsdlInputStream);
656                } catch (Exception e) {
657                    throw new RuntimeException("Could not open stream to wsdl file", e);
658                }
659                return new InputSource(wsdlInputStream);
660            }
661    
662            public String getBaseURI() {
663                return wsdlURI.toString();
664            }
665    
666            public InputSource getImportInputSource(String parentLocation, String relativeLocation) {
667                URI parentURI = URI.create(parentLocation);
668                latestImportURI = parentURI.resolve(relativeLocation);
669                InputStream importInputStream;
670                try {
671                    ZipEntry entry = moduleFile.getEntry(latestImportURI.toString());
672                    importInputStream = moduleFile.getInputStream(entry);
673                    try {
674                        DefinitionsDocument definition = DefinitionsDocument.Factory.parse(importInputStream);
675                        importInputStream.close();
676                        wsdlMap.put(latestImportURI, definition);
677                        importInputStream.close();
678                    } catch (XmlException e) {
679                        //probably was a schema rather than wsdl.  If there are real problems they will show up later.
680                    }
681                    importInputStream = moduleFile.getInputStream(entry);
682                    streams.add(importInputStream);
683                } catch (Exception e) {
684                    throw new RuntimeException("Could not open stream to import file", e);
685                }
686                InputSource inputSource = new InputSource(importInputStream);
687                inputSource.setSystemId(getLatestImportURI());
688                return inputSource;
689            }
690    
691            public String getLatestImportURI() {
692                return latestImportURI.toString();
693            }
694    
695            public void close() {
696                for (Iterator iterator = streams.iterator(); iterator.hasNext();) {
697                    InputStream inputStream = (InputStream) iterator.next();
698                    try {
699                        inputStream.close();
700                    } catch (IOException e) {
701                        //ignore
702                    }
703                }
704                streams.clear();
705            }
706        }
707    }