KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas > ws > axis > QSUpdateServiceWSDLHandler


1 /**
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999-2004 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: QSUpdateServiceWSDLHandler.java,v 1.8 2005/01/11 18:08:31 sauthieg Exp $
23  * --------------------------------------------------------------------------
24  */

25 package org.objectweb.jonas.ws.axis;
26
27 import java.io.File JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.PrintWriter JavaDoc;
31 import java.net.HttpURLConnection JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35
36 import javax.naming.InitialContext JavaDoc;
37 import javax.naming.NamingException JavaDoc;
38 import javax.servlet.http.HttpServletRequest JavaDoc;
39 import javax.servlet.http.HttpServletResponse JavaDoc;
40 import javax.wsdl.Definition;
41 import javax.wsdl.Port;
42 import javax.wsdl.Service;
43 import javax.wsdl.WSDLException;
44 import javax.wsdl.extensions.ExtensibilityElement;
45 import javax.wsdl.extensions.soap.SOAPAddress;
46 import javax.wsdl.factory.WSDLFactory;
47 import javax.wsdl.xml.WSDLReader;
48 import javax.wsdl.xml.WSDLWriter;
49 import javax.xml.namespace.QName JavaDoc;
50 import javax.xml.parsers.DocumentBuilder JavaDoc;
51 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
52 import javax.xml.parsers.ParserConfigurationException JavaDoc;
53
54 import org.w3c.dom.Attr JavaDoc;
55 import org.w3c.dom.Document JavaDoc;
56 import org.w3c.dom.Element JavaDoc;
57 import org.w3c.dom.NodeList JavaDoc;
58 import org.xml.sax.SAXException JavaDoc;
59
60 import org.apache.axis.AxisFault;
61 import org.apache.axis.Constants;
62 import org.apache.axis.MessageContext;
63 import org.apache.axis.i18n.Messages;
64 import org.apache.axis.server.AxisServer;
65 import org.apache.axis.transport.http.AbstractQueryStringHandler;
66 import org.apache.axis.transport.http.HTTPConstants;
67 import org.apache.axis.utils.XMLUtils;
68
69 import org.objectweb.jonas_ws.deployment.api.PortComponentDesc;
70 import org.objectweb.jonas_ws.deployment.api.ServiceDesc;
71
72 import org.objectweb.jonas.ws.WSServiceException;
73
74 /**
75  * Update the wsdlFile specified in wsdd with the good URLs for endpoints.
76  * responds to the ?JWSDL Supports wsdl:import and xsd:include
77  * @author Guillaume Sauthier
78  */

