QSUpdateServiceWSDLHandler.java

00001 
00025 package org.objectweb.jonas.ws.axis;
00026 
00027 import java.io.File;
00028 import java.io.IOException;
00029 import java.io.InputStream;
00030 import java.io.PrintWriter;
00031 import java.net.HttpURLConnection;
00032 import java.net.URL;
00033 import java.util.Iterator;
00034 import java.util.List;
00035 
00036 import javax.naming.InitialContext;
00037 import javax.naming.NamingException;
00038 import javax.servlet.http.HttpServletRequest;
00039 import javax.servlet.http.HttpServletResponse;
00040 import javax.wsdl.Definition;
00041 import javax.wsdl.Port;
00042 import javax.wsdl.Service;
00043 import javax.wsdl.WSDLException;
00044 import javax.wsdl.extensions.ExtensibilityElement;
00045 import javax.wsdl.extensions.soap.SOAPAddress;
00046 import javax.wsdl.factory.WSDLFactory;
00047 import javax.wsdl.xml.WSDLReader;
00048 import javax.wsdl.xml.WSDLWriter;
00049 import javax.xml.namespace.QName;
00050 import javax.xml.parsers.DocumentBuilder;
00051 import javax.xml.parsers.DocumentBuilderFactory;
00052 import javax.xml.parsers.ParserConfigurationException;
00053 
00054 import org.w3c.dom.Attr;
00055 import org.w3c.dom.Document;
00056 import org.w3c.dom.Element;
00057 import org.w3c.dom.NodeList;
00058 import org.xml.sax.SAXException;
00059 
00060 import org.apache.axis.AxisFault;
00061 import org.apache.axis.Constants;
00062 import org.apache.axis.MessageContext;
00063 import org.apache.axis.i18n.Messages;
00064 import org.apache.axis.server.AxisServer;
00065 import org.apache.axis.transport.http.AbstractQueryStringHandler;
00066 import org.apache.axis.transport.http.HTTPConstants;
00067 import org.apache.axis.utils.XMLUtils;
00068 
00069 import org.objectweb.jonas_ws.deployment.api.PortComponentDesc;
00070 import org.objectweb.jonas_ws.deployment.api.ServiceDesc;
00071 
00072 import org.objectweb.jonas.ws.WSServiceException;
00073 
00079 public class QSUpdateServiceWSDLHandler extends AbstractQueryStringHandler {
00080 
00084     private static final String NS_URI_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/";
00085 
00089     private static final QName QNAME_SOAP_ADDRESS = new QName(NS_URI_SOAP, "address");
00090 
00094     private static final String NS_URI_WSDL = "http://schemas.xmlsoap.org/wsdl/";
00095 
00099     private static final String NS_URI_XSD = "http://www.w3.org/2001/XMLSchema";
00100 
00104     private static final String PARAM_FILENAME = "filename";
00105 
00109     private static final String PARAM_CONTEXT = "context";
00110 
00114     private static final String PARAM_JWSDL = "JWSDL";
00115 
00119     private static final QName WSDL_DEFINITIONS_QNAME = new QName(NS_URI_WSDL, "definitions");
00120 
00124     private ServiceDesc sd = null;
00125 
00132     public void invoke(MessageContext msgContext) throws AxisFault {
00133         // Obtain objects relevant to the task at hand from the provided
00134         // MessageContext's bag.
00135         configureFromContext(msgContext);
00136 
00137         AxisServer engine = (AxisServer) msgContext.getProperty(HTTPConstants.PLUGIN_ENGINE);
00138         PrintWriter writer = (PrintWriter) msgContext.getProperty(HTTPConstants.PLUGIN_WRITER);
00139         HttpServletResponse response = (HttpServletResponse) msgContext
00140                 .getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE);
00141         HttpServletRequest request = (HttpServletRequest) msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
00142 
00143         InitialContext ctx;
00144         try {
00145             ctx = new InitialContext();
00146             sd = (ServiceDesc) ctx.lookup("java:comp/jonas/" + engine.getName() + "/dd");
00147         } catch (NamingException e) {
00148             throw new AxisFault("Servlet name not found : " + engine.getName(), e);
00149         }
00150 
00151         String wsdlFilename = request.getParameter(PARAM_FILENAME);
00152         String context = request.getParameter(PARAM_CONTEXT);
00153         try {
00154             Document doc = null;
00155             if (wsdlFilename == null) {
00156                 // as a Document
00157                 doc = getDefinitionAsDocument(sd.getWSDL().getDefinition());
00158                 wsdlFilename = sd.getWSDL().getName();
00159                 String[] pathElements = wsdlFilename.split("/");
00160                 if (pathElements.length <= 2) {
00161                     throw new WSServiceException("invalid filename");
00162                 }
00163 
00164                 StringBuffer buf = new StringBuffer();
00165                 for (int i = 2; i < pathElements.length; i++) {
00166                     buf.append(pathElements[i]);
00167                     if (i != (pathElements.length - 1)) {
00168                         // last part is a filename
00169                         buf.append("/");
00170                     }
00171                 }
00172                 // remove WEB-INF/wsdl/
00173                 // remove META-INF/wsdl/
00174                 wsdlFilename = buf.toString();
00175                 context = ".";
00176                 msgContext.setProperty("WSDL", doc);
00177             } else {
00178                 // try to get the specified WSDL from cache ...
00179                 doc = (Document) msgContext.getProperty("WSDL_" + wsdlFilename);
00180 
00181                 if (doc == null) {
00182                     // create the WSDL/Imported file
00183                     doc = getDocument(wsdlFilename, context);
00184                 }
00185 
00186                 msgContext.setProperty("WSDL_" + wsdlFilename, doc);
00187             }
00188 
00189             if (doc != null) {
00190                 // update WSDL
00191                 modifyImports(doc, request, new File(context, wsdlFilename).getParent());
00192                 Document up2date = updateWSDLPortLocations(doc);
00193                 response.setContentType("text/xml; charset=" + XMLUtils.getEncoding().toLowerCase());
00194                 reportWSDL(up2date, writer);
00195             } else {
00196                 // report Error
00197                 if (log.isDebugEnabled()) {
00198                     log.debug("processWsdlRequest: failed to create WSDL");
00199                 }
00200                 reportNoWSDL(response, writer, "noWSDL02", null);
00201             }
00202         } catch (AxisFault axisFault) {
00203             //the no-service fault is mapped to a no-wsdl error
00204             if (axisFault.getFaultCode().equals(Constants.QNAME_NO_SERVICE_FAULT_CODE)) {
00205                 //which we log
00206                 processAxisFault(axisFault);
00207 
00208                 //then report under a 404 error
00209                 response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
00210                 reportNoWSDL(response, writer, "noWSDL01", axisFault);
00211             } else {
00212                 //all other faults get thrown
00213                 throw axisFault;
00214             }
00215         }
00216     }
00217 
00223     private Document getDefinitionAsDocument(Definition definition) throws AxisFault {
00224 
00225         try {
00226             WSDLWriter writer = getWSDLWriter();
00227             return writer.getDocument(definition);
00228         } catch (WSDLException e) {
00229             throw new AxisFault(e.getMessage(), e);
00230         }
00231 
00232     }
00233 
00240     private void modifyImports(Document doc, HttpServletRequest request, String context) {
00241         // Document may be a wsdl:definition or xsd:schema
00242         // So we must handle import (definitions) and include (schema)
00243 
00244         // wsdl:definition / xsd:schema
00245         Element de = doc.getDocumentElement();
00246 
00247         NodeList imports = de.getElementsByTagNameNS(NS_URI_WSDL, "import");
00248 
00249         // modify wsdl:import location
00250         for (int i = 0; i < imports.getLength(); i++) {
00251             Element imp = (Element) imports.item(i);
00252             Attr location = imp.getAttributeNode("location");
00253             if (!location.getValue().startsWith("http://")) {
00254                 // relative import
00255                 String req = computeUpdatedURL(request, context, location);
00256 
00257                 log.debug("Replacing wsdl:location '" + location.getValue() + "' with '" + req.toString() + "'");
00258                 location.setValue(req.toString());
00259             }
00260         }
00261 
00262         // modify xsd:include schemaLocation
00263         updateSchema(de, "include", request, context);
00264         // modify xsd:import schemaLocation
00265         updateSchema(de, "import", request, context);
00266 
00267         // wsdl:definitions/wsdl:types/xsd:schema/(xsd:import|xsd:include)
00268         NodeList types = de.getElementsByTagNameNS(NS_URI_WSDL, "types");
00269         // is there a types here ?
00270         if (types.getLength() != 0) {
00271 
00272             // get the only wsdl:types element
00273             Element typesElement = (Element) types.item(0);
00274 
00275             // is there some xsd:schema out there ?
00276             NodeList schemasList = typesElement.getElementsByTagNameNS(NS_URI_XSD, "schema");
00277             for (int i = 0; i < schemasList.getLength(); i++) {
00278                 Element schema = (Element) schemasList.item(i);
00279                 updateSchema(schema, "include", request, context);
00280                 updateSchema(schema, "import", request, context);
00281             }
00282         }
00283     }
00284 
00291     private String computeUpdatedURL(HttpServletRequest request, String context, Attr location) {
00292         StringBuffer req = request.getRequestURL();
00293         req.append("?" + PARAM_JWSDL);
00294         req.append("&" + PARAM_FILENAME + "=" + location.getValue());
00295         req.append("&" + PARAM_CONTEXT + "=" + context);
00296         return req.toString();
00297     }
00298 
00305     private void updateSchema(Element schema, String elementName, HttpServletRequest request, String context) {
00306 
00307         NodeList elements = schema.getElementsByTagNameNS(NS_URI_XSD, elementName);
00308 
00309         // modify xsd:include|xsd:import schemaLocation
00310         for (int i = 0; i < elements.getLength(); i++) {
00311             Element e = (Element) elements.item(i);
00312             Attr location = e.getAttributeNode("schemaLocation");
00313             if ((location != null) && (!location.getValue().startsWith("http://"))) {
00314                 // relative import
00315                 String req = computeUpdatedURL(request, context, location);
00316 
00317                 log.debug("Replacing xsd:schemaLocation '" + location.getValue() + "' with '" + req.toString() + "'");
00318                 location.setValue(req.toString());
00319             }
00320         }
00321     }
00322 
00330     private Document getDocument(String wsdlFilename, String context) throws AxisFault {
00331 
00332         // Check that the filename is only relative to META-INF/wsdl or
00333         // WEB-INF/wsdl no deeper !
00334         // TODO Security Check !
00335 
00336         ClassLoader cl = Thread.currentThread().getContextClassLoader();
00337         URL res = cl.getResource(context + "/" + wsdlFilename);
00338 
00339         Document doc = null;
00340         if (res != null) {
00341             try {
00342                 doc = createDocument(res.openStream());
00343             } catch (IOException ioe) {
00344                 throw new AxisFault("Cannot open requested URL : " + res);
00345             }
00346         } else {
00347             throw new AxisFault("Cannot find requested document : " + wsdlFilename);
00348         }
00349 
00350         return doc;
00351     }
00352 
00358     private Document createDocument(InputStream stream) throws AxisFault {
00359         try {
00360             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
00361             factory.setNamespaceAware(true);
00362             factory.setValidating(false);
00363             DocumentBuilder builder = factory.newDocumentBuilder();
00364             return builder.parse(stream);
00365         } catch (ParserConfigurationException pce) {
00366             throw new AxisFault(pce.getMessage(), pce);
00367         } catch (SAXException se) {
00368             throw new AxisFault(se.getMessage(), se);
00369         } catch (IOException ioe) {
00370             throw new AxisFault(ioe.getMessage(), ioe);
00371         }
00372     }
00373 
00380     private Document updateWSDLPortLocations(Document doc) throws AxisFault {
00381         log.debug("Entering updateWSDL");
00382 
00383         QName docQname = new QName(doc.getDocumentElement().getNamespaceURI(), doc.getDocumentElement().getLocalName());
00384 
00385         // If this is a wsdl:definition
00386         if (WSDL_DEFINITIONS_QNAME.equals(docQname)) {
00387             try {
00388                 WSDLReader reader = getWSDLReader();
00389                 // get Definition from Document
00390                 Definition def = reader.readWSDL(null, doc);
00391 
00396                 QName sQName = sd.getWSDL().getServiceQname();
00397                 Service s = def.getService(sQName);
00398                 if (s != null) {
00399 
00400                     List portsComp = sd.getPortComponents();
00401                     for (Iterator i = portsComp.iterator(); i.hasNext();) {
00402                         PortComponentDesc pcd = (PortComponentDesc) i.next();
00403                         URL endpoint = pcd.getEndpointURL();
00404                         QName portQName = pcd.getQName();
00405 
00406                         Port port = s.getPort(portQName.getLocalPart());
00407                         // maybe we have not found the requested Port
00408                         if (port != null) {
00409                             // Set the updated soap:address address
00410                             List ext = port.getExtensibilityElements();
00411                             for (Iterator it = ext.iterator(); it.hasNext();) {
00412                                 ExtensibilityElement element = (ExtensibilityElement) it.next();
00413                                 if (element.getElementType().equals(QNAME_SOAP_ADDRESS)) {
00414                                     SOAPAddress sa = (SOAPAddress) element;
00415                                     sa.setLocationURI(endpoint.toExternalForm());
00416                                     log.debug("Update port soap:location with " + endpoint);
00417                                 }
00418                             }
00419                         } else {
00420                             log.warn("Cannot find wsdl:port '" + portQName.getLocalPart() + "' in wsdl:service "
00421                                     + s.getQName());
00422                         }
00423                     }
00424                 }
00425 
00426                 return WSDLFactory.newInstance().newWSDLWriter().getDocument(def);
00427             } catch (WSDLException wsdle) {
00428                 throw new AxisFault("Cannot read WSDL Document", wsdle);
00429             }
00430         } else {
00431             // if we have something else (not a wsdl:definition)
00432             // return the document unmodified
00433             return doc;
00434         }
00435 
00436     }
00437 
00442     private WSDLReader getWSDLReader() throws WSDLException {
00443         WSDLFactory factory = WSDLFactory.newInstance();
00444         WSDLReader reader = factory.newWSDLReader();
00445         reader.setFeature("javax.wsdl.importDocuments", false);
00446         return reader;
00447     }
00448 
00453     private WSDLWriter getWSDLWriter() throws WSDLException {
00454         WSDLFactory factory = WSDLFactory.newInstance();
00455         return factory.newWSDLWriter();
00456     }
00457 
00463     public void reportWSDL(Document doc, PrintWriter writer) {
00464         XMLUtils.PrettyDocumentToWriter(doc, writer);
00465     }
00466 
00474     public void reportNoWSDL(HttpServletResponse res, PrintWriter writer, String moreDetailCode, AxisFault axisFault) {
00475         res.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
00476         res.setContentType("text/html");
00477 
00478         writer.println("<h2>" + Messages.getMessage("error00") + "</h2>");
00479         writer.println("<p>" + Messages.getMessage("noWSDL00") + "</p>");
00480 
00481         if (moreDetailCode != null) {
00482             writer.println("<p>" + Messages.getMessage(moreDetailCode) + "</p>");
00483         }
00484 
00485         if (axisFault != null && isDevelopment()) {
00486             //dev systems only give fault dumps
00487             writeFault(writer, axisFault);
00488         }
00489     }
00490 
00491 }

Generated on Tue Feb 15 15:05:36 2005 for JOnAS by  doxygen 1.3.9.1