1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.wsdl.wsdl11.builder;
18
19 import java.io.IOException;
20 import java.util.Iterator;
21 import java.util.List;
22 import javax.wsdl.Definition;
23 import javax.wsdl.Fault;
24 import javax.wsdl.Input;
25 import javax.wsdl.Message;
26 import javax.wsdl.Operation;
27 import javax.wsdl.OperationType;
28 import javax.wsdl.Output;
29 import javax.wsdl.Part;
30 import javax.wsdl.PortType;
31 import javax.wsdl.Service;
32 import javax.wsdl.Types;
33 import javax.wsdl.WSDLException;
34 import javax.wsdl.extensions.schema.Schema;
35 import javax.xml.namespace.QName;
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42 import org.xml.sax.SAXException;
43
44 import org.springframework.beans.factory.InitializingBean;
45 import org.springframework.core.io.Resource;
46 import org.springframework.util.Assert;
47 import org.springframework.util.StringUtils;
48 import org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition;
49 import org.springframework.xml.namespace.QNameUtils;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public class XsdBasedSoap12Wsdl4jDefinitionBuilder extends AbstractSoap12Wsdl4jDefinitionBuilder
90 implements InitializingBean {
91
92
93 public static final String DEFAULT_REQUEST_SUFFIX = "Request";
94
95
96 public static final String DEFAULT_RESPONSE_SUFFIX = "Response";
97
98
99 public static final String DEFAULT_FAULT_SUFFIX = "Fault";
100
101
102 public static final String DEFAULT_SCHEMA_PREFIX = "schema";
103
104
105 public static final String DEFAULT_PREFIX = "tns";
106
107
108 public static final String SERVICE_SUFFIX = "Service";
109
110 private Resource schemaResource;
111
112 private XsdSchemaHelper schemaHelper;
113
114 private String schemaLocation;
115
116 private String targetNamespace;
117
118 private String portTypeName;
119
120 private String schemaPrefix = DEFAULT_SCHEMA_PREFIX;
121
122 private String prefix = DEFAULT_PREFIX;
123
124 private String requestSuffix = DEFAULT_REQUEST_SUFFIX;
125
126 private String responseSuffix = DEFAULT_RESPONSE_SUFFIX;
127
128 private String faultSuffix = DEFAULT_FAULT_SUFFIX;
129
130 private boolean followIncludeImport = false;
131
132
133
134
135
136
137 public void setRequestSuffix(String requestSuffix) {
138 this.requestSuffix = requestSuffix;
139 }
140
141
142
143
144
145
146 public void setResponseSuffix(String responseSuffix) {
147 this.responseSuffix = responseSuffix;
148 }
149
150
151
152
153
154
155 public void setFaultSuffix(String faultSuffix) {
156 this.faultSuffix = faultSuffix;
157 }
158
159
160 public void setPortTypeName(String portTypeName) {
161 this.portTypeName = portTypeName;
162 }
163
164
165 public void setTargetNamespace(String targetNamespace) {
166 this.targetNamespace = targetNamespace;
167 }
168
169
170
171
172
173
174 public void setSchemaPrefix(String schemaPrefix) {
175 this.schemaPrefix = schemaPrefix;
176 }
177
178
179
180
181
182
183 public void setPrefix(String prefix) {
184 this.prefix = prefix;
185 }
186
187
188 public void setSchema(Resource schemaResource) {
189 Assert.notNull(schemaResource, "'schema' must not be null");
190 Assert.isTrue(schemaResource.exists(), "schema \"" + schemaResource + "\" does not exit");
191 this.schemaResource = schemaResource;
192 }
193
194
195
196
197
198 public void setSchemaLocation(String schemaLocation) {
199 Assert.hasLength(schemaLocation, "'schemaLocation' must not be empty");
200 this.schemaLocation = schemaLocation;
201 }
202
203
204
205
206
207 public void setFollowIncludeImport(boolean followIncludeImport) {
208 this.followIncludeImport = followIncludeImport;
209 }
210
211 public final void afterPropertiesSet() throws IOException, ParserConfigurationException, SAXException {
212 Assert.notNull(schemaResource, "'schema' is required");
213 Assert.notNull(portTypeName, "'portTypeName' is required");
214 schemaHelper = new XsdSchemaHelper(schemaResource);
215 if (!StringUtils.hasLength(targetNamespace)) {
216 targetNamespace = schemaHelper.getTargetNamespace();
217 }
218 }
219
220
221 protected void populateDefinition(Definition definition) throws WSDLException {
222 super.populateDefinition(definition);
223 definition.setTargetNamespace(targetNamespace);
224 definition.addNamespace(schemaPrefix, schemaHelper.getTargetNamespace());
225 if (!targetNamespace.equals(schemaHelper.getTargetNamespace())) {
226 definition.addNamespace(prefix, targetNamespace);
227 }
228 }
229
230
231 protected void buildImports(Definition definition) throws WSDLException {
232 }
233
234
235
236
237
238
239
240
241
242 protected void buildTypes(Definition definition) throws WSDLException {
243 Types types = definition.createTypes();
244 Schema schema = (Schema) createExtension(Types.class, XsdSchemaHelper.SCHEMA_NAME);
245 if (!StringUtils.hasLength(schemaLocation)) {
246 schema.setElement(schemaHelper.getSchemaElement());
247 }
248 else {
249 Document document;
250 try {
251 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
252 documentBuilderFactory.setNamespaceAware(true);
253 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
254 document = documentBuilder.newDocument();
255 }
256 catch (ParserConfigurationException ex) {
257 throw new WSDLException(WSDLException.PARSER_ERROR, "Could not create DocumentBuilder", ex);
258 }
259 Element importingSchemaElement = document.createElementNS(XsdSchemaHelper.SCHEMA_NAME.getNamespaceURI(),
260 QNameUtils.toQualifiedName(XsdSchemaHelper.SCHEMA_NAME));
261 schema.setElement(importingSchemaElement);
262 Element importElement = document.createElementNS(XsdSchemaHelper.IMPORT_NAME.getNamespaceURI(),
263 QNameUtils.toQualifiedName(XsdSchemaHelper.IMPORT_NAME));
264 importingSchemaElement.appendChild(importElement);
265 importElement.setAttribute("namespace", schemaHelper.getTargetNamespace());
266 importElement.setAttribute("schemaLocation", schemaLocation);
267 }
268 types.addExtensibilityElement(schema);
269 definition.setTypes(types);
270 }
271
272
273
274
275
276
277
278
279 protected void buildMessages(Definition definition) throws WSDLException {
280 List elementDeclarations = schemaHelper.getElementDeclarations(followIncludeImport);
281 for (Iterator iterator = elementDeclarations.iterator(); iterator.hasNext();) {
282 QName elementName = (QName) iterator.next();
283 if (elementName != null &&
284 (isRequestMessage(elementName) || isResponseMessage(elementName) || isFaultMessage(elementName))) {
285 if (definition.getPrefix(elementName.getNamespaceURI()) == null) {
286 int i = 0;
287 while (true) {
288 String prefix = schemaPrefix + Integer.toString(i);
289 if (!StringUtils.hasLength(definition.getNamespace(prefix))) {
290 definition.addNamespace(prefix, elementName.getNamespaceURI());
291 break;
292 }
293 i++;
294 }
295 }
296 Message message = definition.createMessage();
297 populateMessage(message, elementName);
298 Part part = definition.createPart();
299 populatePart(part, elementName);
300 message.addPart(part);
301 message.setUndefined(false);
302 definition.addMessage(message);
303 }
304 }
305 }
306
307
308
309
310
311
312
313
314
315 protected boolean isRequestMessage(QName name) {
316 return name.getLocalPart().endsWith(requestSuffix);
317 }
318
319
320
321
322
323
324
325
326
327 protected boolean isResponseMessage(QName name) {
328 return name.getLocalPart().endsWith(responseSuffix);
329 }
330
331
332
333
334
335
336
337
338
339 protected boolean isFaultMessage(QName name) {
340 return name.getLocalPart().endsWith(faultSuffix);
341 }
342
343
344
345
346
347
348
349
350
351
352 protected void populateMessage(Message message, QName elementName) throws WSDLException {
353 message.setQName(new QName(targetNamespace, elementName.getLocalPart()));
354 }
355
356
357
358
359
360
361
362
363
364
365
366 protected void populatePart(Part part, QName elementName) throws WSDLException {
367 part.setElementName(elementName);
368 part.setName(elementName.getLocalPart());
369 }
370
371 protected void buildPortTypes(Definition definition) throws WSDLException {
372 PortType portType = definition.createPortType();
373 populatePortType(portType);
374 createOperations(definition, portType);
375 portType.setUndefined(false);
376 definition.addPortType(portType);
377 }
378
379
380
381
382
383
384
385
386
387
388 protected void populatePortType(PortType portType) throws WSDLException {
389 portType.setQName(new QName(targetNamespace, portTypeName));
390 }
391
392 private void createOperations(Definition definition, PortType portType) throws WSDLException {
393 for (Iterator messageIterator = definition.getMessages().values().iterator(); messageIterator.hasNext();) {
394 Message message = (Message) messageIterator.next();
395 for (Iterator partIterator = message.getParts().values().iterator(); partIterator.hasNext();) {
396 Part part = (Part) partIterator.next();
397 if (isRequestMessage(part.getElementName())) {
398 Message requestMessage = message;
399 Message responseMessage = definition.getMessage(getResponseMessageName(requestMessage.getQName()));
400 Message faultMessage = definition.getMessage(getFaultMessageName(requestMessage.getQName()));
401 Operation operation = definition.createOperation();
402 populateOperation(operation, requestMessage, responseMessage);
403 if (requestMessage != null) {
404 Input input = definition.createInput();
405 input.setMessage(requestMessage);
406 input.setName(requestMessage.getQName().getLocalPart());
407 operation.setInput(input);
408 }
409 if (responseMessage != null) {
410 Output output = definition.createOutput();
411 output.setMessage(responseMessage);
412 output.setName(responseMessage.getQName().getLocalPart());
413 operation.setOutput(output);
414 }
415 if (faultMessage != null) {
416 Fault fault = definition.createFault();
417 fault.setMessage(faultMessage);
418 fault.setName(faultMessage.getQName().getLocalPart());
419 operation.addFault(fault);
420 }
421 if (requestMessage != null && responseMessage != null) {
422 operation.setStyle(OperationType.REQUEST_RESPONSE);
423 }
424 else if (requestMessage != null && responseMessage == null) {
425 operation.setStyle(OperationType.ONE_WAY);
426 }
427 else if (requestMessage == null && responseMessage != null) {
428 operation.setStyle(OperationType.NOTIFICATION);
429 }
430 operation.setUndefined(false);
431 portType.addOperation(operation);
432 }
433 }
434 }
435 }
436
437
438
439
440
441
442
443
444
445 protected QName getResponseMessageName(QName requestMessageName) {
446 String localPart = requestMessageName.getLocalPart();
447 if (localPart.endsWith(requestSuffix)) {
448 String prefix = localPart.substring(0, localPart.length() - requestSuffix.length());
449 return new QName(requestMessageName.getNamespaceURI(), prefix + responseSuffix);
450 }
451 else {
452 return null;
453 }
454 }
455
456
457
458
459
460
461
462
463
464 protected QName getFaultMessageName(QName requestMessageName) {
465 String localPart = requestMessageName.getLocalPart();
466 if (localPart.endsWith(requestSuffix)) {
467 String prefix = localPart.substring(0, localPart.length() - requestSuffix.length());
468 return new QName(requestMessageName.getNamespaceURI(), prefix + faultSuffix);
469 }
470 else {
471 return null;
472 }
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486 protected void populateOperation(Operation operation, Message requestMessage, Message responseMessage)
487 throws WSDLException {
488 String localPart = requestMessage.getQName().getLocalPart();
489 String operationName = null;
490 if (localPart.endsWith(requestSuffix)) {
491 operationName = localPart.substring(0, localPart.length() - requestSuffix.length());
492 }
493 else {
494 localPart = responseMessage.getQName().getLocalPart();
495 if (localPart.endsWith(responseSuffix)) {
496 operationName = localPart.substring(0, localPart.length() - responseSuffix.length());
497 }
498 }
499 operation.setName(operationName);
500 }
501
502
503 protected void populateService(Service service) throws WSDLException {
504 service.setQName(new QName(targetNamespace, portTypeName + SERVICE_SUFFIX));
505 }
506
507 }