79 public class QSUpdateServiceWSDLHandler extends AbstractQueryStringHandler {
80
81     /**
82      * SOAP NS URI
83      */

84     private static final String JavaDoc NS_URI_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/";
85
86     /**
87      * soap:address Type QName
88      */

89     private static final QName JavaDoc QNAME_SOAP_ADDRESS = new QName JavaDoc(NS_URI_SOAP, "address");
90
91     /**
92      * WSDL NS URI
93      */

94     private static final String JavaDoc NS_URI_WSDL = "http://schemas.xmlsoap.org/wsdl/";
95
96     /**
97      * XSD NS URI
98      */

99     private static final String JavaDoc NS_URI_XSD = "http://www.w3.org/2001/XMLSchema";
100
101     /**
102      * filename parameter name
103      */

104     private static final String JavaDoc PARAM_FILENAME = "filename";
105
106     /**
107      * context parameter name
108      */

109     private static final String JavaDoc PARAM_CONTEXT = "context";
110
111     /**
112      * JWSDL parameter QSHandler name
113      */

114     private static final String JavaDoc PARAM_JWSDL = "JWSDL";
115
116     /**
117      * wsdl:definition QName
118      */

119     private static final QName JavaDoc WSDL_DEFINITIONS_QNAME = new QName JavaDoc(NS_URI_WSDL, "definitions");
120
121     /**
122      * Service meta data
123      */

124     private ServiceDesc sd = null;
125
126     /**
127      * Performs the action associated with this particular query string handler.
128      * @param msgContext a MessageContext object containing message context
129      * information for this query string handler.
130      * @throws AxisFault if an error occurs.
131      */

132     public void invoke(MessageContext msgContext) throws AxisFault {
133         // Obtain objects relevant to the task at hand from the provided
134
// MessageContext's bag.
135
configureFromContext(msgContext);
136
137         AxisServer engine = (AxisServer) msgContext.getProperty(HTTPConstants.PLUGIN_ENGINE);
138         PrintWriter JavaDoc writer = (PrintWriter JavaDoc) msgContext.getProperty(HTTPConstants.PLUGIN_WRITER);
139         HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) msgContext
140                 .getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE);
141         HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
142
143         InitialContext JavaDoc ctx;
144         try {
145             ctx = new InitialContext JavaDoc();
146             sd = (ServiceDesc) ctx.lookup("java:comp/jonas/" + engine.getName() + "/dd");
147         } catch (NamingException JavaDoc e) {
148             throw new AxisFault("Servlet name not found : " + engine.getName(), e);
149         }
150
151         String JavaDoc wsdlFilename = request.getParameter(PARAM_FILENAME);
152         String JavaDoc context = request.getParameter(PARAM_CONTEXT);
153         try {
154             Document JavaDoc doc = null;
155             if (wsdlFilename == null) {
156                 // as a Document
157
doc = getDefinitionAsDocument(sd.getWSDL().getDefinition());
158                 wsdlFilename = sd.getWSDL().getName();
159                 String JavaDoc[] pathElements = wsdlFilename.split("/");
160                 if (pathElements.length <= 2) {
161                     throw new WSServiceException("invalid filename");
162                 }
163
164                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
165                 for (int i = 2; i < pathElements.length; i++) {
166                     buf.append(pathElements[i]);
167                     if (i != (pathElements.length - 1)) {
168                         // last part is a filename
169
buf.append("/");
170                     }
171                 }
172                 // remove WEB-INF/wsdl/
173
// remove META-INF/wsdl/
174
wsdlFilename = buf.toString();
175                 context = ".";
176                 msgContext.setProperty("WSDL", doc);
177             } else {
178                 // try to get the specified WSDL from cache ...
179
doc = (Document JavaDoc) msgContext.getProperty("WSDL_" + wsdlFilename);
180
181                 if (doc == null) {
182                     // create the WSDL/Imported file
183
doc = getDocument(wsdlFilename, context);
184                 }
185
186                 msgContext.setProperty("WSDL_" + wsdlFilename, doc);
187             }
188
189             if (doc != null) {
190                 // update WSDL
191
modifyImports(doc, request, new File JavaDoc(context, wsdlFilename).getParent());
192                 Document JavaDoc up2date = updateWSDLPortLocations(doc);
193                 response.setContentType("text/xml; charset=" + XMLUtils.getEncoding().toLowerCase());
194                 reportWSDL(up2date, writer);
195             } else {
196                 // report Error
197
if (log.isDebugEnabled()) {
198                     log.debug("processWsdlRequest: failed to create WSDL");
199                 }
200                 reportNoWSDL(response, writer, "noWSDL02", null);
201             }
202         } catch (AxisFault axisFault) {
203             //the no-service fault is mapped to a no-wsdl error
204
if (axisFault.getFaultCode().equals(Constants.QNAME_NO_SERVICE_FAULT_CODE)) {
205                 //which we log
206
processAxisFault(axisFault);
207
208                 //then report under a 404 error
209
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
210                 reportNoWSDL(response, writer, "noWSDL01", axisFault);
211             } else {
212                 //all other faults get thrown
213
throw axisFault;
214             }
215         }
216     }
217
218     /**
219      * @param definition Definition to convert
220      * @return returns the given Definition instance as a Document instance
221      * @throws AxisFault when convertion is not possible
222      */

223     private Document JavaDoc getDefinitionAsDocument(Definition definition) throws AxisFault {
224
225         try {
226             WSDLWriter writer = getWSDLWriter();
227             return writer.getDocument(definition);
228         } catch (WSDLException e) {
229             throw new AxisFault(e.getMessage(), e);
230         }
231
232     }
233
234     /**
235      * Update the wsdl:import and xsd:include elements of the given Document.
236      * @param doc Definitions or Schema document instance.
237      * @param request HTTP request
238      * @param context loading Context
239      */

