001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.wsdl11;
019:
020: import java.util.Arrays;
021: import java.util.Collection;
022: import java.util.HashMap;
023: import java.util.HashSet;
024: import java.util.List;
025: import java.util.Map;
026: import javax.wsdl.Binding;
027: import javax.wsdl.BindingFault;
028: import javax.wsdl.BindingInput;
029: import javax.wsdl.BindingOperation;
030: import javax.wsdl.BindingOutput;
031: import javax.wsdl.Definition;
032: import javax.wsdl.Fault;
033: import javax.wsdl.Import;
034: import javax.wsdl.Input;
035: import javax.wsdl.Message;
036: import javax.wsdl.Operation;
037: import javax.wsdl.OperationType;
038: import javax.wsdl.Output;
039: import javax.wsdl.Part;
040: import javax.wsdl.Port;
041: import javax.wsdl.PortType;
042: import javax.wsdl.Service;
043: import javax.wsdl.Types;
044: import javax.wsdl.WSDLException;
045: import javax.wsdl.extensions.ElementExtensible;
046: import javax.wsdl.extensions.ExtensibilityElement;
047: import javax.xml.namespace.QName;
048: import javax.xml.parsers.ParserConfigurationException;
049:
050: import org.w3c.dom.Document;
051: import org.w3c.dom.Element;
052:
053: import com.ibm.wsdl.extensions.schema.SchemaImpl;
054: import org.apache.cxf.Bus;
055: import org.apache.cxf.helpers.CastUtils;
056: import org.apache.cxf.helpers.XMLUtils;
057: import org.apache.cxf.service.factory.ServiceConstructionException;
058: import org.apache.cxf.service.model.AbstractMessageContainer;
059: import org.apache.cxf.service.model.AbstractPropertiesHolder;
060: import org.apache.cxf.service.model.BindingFaultInfo;
061: import org.apache.cxf.service.model.BindingInfo;
062: import org.apache.cxf.service.model.BindingMessageInfo;
063: import org.apache.cxf.service.model.BindingOperationInfo;
064: import org.apache.cxf.service.model.EndpointInfo;
065: import org.apache.cxf.service.model.FaultInfo;
066: import org.apache.cxf.service.model.InterfaceInfo;
067: import org.apache.cxf.service.model.MessagePartInfo;
068: import org.apache.cxf.service.model.OperationInfo;
069: import org.apache.cxf.service.model.SchemaInfo;
070: import org.apache.cxf.service.model.ServiceInfo;
071: import org.apache.cxf.wsdl.WSDLConstants;
072: import org.apache.cxf.wsdl.WSDLManager;
073: import org.apache.ws.commons.schema.XmlSchemaSerializer;
074: import org.apache.ws.commons.schema.XmlSchemaSerializer.XmlSchemaSerializerException;
075:
076: public final class ServiceWSDLBuilder {
077:
078: private final Map<String, String> ns2prefix;
079: private Definition definition;
080: private final List<ServiceInfo> services;
081: private boolean useSchemaImports;
082: private String baseFileName;
083: private int xsdCount;
084: private final Bus bus;
085:
086: public ServiceWSDLBuilder(Bus b, List<ServiceInfo> services) {
087: this .services = services;
088: bus = b;
089: ns2prefix = new HashMap<String, String>();
090: }
091:
092: public ServiceWSDLBuilder(Bus b, ServiceInfo... services) {
093: this (b, Arrays.asList(services));
094: }
095:
096: public void setUseSchemaImports(boolean b) {
097: useSchemaImports = b;
098: }
099:
100: public void setBaseFileName(String s) {
101: baseFileName = s;
102: }
103:
104: public Definition build() throws WSDLException {
105: useSchemaImports = false;
106: return build(null);
107: }
108:
109: public Definition build(Map<String, SchemaInfo> imports)
110: throws WSDLException {
111: try {
112: definition = services.get(0).getProperty(
113: WSDLServiceBuilder.WSDL_DEFINITION,
114: Definition.class);
115: } catch (ClassCastException e) {
116: //ignore
117: }
118: if (definition == null) {
119: ServiceInfo si = services.get(0);
120: definition = newDefinition(si.getName(), si
121: .getTargetNamespace());
122: addExtensibiltyElements(definition, getWSDL11Extensors(si));
123:
124: Collection<PortType> portTypes = new HashSet<PortType>();
125: for (ServiceInfo service : services) {
126: Definition portTypeDef = definition;
127: if (!isSameTNS(service)) {
128: portTypeDef = newDefinition(service.getInterface()
129: .getName(), service.getInterface()
130: .getName().getNamespaceURI());
131: Import wsdlImport = definition.createImport();
132: String tns = service.getInterface().getName()
133: .getNamespaceURI();
134: wsdlImport.setDefinition(portTypeDef);
135: wsdlImport.setNamespaceURI(tns);
136: wsdlImport.setLocationURI(service.getInterface()
137: .getName().getLocalPart()
138: + ".wsdl");
139: definition.addImport(wsdlImport);
140: addNamespace(tns);
141: }
142: portTypes.add(buildPortType(service.getInterface(),
143: portTypeDef));
144:
145: if (service.getSchemas() != null
146: && service.getSchemas().size() > 0) {
147: buildTypes(service.getSchemas(), imports,
148: portTypeDef);
149: }
150: }
151:
152: for (ServiceInfo service : services) {
153: buildBinding(service.getBindings(), portTypes);
154: buildService(service);
155: }
156: }
157: return definition;
158: }
159:
160: private boolean isSameTNS(final ServiceInfo service) {
161: return service.getName().getNamespaceURI().equals(
162: service.getInterface().getName().getNamespaceURI());
163: }
164:
165: private Definition newDefinition(final QName name,
166: String targetNamespace) {
167: Definition d = bus.getExtension(WSDLManager.class)
168: .getWSDLFactory().newDefinition();
169: d.setExtensionRegistry(bus.getExtension(WSDLManager.class)
170: .getExtenstionRegistry());
171: d.setQName(name);
172: d.setTargetNamespace(targetNamespace);
173: addNamespace(WSDLConstants.NP_SCHEMA_XSD,
174: WSDLConstants.NU_SCHEMA_XSD, d);
175: return d;
176: }
177:
178: public List<ExtensibilityElement> getWSDL11Extensors(
179: AbstractPropertiesHolder holder) {
180: return holder.getExtensors(ExtensibilityElement.class);
181: }
182:
183: protected void addExtensibiltyElements(
184: ElementExtensible elementExtensible,
185: List<ExtensibilityElement> extensibilityElements) {
186: if (extensibilityElements != null) {
187: for (ExtensibilityElement element : extensibilityElements) {
188: QName qn = element.getElementType();
189: addNamespace(qn.getNamespaceURI());
190: elementExtensible.addExtensibilityElement(element);
191: }
192: }
193: }
194:
195: protected void buildTypes(final Collection<SchemaInfo> schemas,
196: final Map<String, SchemaInfo> imports, final Definition def) {
197: Types types = def.createTypes();
198:
199: Document doc = null;
200: try {
201: doc = XMLUtils.newDocument();
202: } catch (ParserConfigurationException e) {
203: //should not happen
204: }
205: Element nd = XMLUtils.createElementNS(doc, new QName(
206: "http://www.w3.org/2001/XMLSchema", "schema"));
207: nd.setAttribute("xmlns", "http://www.w3.org/2001/XMLSchema");
208: doc.appendChild(nd);
209:
210: for (SchemaInfo schemaInfo : schemas) {
211:
212: if (schemaInfo.getSchema() != null) {
213: Document[] docs;
214: try {
215: docs = XmlSchemaSerializer.serializeSchema(
216: schemaInfo.getSchema(), false);
217: } catch (XmlSchemaSerializerException e1) {
218: throw new ServiceConstructionException(e1);
219: }
220: Element e = docs[0].getDocumentElement();
221: // XXX A problem can occur with the ibm jdk when the XmlSchema
222: // object is serialized. The xmlns declaration gets incorrectly
223: // set to the same value as the targetNamespace attribute.
224: // The aegis databinding tests demonstrate this particularly.
225: if (e.getPrefix() == null
226: && !WSDLConstants.NU_SCHEMA_XSD.equals(e
227: .getAttributeNS(WSDLConstants.NU_XMLNS,
228: WSDLConstants.NP_XMLNS))) {
229: e.setAttributeNS(WSDLConstants.NU_XMLNS,
230: WSDLConstants.NP_XMLNS,
231: WSDLConstants.NU_SCHEMA_XSD);
232: }
233: schemaInfo.setElement(e);
234: }
235:
236: if (!useSchemaImports) {
237: SchemaImpl schemaImpl = new SchemaImpl();
238: schemaImpl.setRequired(true);
239: schemaImpl.setElementType(WSDLConstants.SCHEMA_QNAME);
240: schemaImpl.setElement(schemaInfo.getElement());
241: types.addExtensibilityElement(schemaImpl);
242: } else {
243: //imports
244: String name = baseFileName + "_schema" + (++xsdCount)
245: + ".xsd";
246: Element imp = XMLUtils.createElementNS(doc, new QName(
247: "http://www.w3.org/2001/XMLSchema", "import"));
248: imp.setAttribute("schemaLocation", name);
249: imp.setAttribute("namespace", schemaInfo
250: .getNamespaceURI());
251: nd.appendChild(imp);
252:
253: imports.put(name, schemaInfo);
254: }
255: }
256: if (useSchemaImports) {
257: SchemaImpl schemaImpl = new SchemaImpl();
258: schemaImpl.setRequired(true);
259: schemaImpl.setElementType(WSDLConstants.SCHEMA_QNAME);
260: schemaImpl.setElement(nd);
261: types.addExtensibilityElement(schemaImpl);
262: }
263: def.setTypes(types);
264: }
265:
266: protected void buildBinding(Collection<BindingInfo> bindingInfos,
267: Collection<PortType> portTypes) {
268: Binding binding = null;
269: for (BindingInfo bindingInfo : bindingInfos) {
270: binding = definition.createBinding();
271: binding.setUndefined(false);
272: for (PortType portType : portTypes) {
273: if (portType.getQName().equals(
274: bindingInfo.getInterface().getName())) {
275: binding.setPortType(portType);
276: break;
277: }
278: }
279: binding.setQName(bindingInfo.getName());
280: buildBindingOperation(definition, binding, bindingInfo
281: .getOperations());
282: addExtensibiltyElements(binding,
283: getWSDL11Extensors(bindingInfo));
284: definition.addBinding(binding);
285: }
286: }
287:
288: protected void buildBindingOperation(Definition def,
289: Binding binding,
290: Collection<BindingOperationInfo> bindingOperationInfos) {
291: BindingOperation bindingOperation = null;
292: for (BindingOperationInfo bindingOperationInfo : bindingOperationInfos) {
293: bindingOperation = def.createBindingOperation();
294: bindingOperation.setName(bindingOperationInfo.getName()
295: .getLocalPart());
296: for (Operation operation : CastUtils.cast(binding
297: .getPortType().getOperations(), Operation.class)) {
298: if (operation.getName().equals(
299: bindingOperation.getName())) {
300: bindingOperation.setOperation(operation);
301: break;
302: }
303: }
304: buildBindingInput(def, bindingOperation,
305: bindingOperationInfo.getInput());
306: buildBindingOutput(def, bindingOperation,
307: bindingOperationInfo.getOutput());
308: buildBindingFault(def, bindingOperation,
309: bindingOperationInfo.getFaults());
310: addExtensibiltyElements(bindingOperation,
311: getWSDL11Extensors(bindingOperationInfo));
312: binding.addBindingOperation(bindingOperation);
313: }
314: }
315:
316: protected void buildBindingFault(Definition def,
317: BindingOperation bindingOperation,
318: Collection<BindingFaultInfo> bindingFaultInfos) {
319: BindingFault bindingFault = null;
320: for (BindingFaultInfo bindingFaultInfo : bindingFaultInfos) {
321: bindingFault = def.createBindingFault();
322: bindingFault.setName(bindingFaultInfo.getFaultInfo()
323: .getFaultName().getLocalPart());
324: bindingOperation.addBindingFault(bindingFault);
325: addExtensibiltyElements(bindingFault,
326: getWSDL11Extensors(bindingFaultInfo));
327: }
328:
329: }
330:
331: protected void buildBindingInput(Definition def,
332: BindingOperation bindingOperation,
333: BindingMessageInfo bindingMessageInfo) {
334: BindingInput bindingInput = null;
335: if (bindingMessageInfo != null) {
336: bindingInput = def.createBindingInput();
337: bindingInput.setName(bindingMessageInfo.getMessageInfo()
338: .getName().getLocalPart());
339: bindingOperation.setBindingInput(bindingInput);
340: addExtensibiltyElements(bindingInput,
341: getWSDL11Extensors(bindingMessageInfo));
342: }
343: }
344:
345: protected void buildBindingOutput(Definition def,
346: BindingOperation bindingOperation,
347: BindingMessageInfo bindingMessageInfo) {
348: BindingOutput bindingOutput = null;
349: if (bindingMessageInfo != null) {
350: bindingOutput = def.createBindingOutput();
351: bindingOutput.setName(bindingMessageInfo.getMessageInfo()
352: .getName().getLocalPart());
353: bindingOperation.setBindingOutput(bindingOutput);
354: addExtensibiltyElements(bindingOutput,
355: getWSDL11Extensors(bindingMessageInfo));
356: }
357: }
358:
359: protected void buildService(ServiceInfo serviceInfo) {
360: Service serv = definition.createService();
361: serv.setQName(serviceInfo.getName());
362: addNamespace(serviceInfo.getName().getNamespaceURI());
363: definition.addService(serv);
364:
365: for (EndpointInfo ei : serviceInfo.getEndpoints()) {
366: addNamespace(ei.getTransportId());
367: Port port = definition.createPort();
368: port.setName(ei.getName().getLocalPart());
369: port.setBinding(definition.getBinding(ei.getBinding()
370: .getName()));
371: addExtensibiltyElements(port, getWSDL11Extensors(ei));
372: serv.addPort(port);
373: }
374: }
375:
376: protected PortType buildPortType(InterfaceInfo intf,
377: final Definition def) {
378: PortType portType = null;
379: try {
380: portType = intf.getProperty(
381: WSDLServiceBuilder.WSDL_PORTTYPE, PortType.class);
382: } catch (ClassCastException e) {
383: // do nothing
384: }
385:
386: if (portType == null) {
387: portType = def.createPortType();
388: portType.setQName(intf.getName());
389: addNamespace(intf.getName().getNamespaceURI(), def);
390: portType.setUndefined(false);
391: buildPortTypeOperation(portType, intf.getOperations(), def);
392: }
393:
394: def.addPortType(portType);
395: return portType;
396: }
397:
398: protected void addNamespace(String namespaceURI, Definition def) {
399: addNamespace(getPrefix(namespaceURI), namespaceURI, def);
400: }
401:
402: protected void addNamespace(String namespaceURI) {
403: addNamespace(getPrefix(namespaceURI), namespaceURI);
404: }
405:
406: protected void addNamespace(String prefix, String namespaceURI) {
407: addNamespace(prefix, namespaceURI, definition);
408: }
409:
410: protected void addNamespace(String prefix, String namespaceURI,
411: Definition def) {
412: ns2prefix.put(namespaceURI, prefix);
413: def.addNamespace(prefix, namespaceURI);
414: }
415:
416: protected void buildPortTypeOperation(PortType portType,
417: Collection<OperationInfo> operationInfos,
418: final Definition def) {
419: for (OperationInfo operationInfo : operationInfos) {
420: Operation operation = null;
421: try {
422: operation = operationInfo.getProperty(
423: WSDLServiceBuilder.WSDL_OPERATION,
424: Operation.class);
425: } catch (ClassCastException e) {
426: // do nothing
427: }
428:
429: if (operation == null) {
430: operation = def.createOperation();
431: operation.setUndefined(false);
432: operation.setName(operationInfo.getName()
433: .getLocalPart());
434: addNamespace(operationInfo.getName().getNamespaceURI(),
435: def);
436: if (operationInfo.isOneWay()) {
437: operation.setStyle(OperationType.ONE_WAY);
438: }
439: Input input = def.createInput();
440: input.setName(operationInfo.getInputName());
441: Message message = def.createMessage();
442: buildMessage(message, operationInfo.getInput(), def);
443: input.setMessage(message);
444: operation.setInput(input);
445:
446: if (operationInfo.getOutput() != null) {
447: Output output = def.createOutput();
448: output.setName(operationInfo.getOutputName());
449: message = def.createMessage();
450: buildMessage(message, operationInfo.getOutput(),
451: def);
452: output.setMessage(message);
453: operation.setOutput(output);
454: }
455: //loop to add fault
456: Collection<FaultInfo> faults = operationInfo
457: .getFaults();
458: Fault fault = null;
459: for (FaultInfo faultInfo : faults) {
460: fault = def.createFault();
461: fault.setName(faultInfo.getFaultName()
462: .getLocalPart());
463: message = def.createMessage();
464: buildMessage(message, faultInfo, def);
465: fault.setMessage(message);
466: operation.addFault(fault);
467: }
468: }
469: portType.addOperation(operation);
470: }
471: }
472:
473: private String getPrefix(String ns) {
474: for (String namespace : WSDLConstants.NS_PREFIX_PAIR.keySet()) {
475: if (namespace.equals(ns)) {
476: return WSDLConstants.NS_PREFIX_PAIR.get(namespace);
477: }
478: }
479: String prefix = ns2prefix.get(ns);
480: if (prefix == null) {
481: prefix = getNewPrefix();
482: ns2prefix.put(ns, prefix);
483: }
484: return prefix;
485: }
486:
487: private String getNewPrefix() {
488: String prefix = "ns1";
489: int i = 0;
490: while (ns2prefix.containsValue(prefix)) {
491: i++;
492: prefix = "ns" + i;
493: }
494: return prefix;
495: }
496:
497: protected void buildMessage(Message message,
498: AbstractMessageContainer messageContainer,
499: final Definition def) {
500: message.setQName(messageContainer.getName());
501: message.setUndefined(false);
502: def.addMessage(message);
503:
504: List<MessagePartInfo> messageParts = messageContainer
505: .getMessageParts();
506: Part messagePart = null;
507: for (MessagePartInfo messagePartInfo : messageParts) {
508: messagePart = def.createPart();
509: messagePart.setName(messagePartInfo.getName()
510: .getLocalPart());
511: if (messagePartInfo.isElement()) {
512: messagePart.setElementName(messagePartInfo
513: .getElementQName());
514: addNamespace(messagePartInfo.getElementQName()
515: .getNamespaceURI(), def);
516: } else if (messagePartInfo.getTypeQName() != null) {
517: messagePart.setTypeName(messagePartInfo.getTypeQName());
518: addNamespace(messagePartInfo.getTypeQName()
519: .getNamespaceURI(), def);
520: }
521: message.addPart(messagePart);
522: }
523: }
524:
525: }
|