View Javadoc

1   /*
2    * Copyright (c) 2006,2007 Julien Ponge. All Rights Reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.izforge.soapdtc.servlet;
24  
25  import com.izforge.soapdtc.SoapMessageUtils;
26  import org.dom4j.Document;
27  import org.dom4j.DocumentFactory;
28  import org.dom4j.Element;
29  import org.dom4j.Namespace;
30  import org.dom4j.io.XPP3Reader;
31  
32  import java.io.IOException;
33  import java.io.Writer;
34  import java.util.HashMap;
35  import java.util.List;
36  import java.util.Map;
37  
38  /**
39   * A WSDL provider that takes advantage of WSDL-DTC descriptions to generate WSDL documents.
40   * A WSDL-DTC document captures the essence of a Document/Literal WSDL descrption and makes it
41   * easier to write WSDL documents. The generated WSDL document will be a WSDL 1.1 SOAP 1.2 binding.
42   *
43   * <strong>Warning: WSDL-DTC is still experimental!</strong>  
44   *
45   * @author Julien Ponge (julien.ponge@gmail.com)
46   */
47  public class WsdlDtcProvider implements IWsdlProvider
48  {
49      private String resource;
50  
51      private String endpointURL;
52  
53      private String wsdl;
54  
55      private Document wsdlDOM;
56      
57      private static final String WSDL_NS_URI = "http://schemas.xmlsoap.org/wsdl/";
58      private static final String WSOAP12_NS_URI = "http://schemas.xmlsoap.org/wsdl/soap12/";
59      private static final String XSD_NS_URI = "http://www.w3.org/2001/XMLSchema";
60      private static final String WSDL_DTC_NS_URI = "http://www.izforge.com/soap-dtc/wsdl-dtc";
61  
62      /**
63       * Constructor.
64       *
65       * @param resource the path to a resource containing the WSDL-DTC document.
66       * @param endpointURL the service endpoint URL.
67       */
68      public WsdlDtcProvider(String resource, String endpointURL)
69      {
70          this.resource = resource;
71          this.endpointURL = endpointURL;
72      }
73  
74  
75      public void writeWsdl(Writer writer) throws IOException
76      {
77          writer.write(getWsdl());
78      }
79  
80      /**
81       * Returns the string representation of the WSDL document.
82       * @return the WSDL document.
83       */
84      protected String getWsdl()
85      {
86          if (wsdl == null)
87          {
88              generateWsdl();
89          }
90          return wsdl;
91      }
92  
93  
94      /**
95       * Returns the DOM4J representation of the WSDL document.
96       * @return the WSDL document.
97       */
98      protected Document getWsdlDOM()
99      {
100         return wsdlDOM;
101     }
102 
103     /**
104      * Generates the WSDL document from the WSDL-DTC specification.
105      */
106     protected void generateWsdl()
107     {
108         DocumentFactory factory = DocumentFactory.getInstance();
109 
110         SoapMessageUtils.configureDocumentFactoryXPathNamespaceURIs(factory);
111         SoapMessageUtils.registerDocumentFactoryXPathNamespaceURIs(factory, "xsd", XSD_NS_URI);
112         SoapMessageUtils.registerDocumentFactoryXPathNamespaceURIs(factory, "wsdl", WSDL_NS_URI);
113         SoapMessageUtils.registerDocumentFactoryXPathNamespaceURIs(factory, "wsoap12", WSOAP12_NS_URI);
114         SoapMessageUtils.registerDocumentFactoryXPathNamespaceURIs(factory, "wsdl-dtc", WSDL_DTC_NS_URI);
115 
116         XPP3Reader reader = new XPP3Reader();
117         Document doc;
118         try
119         {
120             doc = reader.read(getClass().getResourceAsStream(resource));
121         }
122         catch (Exception e)
123         {
124             e.printStackTrace();
125             wsdl = "Could not generate a WSDL document...";
126             return;
127         }
128         String endpointName = doc.valueOf("wsdl-dtc:specification/wsdl-dtc:endpoint/wsdl-dtc:name/text()");
129         String endpointNS = doc.valueOf("wsdl-dtc:specification/wsdl-dtc:endpoint/wsdl-dtc:namespace/text()");
130 
131         /*
132          * Root
133          */
134         Document wsdlDoc = factory.createDocument();
135         Element wsdlRoot = wsdlDoc.addElement("wsdl:definitions", WSDL_NS_URI);
136         wsdlRoot.addNamespace("tns", endpointNS);
137         wsdlRoot.addNamespace("wsoap12", WSOAP12_NS_URI);
138         wsdlRoot.addNamespace("wsdl", WSDL_NS_URI);
139         wsdlRoot.addNamespace("xsd", XSD_NS_URI);
140         wsdlRoot.addAttribute("targetNamespace", doc.valueOf("//wsdl-dtc:endpoint/wsdl-dtc:namespace/text()"));
141 
142         /*
143          * Copy the NS
144          */
145         List<Namespace> namespaces = doc.getRootElement().additionalNamespaces();
146         for (Namespace ns : namespaces)
147         {
148             wsdlRoot.addNamespace(ns.getPrefix(), ns.getURI());
149         }
150 
151         /*
152          * Schema
153          */
154         Element types = wsdlRoot.addElement("wsdl:types", WSDL_NS_URI);
155         types.add((Element)doc.selectSingleNode("//xsd:schema").clone());
156 
157         /*
158          * Messages
159          */
160         List<Element> operationNodes = doc.selectNodes("//wsdl-dtc:operation");
161         Map<String, Element> inputWsdlMessages = new HashMap<String, Element>();
162         Map<String, Element> outputWsdlMessages = new HashMap<String, Element>();
163         for (Element operationElement : operationNodes)
164         {
165             Element inBody = (Element) operationElement.selectSingleNode("wsdl-dtc:input/wsdl-dtc:body");
166             if (inBody != null)
167             {
168                 Element message = factory.createElement("wsdl:message", WSDL_NS_URI);
169                 message.addAttribute("name", operationElement.attributeValue("name") + "In");
170                 List<Element> parts = inBody.selectNodes("wsdl-dtc:part");
171                 for (Element part : parts)
172                 {
173                     message.addElement("wsdl:part", WSDL_NS_URI).addAttribute("name", part.attributeValue("name")).addAttribute("element", part.attributeValue("element"));
174                 }
175                 wsdlRoot.add(message);
176                 inputWsdlMessages.put(operationElement.attributeValue("name"), message);
177             }
178 
179             Element outBody = (Element) operationElement.selectSingleNode("wsdl-dtc:output/wsdl-dtc:body");
180             if (outBody != null)
181             {
182                 Element message = factory.createElement("wsdl:message", WSDL_NS_URI);
183                 message.addAttribute("name", operationElement.attributeValue("name") + "Out");
184                 List<Element> parts = outBody.selectNodes("wsdl-dtc:part");
185                 for (Element part : parts)
186                 {
187                     message.addElement("wsdl:part", WSDL_NS_URI).addAttribute("name", part.attributeValue("name")).addAttribute("element", part.attributeValue("element"));
188                 }
189                 wsdlRoot.add(message);
190                 outputWsdlMessages.put(operationElement.attributeValue("name"), message);
191             }
192         }
193 
194         /*
195          * Port Type
196          */
197         Element portType = wsdlRoot.addElement("wsdl:portType", WSDL_NS_URI);
198         portType.addAttribute("name", endpointName + "PortType");
199         for (Element operationElement : operationNodes)
200         {
201             Element op = portType.addElement("wsdl:operation", WSDL_NS_URI).addAttribute("name", operationElement.attributeValue("name"));
202             Element in = inputWsdlMessages.get(operationElement.attributeValue("name"));
203             Element out = outputWsdlMessages.get(operationElement.attributeValue("name"));
204 
205             if (in != null)
206             {
207                 op.addElement("wsdl:input").addAttribute("message", "tns:" + in.attributeValue("name"));
208             }
209             if (out != null)
210             {
211                 op.addElement("wsdl:output").addAttribute("message", "tns:" + out.attributeValue("name"));
212             }
213         }
214 
215         /*
216          * Binding
217          */
218         Element binding = wsdlRoot.addElement("wsdl:binding", WSDL_NS_URI);
219         binding.addAttribute("name", endpointName + "Soap12Binding");
220         binding.addAttribute("type", "tns:" + portType.attributeValue("name"));
221         Element bbind = binding.addElement("wsoap12:binding", WSOAP12_NS_URI);
222         bbind.addAttribute("transport", "http://schemas.xmlsoap.org/soap/http");
223         bbind.addAttribute("style", "document");
224         for (Element operationElement : operationNodes)
225         {
226             Element op = binding.addElement("wsdl:operation", WSDL_NS_URI).addAttribute("name", operationElement.attributeValue("name"));
227             Element in = inputWsdlMessages.get(operationElement.attributeValue("name"));
228             Element out = outputWsdlMessages.get(operationElement.attributeValue("name"));
229 
230             Element bop = op.addElement("wsoap12:operation", WSOAP12_NS_URI);
231             bop.addAttribute("soapAction", operationElement.attributeValue("soapAction"));
232             bop.addAttribute("soapActionRequired", "true");
233             bop.addAttribute("style", "document");
234             if (in != null)
235             {
236                 Element input = op.addElement("wsdl:input");
237 
238                 List<Element> headerParts = operationElement.selectNodes("wsdl-dtc:input/wsdl-dtc:header/wsdl-dtc:part");
239                 for (Element headerPart : headerParts)
240                 {
241                     Element h = input.addElement("wsoap12:header", WSOAP12_NS_URI);
242                     h.addAttribute("message", headerPart.attributeValue("type"));
243                     h.addAttribute("part", headerPart.attributeValue("name"));
244                     h.addAttribute("use", "literal");
245                 }
246 
247                 input.addElement("wsoap12:body", WSOAP12_NS_URI).addAttribute("use", "literal");
248             }
249             if (out != null)
250             {
251                 Element output = op.addElement("wsdl:output");
252 
253                 List<Element> headerParts = operationElement.selectNodes("wsdl-dtc:output/wsdl-dtc:header/wsdl-dtc:part");
254                 for (Element headerPart : headerParts)
255                 {
256                     Element h = output.addElement("wsoap12:header", WSOAP12_NS_URI);
257                     h.addAttribute("message", headerPart.attributeValue("type"));
258                     h.addAttribute("part", headerPart.attributeValue("name"));
259                     h.addAttribute("use", "literal");
260                 }
261 
262                 output.addElement("wsoap12:body", WSOAP12_NS_URI).addAttribute("use", "literal");
263             }
264         }
265 
266         /*
267          * Service
268          */
269         Element service = wsdlRoot.addElement("wsdl:service", WSDL_NS_URI).addAttribute("name", endpointName);
270         Element port = service.addElement("wsdl:port", WSDL_NS_URI);
271         port.addAttribute("name", endpointName + "Soap12");
272         port.addAttribute("binding", "tns:" + endpointName + "Soap12Binding");
273         port.addElement("wsoap12:address", WSOAP12_NS_URI).addAttribute("location", endpointURL);
274 
275         /*
276          * Done!
277          */
278         wsdlDOM = wsdlDoc;
279         wsdl = wsdlDoc.asXML();
280     }
281 }