240     private void modifyImports(Document JavaDoc doc, HttpServletRequest JavaDoc request, String JavaDoc context) {
241         // Document may be a wsdl:definition or xsd:schema
242
// So we must handle import (definitions) and include (schema)
243

244         // wsdl:definition / xsd:schema
245
Element de = doc.getDocumentElement();
246
247         NodeList JavaDoc imports = de.getElementsByTagNameNS(NS_URI_WSDL, "import");
248
249         // modify wsdl:import location
250
for (int i = 0; i < imports.getLength(); i++) {
251             Element imp = (Element) imports.item(i);
252             Attr JavaDoc location = imp.getAttributeNode("location");
253             if (!location.getValue().startsWith("http://")) {
254                 // relative import
255
String JavaDoc req = computeUpdatedURL(request, context, location);
256
257                 log.debug("Replacing wsdl:location '" + location.getValue() + "' with '" + req.toString() + "'");
258                 location.setValue(req.toString());
259             }
260         }
261
262         // modify xsd:include schemaLocation
263
updateSchema(de, "include", request, context);
264         // modify xsd:import schemaLocation
265
updateSchema(de, "import", request, context);
266
267         // wsdl:definitions/wsdl:types/xsd:schema/(xsd:import|xsd:include)
268
NodeList JavaDoc types = de.getElementsByTagNameNS(NS_URI_WSDL, "types");
269         // is there a types here ?
270
if (types.getLength() != 0) {
271
272             // get the only wsdl:types element
273
Element typesElement = (Element) types.item(0);
274
275             // is there some xsd:schema out there ?
276
NodeList JavaDoc schemasList = typesElement.getElementsByTagNameNS(NS_URI_XSD, "schema");
277             for (int i = 0; i < schemasList.getLength(); i++) {
278                 Element schema = (Element) schemasList.item(i);
279                 updateSchema(schema, "include", request, context);
280                 updateSchema(schema, "import", request, context);
281             }
282         }
283     }
284
285     /**
286      * @param request the Http Request
287      * @param context loading context
288      * @param location attribute to update
289      * @return return the new location value
290      */

291     private String JavaDoc computeUpdatedURL(HttpServletRequest JavaDoc request, String JavaDoc context, Attr JavaDoc location) {
292         StringBuffer JavaDoc req = request.getRequestURL();
293         req.append("?" + PARAM_JWSDL);
294         req.append("&" + PARAM_FILENAME + "=" + location.getValue());
295         req.append("&" + PARAM_CONTEXT + "=" + context);
296         return req.toString();
297     }
298
299     /**
300      * @param schema The Element representing a Schema to be updated
301      * @param elementName the element name with "schemaLocation" attribute (can be "import" or "include")
302      * @param request the HTTP Request
303      * @param context loading context
304      */

305     private void updateSchema(Element schema, String JavaDoc elementName, HttpServletRequest JavaDoc request, String JavaDoc context) {
306
307         NodeList JavaDoc elements = schema.getElementsByTagNameNS(NS_URI_XSD, elementName);
308
309         // modify xsd:include|xsd:import schemaLocation
310
for (int i = 0; i < elements.getLength(); i++) {
311             Element e = (Element) elements.item(i);
312             Attr JavaDoc location = e.getAttributeNode("schemaLocation");
313             if ((location != null) && (!location.getValue().startsWith("http://"))) {
314                 // relative import
315
String JavaDoc req = computeUpdatedURL(request, context, location);
316
317                 log.debug("Replacing xsd:schemaLocation '" + location.getValue() + "' with '" + req.toString() + "'");
318                 location.setValue(req.toString());
319             }
320         }
321     }
322
323     /**
324      * @param wsdlFilename resource to load.
325      * @param context loading context
326      * @return Returns a Document created from the filename loaded in the
327      * context ClassLoader.
328      * @throws AxisFault if resource if not found or if resource is not XML.
329      */

330     private Document JavaDoc getDocument(String JavaDoc wsdlFilename, String JavaDoc context) throws AxisFault {
331
332         // Check that the filename is only relative to META-INF/wsdl or
333
// WEB-INF/wsdl no deeper !
334
// TODO Security Check !
335

336         ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
337         URL JavaDoc res = cl.getResource(context + "/" + wsdlFilename);
338
339         Document JavaDoc doc = null;
340         if (res != null) {
341             try {
342                 doc = createDocument(res.openStream());
343             } catch (IOException JavaDoc ioe) {
344                 throw new AxisFault("Cannot open requested URL : " + res);
345             }
346         } else {
347             throw new AxisFault("Cannot find requested document : " + wsdlFilename);
348         }
349
350         return doc;
351     }
352
353     /**
354      * @param stream supposed XML InputStream
355      * @return Returns the Document parsed from the given InputStream
356      * @throws AxisFault if parsing goes wrong.
357      */

358     private Document JavaDoc createDocument(InputStream JavaDoc stream) throws AxisFault {
359         try {
360             DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
361             factory.setNamespaceAware(true);
362             factory.setValidating(false);
363             DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
364             return builder.parse(stream);
365         } catch (ParserConfigurationException JavaDoc pce) {
366             throw new AxisFault(pce.getMessage(), pce);
367         } catch (SAXException JavaDoc se) {
368             throw new AxisFault(se.getMessage(), se);
369         } catch (IOException JavaDoc ioe) {
370             throw new AxisFault(ioe.getMessage(), ioe);
371         }
372     }
373
374     /**
375      * @param doc Document to update
376      * @return updated Document
377      * @throws AxisFault When Document cannot be parsed as a WSDL Definition
378      * instance
379      */

