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