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