380     private Document JavaDoc updateWSDLPortLocations(Document JavaDoc doc) throws AxisFault {
381         log.debug("Entering updateWSDL");
382
383         QName JavaDoc docQname = new QName JavaDoc(doc.getDocumentElement().getNamespaceURI(), doc.getDocumentElement().getLocalName());
384
385         // If this is a wsdl:definition
386
if (WSDL_DEFINITIONS_QNAME.equals(docQname)) {
387             try {
388                 WSDLReader reader = getWSDLReader();
389                 // get Definition from Document
390
Definition def = reader.readWSDL(null, doc);
391
392                 /**
393                  * 1. iterer sur le port-component pour prendre leur URL 2. les
394                  * assigner en fonction du wsdl-port
395                  */

396                 QName JavaDoc sQName = sd.getWSDL().getServiceQname();
397                 Service s = def.getService(sQName);
398                 if (s != null) {
399
400                     List JavaDoc portsComp = sd.getPortComponents();
401                     for (Iterator JavaDoc i = portsComp.iterator(); i.hasNext();) {
402                         PortComponentDesc pcd = (PortComponentDesc) i.next();
403                         URL JavaDoc endpoint = pcd.getEndpointURL();
404                         QName JavaDoc portQName = pcd.getQName();
405
406                         Port port = s.getPort(portQName.getLocalPart());
407                         // maybe we have not found the requested Port
408
if (port != null) {
409                             // Set the updated soap:address address
410
List JavaDoc ext = port.getExtensibilityElements();
411                             for (Iterator JavaDoc it = ext.iterator(); it.hasNext();) {
412                                 ExtensibilityElement element = (ExtensibilityElement) it.next();
413                                 if (element.getElementType().equals(QNAME_SOAP_ADDRESS)) {
414                                     SOAPAddress sa = (SOAPAddress) element;
415                                     sa.setLocationURI(endpoint.toExternalForm());
416                                     log.debug("Update port soap:location with " + endpoint);
417                                 }
418                             }
419                         } else {
420                             log.warn("Cannot find wsdl:port '" + portQName.getLocalPart() + "' in wsdl:service "
421                                     + s.getQName());
422                         }
423                     }
424                 }
425
426                 return WSDLFactory.newInstance().newWSDLWriter().getDocument(def);
427             } catch (WSDLException wsdle) {
428                 throw new AxisFault("Cannot read WSDL Document", wsdle);
429             }
430         } else {
431             // if we have something else (not a wsdl:definition)
432
// return the document unmodified
433
return doc;
434         }
435
436     }
437
438     /**
439      * @return Returns a configured WSDLReader
440      * @throws WSDLException if factory or reader cannot be instanciated.
441      */

442     private WSDLReader getWSDLReader() throws WSDLException {
443         WSDLFactory factory = WSDLFactory.newInstance();
444         WSDLReader reader = factory.newWSDLReader();
445         reader.setFeature("javax.wsdl.importDocuments", false);
446         return reader;
447     }
448
449     /**
450      * @return Returns a configured WSDLWriter
451      * @throws WSDLException if factory or writer cannot be instanciated.
452      */

453     private WSDLWriter getWSDLWriter() throws WSDLException {
454         WSDLFactory factory = WSDLFactory.newInstance();
455         return factory.newWSDLWriter();
456     }
457
458     /**
459      * Reports WSDL
460      * @param doc Document to write
461      * @param writer Servlet Writer to use
462      */

463     public void reportWSDL(Document JavaDoc doc, PrintWriter JavaDoc writer) {
464         XMLUtils.PrettyDocumentToWriter(doc, writer);
465     }
466
467     /**
468      * Reports that we have no WSDL
469      * @param res HttpServletResponse
470      * @param writer PrintWriter
471      * @param moreDetailCode optional name of a message to provide more detail
472      * @param axisFault optional fault string, for extra info at debug time only
473      */

474     public void reportNoWSDL(HttpServletResponse JavaDoc res, PrintWriter JavaDoc writer, String JavaDoc moreDetailCode, AxisFault axisFault) {
475         res.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
476         res.setContentType("text/html");
477
478         writer.println("<h2>" + Messages.getMessage("error00") + "</h2>");
479         writer.println("<p>" + Messages.getMessage("noWSDL00") + "</p>");
480
481         if (moreDetailCode != null) {
482             writer.println("<p>" + Messages.getMessage(moreDetailCode) + "</p>");
483         }
484
485         if (axisFault != null && isDevelopment()) {
486             //dev systems only give fault dumps
487
writeFault(writer, axisFault);
488         }
489     }
490
491 }
Popular Tags