src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLGenerator.java

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

mercurial