1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.ws.wsdl.writer;
  27 
  28 
  29 import static com.sun.xml.internal.bind.v2.schemagen.Util.*;
  30 
  31 import com.oracle.webservices.internal.api.databinding.WSDLResolver;
  32 
  33 import com.sun.xml.internal.txw2.TXW;
  34 import com.sun.xml.internal.txw2.TypedXmlWriter;
  35 import com.sun.xml.internal.txw2.output.ResultFactory;
  36 import com.sun.xml.internal.txw2.output.XmlSerializer;
  37 import com.sun.xml.internal.txw2.output.TXWResult;
  38 import com.sun.xml.internal.ws.api.SOAPVersion;
  39 import com.sun.xml.internal.ws.api.WSBinding;
  40 import com.sun.xml.internal.ws.api.model.JavaMethod;
  41 import com.sun.xml.internal.ws.api.model.MEP;
  42 import com.sun.xml.internal.ws.api.model.ParameterBinding;
  43 import com.sun.xml.internal.ws.api.model.SEIModel;
  44 import com.sun.xml.internal.ws.api.model.soap.SOAPBinding;
  45 import com.sun.xml.internal.ws.api.server.Container;
  46 import com.sun.xml.internal.ws.api.wsdl.writer.WSDLGeneratorExtension;
  47 import com.sun.xml.internal.ws.api.wsdl.writer.WSDLGenExtnContext;
  48 import com.sun.xml.internal.ws.model.AbstractSEIModelImpl;
  49 import com.sun.xml.internal.ws.model.CheckedExceptionImpl;
  50 import com.sun.xml.internal.ws.model.JavaMethodImpl;
  51 import com.sun.xml.internal.ws.model.ParameterImpl;
  52 import com.sun.xml.internal.ws.model.WrapperParameter;
  53 import com.sun.xml.internal.ws.util.xml.XmlUtil;
  54 import com.sun.xml.internal.ws.wsdl.parser.SOAPConstants;
  55 import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants;
  56 import com.sun.xml.internal.ws.wsdl.writer.document.Binding;
  57 import com.sun.xml.internal.ws.wsdl.writer.document.BindingOperationType;
  58 import com.sun.xml.internal.ws.wsdl.writer.document.Definitions;
  59 import com.sun.xml.internal.ws.wsdl.writer.document.Fault;
  60 import com.sun.xml.internal.ws.wsdl.writer.document.FaultType;
  61 import com.sun.xml.internal.ws.wsdl.writer.document.Import;
  62 import com.sun.xml.internal.ws.wsdl.writer.document.Message;
  63 import com.sun.xml.internal.ws.wsdl.writer.document.Operation;
  64 import com.sun.xml.internal.ws.wsdl.writer.document.ParamType;
  65 import com.sun.xml.internal.ws.wsdl.writer.document.Port;
  66 import com.sun.xml.internal.ws.wsdl.writer.document.PortType;
  67 import com.sun.xml.internal.ws.wsdl.writer.document.Service;
  68 import com.sun.xml.internal.ws.wsdl.writer.document.Types;
  69 import com.sun.xml.internal.ws.wsdl.writer.document.soap.Body;
  70 import com.sun.xml.internal.ws.wsdl.writer.document.soap.BodyType;
  71 import com.sun.xml.internal.ws.wsdl.writer.document.soap.Header;
  72 import com.sun.xml.internal.ws.wsdl.writer.document.soap.SOAPAddress;
  73 import com.sun.xml.internal.ws.wsdl.writer.document.soap.SOAPFault;
  74 import com.sun.xml.internal.ws.wsdl.writer.document.xsd.Schema;
  75 import com.sun.xml.internal.ws.spi.db.BindingContext;
  76 import com.sun.xml.internal.ws.spi.db.BindingHelper;
  77 import com.sun.xml.internal.ws.spi.db.TypeInfo;
  78 import com.sun.xml.internal.ws.spi.db.WrapperComposite;
  79 import com.sun.xml.internal.ws.util.RuntimeVersion;
  80 import com.sun.xml.internal.ws.policy.jaxws.PolicyWSDLGeneratorExtension;
  81 import com.sun.xml.internal.ws.encoding.soap.streaming.SOAPNamespaceConstants;
  82 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Element;
  83 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexType;
  84 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ExplicitGroup;
  85 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement;
  86 
  87 import javax.jws.soap.SOAPBinding.Style;
  88 import javax.jws.soap.SOAPBinding.Use;
  89 import javax.xml.bind.SchemaOutputResolver;
  90 import javax.xml.namespace.QName;
  91 import javax.xml.transform.Result;
  92 import javax.xml.transform.Transformer;
  93 import javax.xml.transform.TransformerConfigurationException;
  94 import javax.xml.transform.TransformerException;
  95 import javax.xml.transform.TransformerFactory;
  96 import javax.xml.transform.dom.DOMResult;
  97 import javax.xml.transform.dom.DOMSource;
  98 import javax.xml.transform.sax.SAXResult;
  99 import javax.xml.ws.Holder;
 100 import javax.xml.ws.WebServiceException;
 101 
 102 import org.w3c.dom.Document;
 103 
 104 import java.io.IOException;
 105 import java.net.URI;
 106 import java.net.URISyntaxException;
 107 import java.util.ArrayList;
 108 import java.util.HashMap;
 109 import java.util.HashSet;
 110 import java.util.Iterator;
 111 import java.util.List;
 112 import java.util.Set;
 113 
 114 
 115 /**
 116  * Class used to generate WSDLs from a {@link SEIModel}.
 117  *
 118  * @author WS Development Team
 119  */
 120 public class WSDLGenerator {
 121     private JAXWSOutputSchemaResolver resolver;
 122     private WSDLResolver wsdlResolver = null;
 123     private AbstractSEIModelImpl model;
 124     private Definitions serviceDefinitions;
 125     private Definitions portDefinitions;
 126     private Types types;
 127     /**
 128      * Constant String for ".wsdl"
 129      */
 130     private static final String DOT_WSDL = ".wsdl";
 131     /**
 132      * Constant String appended to response message names
 133      */
 134     private static final String RESPONSE = "Response";
 135     /**
 136      * constant String used for part name for wrapped request messages
 137      */
 138     private static final String PARAMETERS = "parameters";
 139     /**
 140      * the part name for unwrappable response messages
 141      */
 142     private static final String RESULT = "parameters";
 143     /**
 144      * the part name for response messages that are not unwrappable
 145      */
 146     private static final String UNWRAPPABLE_RESULT = "result";
 147     /**
 148      * The WSDL namespace
 149      */
 150     private static final String WSDL_NAMESPACE = WSDLConstants.NS_WSDL;
 151 
 152     /**
 153      * the XSD namespace
 154      */
 155     private static final String XSD_NAMESPACE = SOAPNamespaceConstants.XSD;
 156     /**
 157      * the namespace prefix to use for the XSD namespace
 158      */
 159     private static final String XSD_PREFIX = "xsd";
 160     /**
 161      * The SOAP 1.1 namespace
 162      */
 163     private static final String SOAP11_NAMESPACE = SOAPConstants.NS_WSDL_SOAP;
 164     /**
 165      * The SOAP 1.2 namespace
 166      */
 167     private static final String SOAP12_NAMESPACE = SOAPConstants.NS_WSDL_SOAP12;
 168     /**
 169      * The namespace prefix to use for the SOAP 1.1 namespace
 170      */
 171     private static final String SOAP_PREFIX = "soap";
 172     /**
 173      * The namespace prefix to use for the SOAP 1.2 namespace
 174      */
 175     private static final String SOAP12_PREFIX = "soap12";
 176     /**
 177      * The namespace prefix to use for the targetNamespace
 178      */
 179     private static final String TNS_PREFIX = "tns";
 180 
 181     /**
 182      * Constant String "document" used to specify <code>document</code> style
 183      * soapBindings
 184      */
 185     private static final String DOCUMENT = "document";
 186     /**
 187      * Constant String "rpc" used to specify <code>rpc</code> style
 188      * soapBindings
 189      */
 190     private static final String RPC = "rpc";
 191     /**
 192      * Constant String "literal" used to create <code>literal</code> use binddings
 193      */
 194     private static final String LITERAL = "literal";
 195     /**
 196      * Constant String to flag the URL to replace at runtime for the endpoint
 197      */
 198     private static final String REPLACE_WITH_ACTUAL_URL = "REPLACE_WITH_ACTUAL_URL";
 199     private Set<QName> processedExceptions = new HashSet<QName>();
 200     private WSBinding binding;
 201     private String wsdlLocation;
 202     private String portWSDLID;
 203     private String schemaPrefix;
 204     private WSDLGeneratorExtension extension;
 205     List<WSDLGeneratorExtension> extensionHandlers;
 206 
 207     private String endpointAddress = REPLACE_WITH_ACTUAL_URL;
 208     private Container container;
 209     private final Class implType;
 210 
 211     private boolean inlineSchemas;      // TODO
 212     private final boolean disableXmlSecurity;
 213 
 214     /**
 215      * Creates the WSDLGenerator
 216      * @param model The {@link AbstractSEIModelImpl} used to generate the WSDL
 217      * @param wsdlResolver The {@link WSDLResolver} to use resovle names while generating the WSDL
 218      * @param binding specifies which {@link javax.xml.ws.BindingType} to generate
 219      * @param extensions an array {@link WSDLGeneratorExtension} that will
 220      * be invoked to generate WSDL extensions
 221      */
 222     public WSDLGenerator(AbstractSEIModelImpl model, WSDLResolver wsdlResolver, WSBinding binding, Container container,
 223                          Class implType, boolean inlineSchemas, WSDLGeneratorExtension... extensions) {
 224         this(model, wsdlResolver, binding, container, implType, inlineSchemas, false, extensions);
 225     }
 226 
 227     /**
 228      * Creates the WSDLGenerator
 229      * @param model The {@link AbstractSEIModelImpl} used to generate the WSDL
 230      * @param wsdlResolver The {@link WSDLResolver} to use resovle names while generating the WSDL
 231      * @param binding specifies which {@link javax.xml.ws.BindingType} to generate
 232      * @param disableXmlSecurity specifies whether to disable the secure xml processing feature
 233      * @param extensions an array {@link WSDLGeneratorExtension} that will
 234      * be invoked to generate WSDL extensions
 235      */
 236     public WSDLGenerator(AbstractSEIModelImpl model, WSDLResolver wsdlResolver, WSBinding binding, Container container,
 237                          Class implType, boolean inlineSchemas, boolean disableXmlSecurity,
 238                          WSDLGeneratorExtension... extensions) {
 239 
 240         this.model = model;
 241         resolver = new JAXWSOutputSchemaResolver();
 242         this.wsdlResolver = wsdlResolver;
 243         this.binding = binding;
 244         this.container = container;
 245         this.implType = implType;
 246         extensionHandlers = new ArrayList<WSDLGeneratorExtension>();
 247         this.inlineSchemas = inlineSchemas;
 248         this.disableXmlSecurity = disableXmlSecurity;
 249 
 250         // register handlers for default extensions
 251         register(new W3CAddressingWSDLGeneratorExtension());
 252         register(new W3CAddressingMetadataWSDLGeneratorExtension());
 253         register(new PolicyWSDLGeneratorExtension());
 254 
 255         if (container != null) { // on server
 256             WSDLGeneratorExtension[] wsdlGeneratorExtensions = container.getSPI(WSDLGeneratorExtension[].class);
 257             if (wsdlGeneratorExtensions != null) {
 258                 for (WSDLGeneratorExtension wsdlGeneratorExtension : wsdlGeneratorExtensions) {
 259                     register(wsdlGeneratorExtension);
 260                 }
 261             }
 262         }
 263 
 264         for (WSDLGeneratorExtension w : extensions)
 265             register(w);
 266 
 267         this.extension = new WSDLGeneratorExtensionFacade(extensionHandlers.toArray(new WSDLGeneratorExtension[0]));
 268     }
 269 
 270     /**
 271      * Sets the endpoint address string to be written.
 272      * Defaults to {@link #REPLACE_WITH_ACTUAL_URL}.
 273      *
 274      * @param address wsdl:port/soap:address/[@location] value
 275      */
 276     public void setEndpointAddress(String address) {
 277         this.endpointAddress = address;
 278     }
 279 
 280     protected String mangleName(String name) {
 281         return BindingHelper.mangleNameToClassName(name);
 282     }
 283 
 284     /**
 285      * Performes the actual WSDL generation
 286      */
 287     public void doGeneration() {
 288         XmlSerializer serviceWriter;
 289         XmlSerializer portWriter = null;
 290         String fileName = mangleName(model.getServiceQName().getLocalPart());
 291         Result result = wsdlResolver.getWSDL(fileName + DOT_WSDL);
 292         wsdlLocation = result.getSystemId();
 293         serviceWriter = new CommentFilter(ResultFactory.createSerializer(result));
 294         if (model.getServiceQName().getNamespaceURI().equals(model.getTargetNamespace())) {
 295             portWriter = serviceWriter;
 296             schemaPrefix = fileName + "_";
 297         } else {
 298             String wsdlName = mangleName(model.getPortTypeName().getLocalPart());
 299             if (wsdlName.equals(fileName))
 300                 wsdlName += "PortType";
 301             Holder<String> absWSDLName = new Holder<String>();
 302             absWSDLName.value = wsdlName + DOT_WSDL;
 303             result = wsdlResolver.getAbstractWSDL(absWSDLName);
 304 
 305             if (result != null) {
 306                 portWSDLID = result.getSystemId();
 307                 if (portWSDLID.equals(wsdlLocation)) {
 308                     portWriter = serviceWriter;
 309                 } else {
 310                     portWriter = new CommentFilter(ResultFactory.createSerializer(result));
 311                 }
 312             } else {
 313                 portWSDLID = absWSDLName.value;
 314             }
 315             schemaPrefix = new java.io.File(portWSDLID).getName();
 316             int idx = schemaPrefix.lastIndexOf('.');
 317             if (idx > 0)
 318                 schemaPrefix = schemaPrefix.substring(0, idx);
 319             schemaPrefix = mangleName(schemaPrefix) + "_";
 320         }
 321         generateDocument(serviceWriter, portWriter);
 322     }
 323 
 324     /**
 325      * Writing directly to XmlSerializer is a problem, since it doesn't suppress
 326      * xml declaration. Creating filter so that comment is written before TXW writes
 327      * anything in the WSDL.
 328      */
 329     private static class CommentFilter implements XmlSerializer {
 330         final XmlSerializer serializer;
 331         private static final String VERSION_COMMENT =
 332                 " Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is " + RuntimeVersion.VERSION + ". ";
 333 
 334         CommentFilter(XmlSerializer serializer) {
 335             this.serializer = serializer;
 336         }
 337 
 338         @Override
 339         public void startDocument() {
 340             serializer.startDocument();
 341             comment(new StringBuilder(VERSION_COMMENT));
 342             text(new StringBuilder("\n"));
 343         }
 344 
 345         @Override
 346         public void beginStartTag(String uri, String localName, String prefix) {
 347             serializer.beginStartTag(uri, localName, prefix);
 348         }
 349 
 350         @Override
 351         public void writeAttribute(String uri, String localName, String prefix, StringBuilder value) {
 352             serializer.writeAttribute(uri, localName, prefix, value);
 353         }
 354 
 355         @Override
 356         public void writeXmlns(String prefix, String uri) {
 357             serializer.writeXmlns(prefix, uri);
 358         }
 359 
 360         @Override
 361         public void endStartTag(String uri, String localName, String prefix) {
 362             serializer.endStartTag(uri, localName, prefix);
 363         }
 364 
 365         @Override
 366         public void endTag() {
 367             serializer.endTag();
 368         }
 369 
 370         @Override
 371         public void text(StringBuilder text) {
 372             serializer.text(text);
 373         }
 374 
 375         @Override
 376         public void cdata(StringBuilder text) {
 377             serializer.cdata(text);
 378         }
 379 
 380         @Override
 381         public void comment(StringBuilder comment) {
 382             serializer.comment(comment);
 383         }
 384 
 385         @Override
 386         public void endDocument() {
 387             serializer.endDocument();
 388         }
 389 
 390         @Override
 391         public void flush() {
 392             serializer.flush();
 393         }
 394 
 395     }
 396 
 397     private void generateDocument(XmlSerializer serviceStream, XmlSerializer portStream) {
 398         serviceDefinitions = TXW.create(Definitions.class, serviceStream);
 399         serviceDefinitions._namespace(WSDL_NAMESPACE, "");//WSDL_PREFIX);
 400         serviceDefinitions._namespace(XSD_NAMESPACE, XSD_PREFIX);
 401         serviceDefinitions.targetNamespace(model.getServiceQName().getNamespaceURI());
 402         serviceDefinitions._namespace(model.getServiceQName().getNamespaceURI(), TNS_PREFIX);
 403         if (binding.getSOAPVersion() == SOAPVersion.SOAP_12)
 404             serviceDefinitions._namespace(SOAP12_NAMESPACE, SOAP12_PREFIX);
 405         else
 406             serviceDefinitions._namespace(SOAP11_NAMESPACE, SOAP_PREFIX);
 407         serviceDefinitions.name(model.getServiceQName().getLocalPart());
 408         WSDLGenExtnContext serviceCtx = new WSDLGenExtnContext(serviceDefinitions, model, binding, container, implType);
 409         extension.start(serviceCtx);
 410         if (serviceStream != portStream && portStream != null) {
 411             // generate an abstract and concrete wsdl
 412             portDefinitions = TXW.create(Definitions.class, portStream);
 413             portDefinitions._namespace(WSDL_NAMESPACE, "");//WSDL_PREFIX);
 414             portDefinitions._namespace(XSD_NAMESPACE, XSD_PREFIX);
 415             if (model.getTargetNamespace() != null) {
 416                 portDefinitions.targetNamespace(model.getTargetNamespace());
 417                 portDefinitions._namespace(model.getTargetNamespace(), TNS_PREFIX);
 418             }
 419 
 420             String schemaLoc = relativize(portWSDLID, wsdlLocation);
 421             Import _import = serviceDefinitions._import().namespace(model.getTargetNamespace());
 422             _import.location(schemaLoc);
 423         } else if (portStream != null) {
 424             // abstract and concrete are the same
 425             portDefinitions = serviceDefinitions;
 426         } else {
 427             // import a provided abstract wsdl
 428             String schemaLoc = relativize(portWSDLID, wsdlLocation);
 429             Import _import = serviceDefinitions._import().namespace(model.getTargetNamespace());
 430             _import.location(schemaLoc);
 431         }
 432         extension.addDefinitionsExtension(serviceDefinitions);
 433 
 434         if (portDefinitions != null) {
 435             generateTypes();
 436             generateMessages();
 437             generatePortType();
 438         }
 439         generateBinding();
 440         generateService();
 441         //Give a chance to WSDLGeneratorExtensions to write stuff before closing </wsdl:defintions>
 442         extension.end(serviceCtx);
 443         serviceDefinitions.commit();
 444         if (portDefinitions != null && portDefinitions != serviceDefinitions)
 445             portDefinitions.commit();
 446     }
 447 
 448 
 449     /**
 450      * Generates the types section of the WSDL
 451      */
 452     protected void generateTypes() {
 453         types = portDefinitions.types();
 454         if (model.getBindingContext() != null) {
 455             if (inlineSchemas && model.getBindingContext().getClass().getName().indexOf("glassfish") == -1) {
 456                 resolver.nonGlassfishSchemas = new ArrayList<DOMResult>();
 457             }
 458             try {
 459                 model.getBindingContext().generateSchema(resolver);
 460             } catch (IOException e) {
 461                 // TODO locallize and wrap this
 462                 throw new WebServiceException(e.getMessage());
 463             }
 464         }
 465         if (resolver.nonGlassfishSchemas != null) {
 466             TransformerFactory tf = XmlUtil.newTransformerFactory(!disableXmlSecurity);
 467             try {
 468                 Transformer t = tf.newTransformer();
 469                 for (DOMResult xsd : resolver.nonGlassfishSchemas) {
 470                     Document doc = (Document) xsd.getNode();
 471                     SAXResult sax = new SAXResult(new TXWContentHandler(types));
 472                     t.transform(new DOMSource(doc.getDocumentElement()), sax);
 473                 }
 474             } catch (TransformerConfigurationException e) {
 475                 throw new WebServiceException(e.getMessage(), e);
 476             } catch (TransformerException e) {
 477                 throw new WebServiceException(e.getMessage(), e);
 478             }
 479         }
 480         generateWrappers();
 481     }
 482 
 483     void generateWrappers() {
 484         List<WrapperParameter> wrappers = new ArrayList<WrapperParameter>();
 485         for (JavaMethodImpl method : model.getJavaMethods()) {
 486             if(method.getBinding().isRpcLit()) continue;
 487             for (ParameterImpl p : method.getRequestParameters()) {
 488                 if (p instanceof WrapperParameter) {
 489                     if (WrapperComposite.class.equals((((WrapperParameter)p).getTypeInfo().type))) {
 490                         wrappers.add((WrapperParameter)p);
 491                     }
 492                 }
 493             }
 494             for (ParameterImpl p : method.getResponseParameters()) {
 495                 if (p instanceof WrapperParameter) {
 496                     if (WrapperComposite.class.equals((((WrapperParameter)p).getTypeInfo().type))) {
 497                         wrappers.add((WrapperParameter)p);
 498                     }
 499                 }
 500             }
 501         }
 502         if (wrappers.isEmpty()) return;
 503         HashMap<String, Schema> xsds = new HashMap<String, Schema>();
 504         for(WrapperParameter wp : wrappers) {
 505             String tns = wp.getName().getNamespaceURI();
 506             Schema xsd = xsds.get(tns);
 507             if (xsd == null) {
 508                 xsd = types.schema();
 509                 xsd.targetNamespace(tns);
 510                 xsds.put(tns, xsd);
 511             }
 512             Element e =  xsd._element(Element.class);
 513             e._attribute("name", wp.getName().getLocalPart());
 514             e.type(wp.getName());
 515             ComplexType ct =  xsd._element(ComplexType.class);
 516             ct._attribute("name", wp.getName().getLocalPart());
 517             ExplicitGroup sq = ct.sequence();
 518             for (ParameterImpl p : wp.getWrapperChildren() ) {
 519                 if (p.getBinding().isBody()) {
 520                     LocalElement le = sq.element();
 521                     le._attribute("name", p.getName().getLocalPart());
 522                     TypeInfo typeInfo = p.getItemType();
 523                     boolean repeatedElement = false;
 524                     if (typeInfo == null) {
 525                         typeInfo = p.getTypeInfo();
 526                     } else {
 527                         repeatedElement = true;
 528                     }
 529                     QName type = model.getBindingContext().getTypeName(typeInfo);
 530                     le.type(type);
 531                     if (repeatedElement) {
 532                         le.minOccurs(0);
 533                         le.maxOccurs("unbounded");
 534                     }
 535                 }
 536             }
 537         }
 538     }
 539 
 540     /**
 541      * Generates the WSDL messages
 542      */
 543     protected void generateMessages() {
 544         for (JavaMethodImpl method : model.getJavaMethods()) {
 545             generateSOAPMessages(method, method.getBinding());
 546         }
 547     }
 548 
 549     /**
 550      * Generates messages for a SOAPBinding
 551      * @param method The {@link JavaMethod} to generate messages for
 552      * @param binding The {@link com.sun.xml.internal.ws.api.model.soap.SOAPBinding} to add the generated messages to
 553      */
 554     protected void generateSOAPMessages(JavaMethodImpl method, com.sun.xml.internal.ws.api.model.soap.SOAPBinding binding) {
 555         boolean isDoclit = binding.isDocLit();
 556 //        Message message = portDefinitions.message().name(method.getOperation().getName().getLocalPart());
 557         Message message = portDefinitions.message().name(method.getRequestMessageName());
 558         extension.addInputMessageExtension(message, method);
 559         com.sun.xml.internal.ws.wsdl.writer.document.Part part;
 560         BindingContext jaxbContext = model.getBindingContext();
 561         boolean unwrappable = true;
 562         for (ParameterImpl param : method.getRequestParameters()) {
 563             if (isDoclit) {
 564                 if (isHeaderParameter(param))
 565                     unwrappable = false;
 566 
 567                 part = message.part().name(param.getPartName());
 568                 part.element(param.getName());
 569             } else {
 570                 if (param.isWrapperStyle()) {
 571                     for (ParameterImpl childParam : ((WrapperParameter) param).getWrapperChildren()) {
 572                         part = message.part().name(childParam.getPartName());
 573                         part.type(jaxbContext.getTypeName(childParam.getXMLBridge().getTypeInfo()));
 574                     }
 575                 } else {
 576                     part = message.part().name(param.getPartName());
 577                     part.element(param.getName());
 578                 }
 579             }
 580         }
 581         if (method.getMEP() != MEP.ONE_WAY) {
 582             message = portDefinitions.message().name(method.getResponseMessageName());
 583             extension.addOutputMessageExtension(message, method);
 584 
 585             for (ParameterImpl param : method.getResponseParameters()) {
 586                 if (isDoclit) {
 587                     part = message.part().name(param.getPartName());
 588                     part.element(param.getName());
 589 
 590                 } else {
 591                     if (param.isWrapperStyle()) {
 592                         for (ParameterImpl childParam : ((WrapperParameter) param).getWrapperChildren()) {
 593                             part = message.part().name(childParam.getPartName());
 594                             part.type(jaxbContext.getTypeName(childParam.getXMLBridge().getTypeInfo()));
 595                         }
 596                     } else {
 597                         part = message.part().name(param.getPartName());
 598                         part.element(param.getName());
 599                     }
 600                 }
 601             }
 602         }
 603         for (CheckedExceptionImpl exception : method.getCheckedExceptions()) {
 604             QName tagName = exception.getDetailType().tagName;
 605             String messageName = exception.getMessageName();
 606             QName messageQName = new QName(model.getTargetNamespace(), messageName);
 607             if (processedExceptions.contains(messageQName))
 608                 continue;
 609             message = portDefinitions.message().name(messageName);
 610 
 611             extension.addFaultMessageExtension(message, method, exception);
 612             part = message.part().name("fault");//tagName.getLocalPart());
 613             part.element(tagName);
 614             processedExceptions.add(messageQName);
 615         }
 616     }
 617 
 618     /**
 619      * Generates the WSDL portType
 620      */
 621     protected void generatePortType() {
 622 
 623         PortType portType = portDefinitions.portType().name(model.getPortTypeName().getLocalPart());
 624         extension.addPortTypeExtension(portType);
 625         for (JavaMethodImpl method : model.getJavaMethods()) {
 626             Operation operation = portType.operation().name(method.getOperationName());
 627             generateParameterOrder(operation, method);
 628             extension.addOperationExtension(operation, method);
 629             switch (method.getMEP()) {
 630                 case REQUEST_RESPONSE:
 631                     // input message
 632                     generateInputMessage(operation, method);
 633                     // output message
 634                     generateOutputMessage(operation, method);
 635                     break;
 636                 case ONE_WAY:
 637                     generateInputMessage(operation, method);
 638                     break;
 639                 default:
 640                     break;
 641             }
 642             // faults
 643             for (CheckedExceptionImpl exception : method.getCheckedExceptions()) {
 644                 QName messageName = new QName(model.getTargetNamespace(), exception.getMessageName());
 645                 FaultType paramType = operation.fault().message(messageName).name(exception.getMessageName());
 646                 extension.addOperationFaultExtension(paramType, method, exception);
 647             }
 648         }
 649     }
 650 
 651     /**
 652      * Determines if the <CODE>method</CODE> is wrapper style
 653      * @param method The {@link JavaMethod} to check if it is wrapper style
 654      * @return true if the method is wrapper style, otherwise, false.
 655      */
 656     protected boolean isWrapperStyle(JavaMethodImpl method) {
 657         if (method.getRequestParameters().size() > 0) {
 658             ParameterImpl param = method.getRequestParameters().iterator().next();
 659             return param.isWrapperStyle();
 660         }
 661         return false;
 662     }
 663 
 664     /**
 665      * Determines if a {@link JavaMethod} is rpc/literal
 666      * @param method The method to check
 667      * @return true if method is rpc/literal, otherwise, false
 668      */
 669     protected boolean isRpcLit(JavaMethodImpl method) {
 670         return method.getBinding().getStyle() == Style.RPC;
 671     }
 672 
 673     /**
 674      * Generates the parameterOrder for a PortType operation
 675      * @param operation The operation to generate the parameterOrder for
 676      * @param method The {@link JavaMethod} to generate the parameterOrder from
 677      */
 678     protected void generateParameterOrder(Operation operation, JavaMethodImpl method) {
 679         if (method.getMEP() == MEP.ONE_WAY)
 680             return;
 681         if (isRpcLit(method))
 682             generateRpcParameterOrder(operation, method);
 683         else
 684             generateDocumentParameterOrder(operation, method);
 685     }
 686 
 687     /**
 688      * Generates the parameterOrder for a PortType operation
 689      * @param operation the operation to generate the parameterOrder for
 690      * @param method the {@link JavaMethod} to generate the parameterOrder from
 691      */
 692     protected void generateRpcParameterOrder(Operation operation, JavaMethodImpl method) {
 693         String partName;
 694         StringBuilder paramOrder = new StringBuilder();
 695         Set<String> partNames = new HashSet<String>();
 696         List<ParameterImpl> sortedParams = sortMethodParameters(method);
 697         int i = 0;
 698         for (ParameterImpl parameter : sortedParams) {
 699             if (parameter.getIndex() >= 0) {
 700                 partName = parameter.getPartName();
 701                 if (!partNames.contains(partName)) {
 702                     if (i++ > 0)
 703                         paramOrder.append(' ');
 704                     paramOrder.append(partName);
 705                     partNames.add(partName);
 706                 }
 707             }
 708         }
 709         if (i > 1) {
 710             operation.parameterOrder(paramOrder.toString());
 711         }
 712     }
 713 
 714 
 715     /**
 716      * Generates the parameterOrder for a PortType operation
 717      * @param operation the operation to generate the parameterOrder for
 718      * @param method the {@link JavaMethod} to generate the parameterOrder from
 719      */
 720     protected void generateDocumentParameterOrder(Operation operation, JavaMethodImpl method) {
 721         String partName;
 722         StringBuilder paramOrder = new StringBuilder();
 723         Set<String> partNames = new HashSet<String>();
 724         List<ParameterImpl> sortedParams = sortMethodParameters(method);
 725 //        boolean isWrapperStyle = isWrapperStyle(method);
 726         int i = 0;
 727         for (ParameterImpl parameter : sortedParams) {
 728 //            System.out.println("param: "+parameter.getIndex()+" name: "+parameter.getName().getLocalPart());
 729             if (parameter.getIndex() < 0)
 730                 continue;
 731 
 732             // This should be safe change. if it affects compatibility,
 733             // remove the following single statement and uncomment the code in block below.
 734             partName = parameter.getPartName();
 735             /*
 736             if (isWrapperStyle && isBodyParameter(parameter)) {
 737                System.out.println("isWrapper and is body");
 738                 if (method.getRequestParameters().contains(parameter))
 739                     partName = PARAMETERS;
 740                 else {
 741                     //Rama: don't understand this logic "Response" below,
 742 
 743                     // really make sure this is a wrapper style wsdl we are creating
 744                     partName = RESPONSE;
 745                 }
 746             } else {
 747                partName = parameter.getPartName();
 748             }*/
 749 
 750             if (!partNames.contains(partName)) {
 751                 if (i++ > 0)
 752                     paramOrder.append(' ');
 753                 paramOrder.append(partName);
 754                 partNames.add(partName);
 755             }
 756         }
 757         if (i > 1) {
 758             operation.parameterOrder(paramOrder.toString());
 759         }
 760     }
 761 
 762     /**
 763      * Sorts the parameters for the method by their position
 764      * @param method the {@link JavaMethod} used to sort the parameters
 765      * @return the sorted {@link List} of parameters
 766      */
 767     protected List<ParameterImpl> sortMethodParameters(JavaMethodImpl method) {
 768         Set<ParameterImpl> paramSet = new HashSet<ParameterImpl>();
 769         List<ParameterImpl> sortedParams = new ArrayList<ParameterImpl>();
 770         if (isRpcLit(method)) {
 771             for (ParameterImpl param : method.getRequestParameters()) {
 772                 if (param instanceof WrapperParameter) {
 773                     paramSet.addAll(((WrapperParameter) param).getWrapperChildren());
 774                 } else {
 775                     paramSet.add(param);
 776                 }
 777             }
 778             for (ParameterImpl param : method.getResponseParameters()) {
 779                 if (param instanceof WrapperParameter) {
 780                     paramSet.addAll(((WrapperParameter) param).getWrapperChildren());
 781                 } else {
 782                     paramSet.add(param);
 783                 }
 784             }
 785         } else {
 786             paramSet.addAll(method.getRequestParameters());
 787             paramSet.addAll(method.getResponseParameters());
 788         }
 789         Iterator<ParameterImpl> params = paramSet.iterator();
 790         if (paramSet.isEmpty())
 791             return sortedParams;
 792         ParameterImpl param = params.next();
 793         sortedParams.add(param);
 794         ParameterImpl sortedParam;
 795         int pos;
 796         for (int i = 1; i < paramSet.size(); i++) {
 797             param = params.next();
 798             for (pos = 0; pos < i; pos++) {
 799                 sortedParam = sortedParams.get(pos);
 800                 if (param.getIndex() == sortedParam.getIndex() &&
 801                         param instanceof WrapperParameter)
 802                     break;
 803                 if (param.getIndex() < sortedParam.getIndex()) {
 804                     break;
 805                 }
 806             }
 807             sortedParams.add(pos, param);
 808         }
 809         return sortedParams;
 810     }
 811 
 812     /**
 813      * Determines if a parameter is associated with the message Body
 814      * @param parameter the parameter to check
 815      * @return true if the parameter is a <code>body</code> parameter
 816      */
 817     protected boolean isBodyParameter(ParameterImpl parameter) {
 818         ParameterBinding paramBinding = parameter.getBinding();
 819         return paramBinding.isBody();
 820     }
 821 
 822     protected boolean isHeaderParameter(ParameterImpl parameter) {
 823         ParameterBinding paramBinding = parameter.getBinding();
 824         return paramBinding.isHeader();
 825     }
 826 
 827     protected boolean isAttachmentParameter(ParameterImpl parameter) {
 828         ParameterBinding paramBinding = parameter.getBinding();
 829         return paramBinding.isAttachment();
 830     }
 831 
 832 
 833     /**
 834      * Generates the Binding section of the WSDL
 835      */
 836     protected void generateBinding() {
 837         Binding newBinding = serviceDefinitions.binding().name(model.getBoundPortTypeName().getLocalPart());
 838         extension.addBindingExtension(newBinding);
 839         newBinding.type(model.getPortTypeName());
 840         boolean first = true;
 841         for (JavaMethodImpl method : model.getJavaMethods()) {
 842             if (first) {
 843                 SOAPBinding sBinding = method.getBinding();
 844                 SOAPVersion soapVersion = sBinding.getSOAPVersion();
 845                 if (soapVersion == SOAPVersion.SOAP_12) {
 846                     com.sun.xml.internal.ws.wsdl.writer.document.soap12.SOAPBinding soapBinding = newBinding.soap12Binding();
 847                     soapBinding.transport(this.binding.getBindingId().getTransport());
 848                     if (sBinding.getStyle().equals(Style.DOCUMENT))
 849                         soapBinding.style(DOCUMENT);
 850                     else
 851                         soapBinding.style(RPC);
 852                 } else {
 853                     com.sun.xml.internal.ws.wsdl.writer.document.soap.SOAPBinding soapBinding = newBinding.soapBinding();
 854                     soapBinding.transport(this.binding.getBindingId().getTransport());
 855                     if (sBinding.getStyle().equals(Style.DOCUMENT))
 856                         soapBinding.style(DOCUMENT);
 857                     else
 858                         soapBinding.style(RPC);
 859                 }
 860                 first = false;
 861             }
 862             if (this.binding.getBindingId().getSOAPVersion() == SOAPVersion.SOAP_12)
 863                 generateSOAP12BindingOperation(method, newBinding);
 864             else
 865                 generateBindingOperation(method, newBinding);
 866         }
 867     }
 868 
 869     protected void generateBindingOperation(JavaMethodImpl method, Binding binding) {
 870         BindingOperationType operation = binding.operation().name(method.getOperationName());
 871         extension.addBindingOperationExtension(operation, method);
 872         String targetNamespace = model.getTargetNamespace();
 873         QName requestMessage = new QName(targetNamespace, method.getOperationName());
 874         List<ParameterImpl> bodyParams = new ArrayList<ParameterImpl>();
 875         List<ParameterImpl> headerParams = new ArrayList<ParameterImpl>();
 876         splitParameters(bodyParams, headerParams, method.getRequestParameters());
 877         SOAPBinding soapBinding = method.getBinding();
 878         operation.soapOperation().soapAction(soapBinding.getSOAPAction());
 879 
 880         // input
 881         TypedXmlWriter input = operation.input();
 882         extension.addBindingOperationInputExtension(input, method);
 883         BodyType body = input._element(Body.class);
 884         boolean isRpc = soapBinding.getStyle().equals(Style.RPC);
 885         if (soapBinding.getUse() == Use.LITERAL) {
 886             body.use(LITERAL);
 887             if (headerParams.size() > 0) {
 888                 if (bodyParams.size() > 0) {
 889                     ParameterImpl param = bodyParams.iterator().next();
 890                     if (isRpc) {
 891                         StringBuilder parts = new StringBuilder();
 892                         int i = 0;
 893                         for (ParameterImpl parameter : ((WrapperParameter) param).getWrapperChildren()) {
 894                             if (i++ > 0)
 895                                 parts.append(' ');
 896                             parts.append(parameter.getPartName());
 897                         }
 898                         body.parts(parts.toString());
 899                     } else {
 900                         body.parts(param.getPartName());
 901                     }
 902                 } else {
 903                     body.parts("");
 904                 }
 905                 generateSOAPHeaders(input, headerParams, requestMessage);
 906             }
 907             if (isRpc) {
 908                 body.namespace(method.getRequestParameters().iterator().next().getName().getNamespaceURI());
 909             }
 910         } else {
 911             // TODO localize this
 912             throw new WebServiceException("encoded use is not supported");
 913         }
 914 
 915         if (method.getMEP() != MEP.ONE_WAY) {
 916             // output
 917             bodyParams.clear();
 918             headerParams.clear();
 919             splitParameters(bodyParams, headerParams, method.getResponseParameters());
 920             TypedXmlWriter output = operation.output();
 921             extension.addBindingOperationOutputExtension(output, method);
 922             body = output._element(Body.class);
 923             body.use(LITERAL);
 924             if (headerParams.size() > 0) {
 925                 StringBuilder parts = new StringBuilder();
 926                 if (bodyParams.size() > 0) {
 927                     ParameterImpl param = bodyParams.iterator().hasNext() ? bodyParams.iterator().next() : null;
 928                     if (param != null) {
 929                         if (isRpc) {
 930                             int i = 0;
 931                             for (ParameterImpl parameter : ((WrapperParameter) param).getWrapperChildren()) {
 932                                 if (i++ > 0) {
 933                                     parts.append(" ");
 934                                 }
 935                                 parts.append(parameter.getPartName());
 936                             }
 937                         } else {
 938                             parts = new StringBuilder(param.getPartName());
 939                         }
 940                     }
 941                 }
 942                 body.parts(parts.toString());
 943                 QName responseMessage = new QName(targetNamespace, method.getResponseMessageName());
 944                 generateSOAPHeaders(output, headerParams, responseMessage);
 945             }
 946             if (isRpc) {
 947                 body.namespace(method.getRequestParameters().iterator().next().getName().getNamespaceURI());
 948             }
 949         }
 950         for (CheckedExceptionImpl exception : method.getCheckedExceptions()) {
 951             Fault fault = operation.fault().name(exception.getMessageName());
 952             extension.addBindingOperationFaultExtension(fault, method, exception);
 953             SOAPFault soapFault = fault._element(SOAPFault.class).name(exception.getMessageName());
 954             soapFault.use(LITERAL);
 955         }
 956     }
 957 
 958     protected void generateSOAP12BindingOperation(JavaMethodImpl method, Binding binding) {
 959         BindingOperationType operation = binding.operation().name(method.getOperationName());
 960         extension.addBindingOperationExtension(operation, method);
 961         String targetNamespace = model.getTargetNamespace();
 962         QName requestMessage = new QName(targetNamespace, method.getOperationName());
 963         ArrayList<ParameterImpl> bodyParams = new ArrayList<ParameterImpl>();
 964         ArrayList<ParameterImpl> headerParams = new ArrayList<ParameterImpl>();
 965         splitParameters(bodyParams, headerParams, method.getRequestParameters());
 966         SOAPBinding soapBinding = method.getBinding();
 967 
 968         String soapAction = soapBinding.getSOAPAction();
 969         if (soapAction != null) {
 970             operation.soap12Operation().soapAction(soapAction);
 971         }
 972 
 973         // input
 974         TypedXmlWriter input = operation.input();
 975         extension.addBindingOperationInputExtension(input, method);
 976         com.sun.xml.internal.ws.wsdl.writer.document.soap12.BodyType body = input._element(com.sun.xml.internal.ws.wsdl.writer.document.soap12.Body.class);
 977         boolean isRpc = soapBinding.getStyle().equals(Style.RPC);
 978         if (soapBinding.getUse().equals(Use.LITERAL)) {
 979             body.use(LITERAL);
 980             if (headerParams.size() > 0) {
 981                 if (bodyParams.size() > 0) {
 982                     ParameterImpl param = bodyParams.iterator().next();
 983                     if (isRpc) {
 984                         StringBuilder parts = new StringBuilder();
 985                         int i = 0;
 986                         for (ParameterImpl parameter : ((WrapperParameter) param).getWrapperChildren()) {
 987                             if (i++ > 0)
 988                                 parts.append(' ');
 989                             parts.append(parameter.getPartName());
 990                         }
 991                         body.parts(parts.toString());
 992                     } else {
 993                         body.parts(param.getPartName());
 994                     }
 995                 } else {
 996                     body.parts("");
 997                 }
 998                 generateSOAP12Headers(input, headerParams, requestMessage);
 999             }
1000             if (isRpc) {
1001                 body.namespace(method.getRequestParameters().iterator().next().getName().getNamespaceURI());
1002             }
1003         } else {
1004             // TODO localize this
1005             throw new WebServiceException("encoded use is not supported");
1006         }
1007 
1008         if (method.getMEP() != MEP.ONE_WAY) {
1009             // output
1010             bodyParams.clear();
1011             headerParams.clear();
1012             splitParameters(bodyParams, headerParams, method.getResponseParameters());
1013             TypedXmlWriter output = operation.output();
1014             extension.addBindingOperationOutputExtension(output, method);
1015             body = output._element(com.sun.xml.internal.ws.wsdl.writer.document.soap12.Body.class);
1016             body.use(LITERAL);
1017             if (headerParams.size() > 0) {
1018                 if (bodyParams.size() > 0) {
1019                     ParameterImpl param = bodyParams.iterator().next();
1020                     if (isRpc) {
1021                         StringBuilder parts = new StringBuilder();
1022                         int i = 0;
1023                         for (ParameterImpl parameter : ((WrapperParameter) param).getWrapperChildren()) {
1024                             if (i++ > 0) {
1025                                 parts.append(" ");
1026                             }
1027                             parts.append(parameter.getPartName());
1028                         }
1029                         body.parts(parts.toString());
1030                     } else {
1031                         body.parts(param.getPartName());
1032                     }
1033                 } else {
1034                     body.parts("");
1035                 }
1036                 QName responseMessage = new QName(targetNamespace, method.getResponseMessageName());
1037                 generateSOAP12Headers(output, headerParams, responseMessage);
1038             }
1039             if (isRpc) {
1040                 body.namespace(method.getRequestParameters().iterator().next().getName().getNamespaceURI());
1041             }
1042         }
1043         for (CheckedExceptionImpl exception : method.getCheckedExceptions()) {
1044             Fault fault = operation.fault().name(exception.getMessageName());
1045             extension.addBindingOperationFaultExtension(fault, method, exception);
1046             com.sun.xml.internal.ws.wsdl.writer.document.soap12.SOAPFault soapFault = fault._element(com.sun.xml.internal.ws.wsdl.writer.document.soap12.SOAPFault.class).name(exception.getMessageName());
1047             soapFault.use(LITERAL);
1048         }
1049     }
1050 
1051     protected void splitParameters(List<ParameterImpl> bodyParams, List<ParameterImpl> headerParams, List<ParameterImpl> params) {
1052         for (ParameterImpl parameter : params) {
1053             if (isBodyParameter(parameter)) {
1054                 bodyParams.add(parameter);
1055             } else {
1056                 headerParams.add(parameter);
1057             }
1058         }
1059     }
1060 
1061     protected void generateSOAPHeaders(TypedXmlWriter writer, List<ParameterImpl> parameters, QName message) {
1062 
1063         for (ParameterImpl headerParam : parameters) {
1064             Header header = writer._element(Header.class);
1065             header.message(message);
1066             header.part(headerParam.getPartName());
1067             header.use(LITERAL);
1068         }
1069     }
1070 
1071     protected void generateSOAP12Headers(TypedXmlWriter writer, List<ParameterImpl> parameters, QName message) {
1072 
1073         for (ParameterImpl headerParam : parameters) {
1074             com.sun.xml.internal.ws.wsdl.writer.document.soap12.Header header = writer._element(com.sun.xml.internal.ws.wsdl.writer.document.soap12.Header.class);
1075             header.message(message);
1076 
1077 
1078             header.part(headerParam.getPartName());
1079             header.use(LITERAL);
1080         }
1081     }
1082 
1083     /**
1084      * Generates the Service section of the WSDL
1085      */
1086     protected void generateService() {
1087         QName portQName = model.getPortName();
1088         QName serviceQName = model.getServiceQName();
1089         Service service = serviceDefinitions.service().name(serviceQName.getLocalPart());
1090         extension.addServiceExtension(service);
1091         Port port = service.port().name(portQName.getLocalPart());
1092         port.binding(model.getBoundPortTypeName());
1093         extension.addPortExtension(port);
1094         if (model.getJavaMethods().isEmpty())
1095             return;
1096 
1097         if (this.binding.getBindingId().getSOAPVersion() == SOAPVersion.SOAP_12) {
1098             com.sun.xml.internal.ws.wsdl.writer.document.soap12.SOAPAddress address = port._element(com.sun.xml.internal.ws.wsdl.writer.document.soap12.SOAPAddress.class);
1099             address.location(endpointAddress);
1100         } else {
1101             SOAPAddress address = port._element(SOAPAddress.class);
1102             address.location(endpointAddress);
1103         }
1104     }
1105 
1106     protected void generateInputMessage(Operation operation, JavaMethodImpl method) {
1107         ParamType paramType = operation.input();
1108         extension.addOperationInputExtension(paramType, method);
1109 //        paramType.message(method.getOperation().getName());
1110         paramType.message(new QName(model.getTargetNamespace(), method.getRequestMessageName()));
1111     }
1112 
1113     protected void generateOutputMessage(Operation operation, JavaMethodImpl method) {
1114         ParamType paramType = operation.output();
1115         extension.addOperationOutputExtension(paramType, method);
1116 //        paramType.message(new QName(model.getTargetNamespace(), method.getOperation().getLocalName()+RESPONSE));
1117         paramType.message(new QName(model.getTargetNamespace(), method.getResponseMessageName()));
1118     }
1119 
1120     /**
1121      * Creates the {@link Result} object used by JAXB to generate a schema for the
1122      * namesapceUri namespace.
1123      * @param namespaceUri The namespace for the schema being generated
1124      * @param suggestedFileName the JAXB suggested file name for the schema file
1125      * @return the {@link Result} for JAXB to generate the schema into
1126      * @throws java.io.IOException thrown if on IO error occurs
1127      */
1128     public Result createOutputFile(String namespaceUri, String suggestedFileName) throws IOException {
1129         Result result;
1130         if (namespaceUri == null) {
1131             return null;
1132         }
1133 
1134         Holder<String> fileNameHolder = new Holder<String>();
1135         fileNameHolder.value = schemaPrefix + suggestedFileName;
1136         result = wsdlResolver.getSchemaOutput(namespaceUri, fileNameHolder);
1137 //        System.out.println("schema file: "+fileNameHolder.value);
1138 //        System.out.println("result: "+result);
1139         String schemaLoc;
1140         if (result == null)
1141             schemaLoc = fileNameHolder.value;
1142         else
1143             schemaLoc = relativize(result.getSystemId(), wsdlLocation);
1144         boolean isEmptyNs = namespaceUri.trim().equals("");
1145         if (!isEmptyNs) {
1146             com.sun.xml.internal.ws.wsdl.writer.document.xsd.Import _import = types.schema()._import();
1147             _import.namespace(namespaceUri);
1148             _import.schemaLocation(schemaLoc);
1149         }
1150         return result;
1151     }
1152 
1153     private Result createInlineSchema(String namespaceUri, String suggestedFileName) throws IOException {
1154         Result result;
1155         if (namespaceUri.equals("")) {
1156             return null;
1157         }
1158 
1159 //        Holder<String> fileNameHolder = new Holder<String>();
1160 //        fileNameHolder.value = schemaPrefix+suggestedFileName;
1161 //        result = wsdlResolver.getSchemaOutput(namespaceUri, fileNameHolder);
1162 //        if (result == null) {
1163 //            // JAXB doesn't have to generate it, a schema is already available
1164 //            com.sun.xml.internal.ws.wsdl.writer.document.xsd.Import _import = types.schema()._import().namespace(namespaceUri);
1165 //            _import.schemaLocation(fileNameHolder.value);
1166 //        } else {
1167         // Let JAXB write the schema directly into wsdl's TypedXmlWriter
1168         result = new TXWResult(types);
1169         result.setSystemId("");
1170 //        }
1171         return result;
1172     }
1173 
1174     /**
1175      * Relativizes a URI by using another URI (base URI.)
1176      *
1177      * <p>
1178      * For example, {@code relative("http://www.sun.com/abc/def","http://www.sun.com/pqr/stu") => "../abc/def"}
1179      *
1180      * <p>
1181      * This method only works on hierarchical URI's, not opaque URI's (refer to the
1182      * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/net/URI.html">java.net.URI</a>
1183      * javadoc for complete definitions of these terms.
1184      *
1185      * <p>
1186      * This method will not normalize the relative URI.
1187      * @param uri the URI to relativize
1188      *
1189      *
1190      * @param baseUri the base URI to use for the relativization
1191      * @return the relative URI or the original URI if a relative one could not be computed
1192      */
1193     protected static String relativize(String uri, String baseUri) {
1194         try {
1195             assert uri != null;
1196 
1197             if (baseUri == null) return uri;
1198 
1199             URI theUri = new URI(escapeURI(uri));
1200             URI theBaseUri = new URI(escapeURI(baseUri));
1201 
1202             if (theUri.isOpaque() || theBaseUri.isOpaque())
1203                 return uri;
1204 
1205             if (!equalsIgnoreCase(theUri.getScheme(), theBaseUri.getScheme()) ||
1206                     !equal(theUri.getAuthority(), theBaseUri.getAuthority()))
1207                 return uri;
1208 
1209             String uriPath = theUri.getPath();
1210             String basePath = theBaseUri.getPath();
1211 
1212             // normalize base path
1213             if (!basePath.endsWith("/")) {
1214                 basePath = normalizeUriPath(basePath);
1215             }
1216 
1217             if (uriPath.equals(basePath))
1218                 return ".";
1219 
1220             String relPath = calculateRelativePath(uriPath, basePath);
1221 
1222             if (relPath == null)
1223                 return uri; // recursion found no commonality in the two uris at all
1224             StringBuilder relUri = new StringBuilder();
1225             relUri.append(relPath);
1226             if (theUri.getQuery() != null)
1227                 relUri.append('?').append(theUri.getQuery());
1228             if (theUri.getFragment() != null)
1229                 relUri.append('#').append(theUri.getFragment());
1230 
1231             return relUri.toString();
1232         } catch (URISyntaxException e) {
1233             throw new InternalError("Error escaping one of these uris:\n\t" + uri + "\n\t" + baseUri);
1234         }
1235     }
1236 
1237     private static String calculateRelativePath(String uri, String base) {
1238         if (base == null) {
1239             return null;
1240         }
1241         if (uri.startsWith(base)) {
1242             return uri.substring(base.length());
1243         } else {
1244             return "../" + calculateRelativePath(uri, getParentUriPath(base));
1245         }
1246     }
1247 
1248 
1249     /**
1250      * Implements the SchemaOutputResolver used by JAXB to
1251      */
1252     protected class JAXWSOutputSchemaResolver extends SchemaOutputResolver {
1253         ArrayList<DOMResult> nonGlassfishSchemas = null;
1254 
1255         /**
1256          * Creates the {@link Result} object used by JAXB to generate a schema for the
1257          * namesapceUri namespace.
1258          * @param namespaceUri The namespace for the schema being generated
1259          * @param suggestedFileName the JAXB suggested file name for the schema file
1260          * @return the {@link Result} for JAXB to generate the schema into
1261          * @throws java.io.IOException thrown if on IO error occurs
1262          */
1263         @Override
1264         public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
1265             return inlineSchemas
1266                     ? ((nonGlassfishSchemas != null) ? nonGlassfishSchemaResult(namespaceUri, suggestedFileName) : createInlineSchema(namespaceUri, suggestedFileName))
1267 //                    ? createInlineSchema(namespaceUri, suggestedFileName)
1268                     : createOutputFile(namespaceUri, suggestedFileName);
1269         }
1270 
1271         private Result nonGlassfishSchemaResult(String namespaceUri, String suggestedFileName) throws IOException {
1272             DOMResult result = new DOMResult();
1273             result.setSystemId("");
1274             nonGlassfishSchemas.add(result);
1275             return result;
1276         }
1277     }
1278 
1279     private void register(WSDLGeneratorExtension h) {
1280         extensionHandlers.add(h);
1281     }
1282 }