
org.objectweb.jonas.ws.axis.QSUpdateServiceWSDLHandler Maven / Gradle / Ivy
The newest version!
/**
* JOnAS: Java(TM) Open Application Server
* Copyright (C) 1999-2004 Bull S.A.
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: QSUpdateServiceWSDLHandler.java 6070 2005-01-11 18:08:31Z sauthieg $
* --------------------------------------------------------------------------
*/
package org.objectweb.jonas.ws.axis;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.wsdl.xml.WSDLWriter;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.apache.axis.AxisFault;
import org.apache.axis.Constants;
import org.apache.axis.MessageContext;
import org.apache.axis.i18n.Messages;
import org.apache.axis.server.AxisServer;
import org.apache.axis.transport.http.AbstractQueryStringHandler;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.axis.utils.XMLUtils;
import org.objectweb.jonas_ws.deployment.api.PortComponentDesc;
import org.objectweb.jonas_ws.deployment.api.ServiceDesc;
import org.objectweb.jonas.ws.WSServiceException;
/**
* Update the wsdlFile specified in wsdd with the good URLs for endpoints.
* responds to the ?JWSDL Supports wsdl:import and xsd:include
* @author Guillaume Sauthier
*/
public class QSUpdateServiceWSDLHandler extends AbstractQueryStringHandler {
/**
* SOAP NS URI
*/
private static final String NS_URI_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/";
/**
* soap:address Type QName
*/
private static final QName QNAME_SOAP_ADDRESS = new QName(NS_URI_SOAP, "address");
/**
* WSDL NS URI
*/
private static final String NS_URI_WSDL = "http://schemas.xmlsoap.org/wsdl/";
/**
* XSD NS URI
*/
private static final String NS_URI_XSD = "http://www.w3.org/2001/XMLSchema";
/**
* filename parameter name
*/
private static final String PARAM_FILENAME = "filename";
/**
* context parameter name
*/
private static final String PARAM_CONTEXT = "context";
/**
* JWSDL parameter QSHandler name
*/
private static final String PARAM_JWSDL = "JWSDL";
/**
* wsdl:definition QName
*/
private static final QName WSDL_DEFINITIONS_QNAME = new QName(NS_URI_WSDL, "definitions");
/**
* Service meta data
*/
private ServiceDesc sd = null;
/**
* Performs the action associated with this particular query string handler.
* @param msgContext a MessageContext object containing message context
* information for this query string handler.
* @throws AxisFault if an error occurs.
*/
public void invoke(MessageContext msgContext) throws AxisFault {
// Obtain objects relevant to the task at hand from the provided
// MessageContext's bag.
configureFromContext(msgContext);
AxisServer engine = (AxisServer) msgContext.getProperty(HTTPConstants.PLUGIN_ENGINE);
PrintWriter writer = (PrintWriter) msgContext.getProperty(HTTPConstants.PLUGIN_WRITER);
HttpServletResponse response = (HttpServletResponse) msgContext
.getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE);
HttpServletRequest request = (HttpServletRequest) msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
InitialContext ctx;
try {
ctx = new InitialContext();
sd = (ServiceDesc) ctx.lookup("java:comp/jonas/" + engine.getName() + "/dd");
} catch (NamingException e) {
throw new AxisFault("Servlet name not found : " + engine.getName(), e);
}
String wsdlFilename = request.getParameter(PARAM_FILENAME);
String context = request.getParameter(PARAM_CONTEXT);
try {
Document doc = null;
if (wsdlFilename == null) {
// as a Document
doc = getDefinitionAsDocument(sd.getWSDL().getDefinition());
wsdlFilename = sd.getWSDL().getName();
String[] pathElements = wsdlFilename.split("/");
if (pathElements.length <= 2) {
throw new WSServiceException("invalid filename");
}
StringBuffer buf = new StringBuffer();
for (int i = 2; i < pathElements.length; i++) {
buf.append(pathElements[i]);
if (i != (pathElements.length - 1)) {
// last part is a filename
buf.append("/");
}
}
// remove WEB-INF/wsdl/
// remove META-INF/wsdl/
wsdlFilename = buf.toString();
context = ".";
msgContext.setProperty("WSDL", doc);
} else {
// try to get the specified WSDL from cache ...
doc = (Document) msgContext.getProperty("WSDL_" + wsdlFilename);
if (doc == null) {
// create the WSDL/Imported file
doc = getDocument(wsdlFilename, context);
}
msgContext.setProperty("WSDL_" + wsdlFilename, doc);
}
if (doc != null) {
// update WSDL
modifyImports(doc, request, new File(context, wsdlFilename).getParent());
Document up2date = updateWSDLPortLocations(doc);
response.setContentType("text/xml; charset=" + XMLUtils.getEncoding().toLowerCase());
reportWSDL(up2date, writer);
} else {
// report Error
if (log.isDebugEnabled()) {
log.debug("processWsdlRequest: failed to create WSDL");
}
reportNoWSDL(response, writer, "noWSDL02", null);
}
} catch (AxisFault axisFault) {
//the no-service fault is mapped to a no-wsdl error
if (axisFault.getFaultCode().equals(Constants.QNAME_NO_SERVICE_FAULT_CODE)) {
//which we log
processAxisFault(axisFault);
//then report under a 404 error
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
reportNoWSDL(response, writer, "noWSDL01", axisFault);
} else {
//all other faults get thrown
throw axisFault;
}
}
}
/**
* @param definition Definition to convert
* @return returns the given Definition instance as a Document instance
* @throws AxisFault when convertion is not possible
*/
private Document getDefinitionAsDocument(Definition definition) throws AxisFault {
try {
WSDLWriter writer = getWSDLWriter();
return writer.getDocument(definition);
} catch (WSDLException e) {
throw new AxisFault(e.getMessage(), e);
}
}
/**
* Update the wsdl:import and xsd:include elements of the given Document.
* @param doc Definitions or Schema document instance.
* @param request HTTP request
* @param context loading Context
*/
private void modifyImports(Document doc, HttpServletRequest request, String context) {
// Document may be a wsdl:definition or xsd:schema
// So we must handle import (definitions) and include (schema)
// wsdl:definition / xsd:schema
Element de = doc.getDocumentElement();
NodeList imports = de.getElementsByTagNameNS(NS_URI_WSDL, "import");
// modify wsdl:import location
for (int i = 0; i < imports.getLength(); i++) {
Element imp = (Element) imports.item(i);
Attr location = imp.getAttributeNode("location");
if (!location.getValue().startsWith("http://")) {
// relative import
String req = computeUpdatedURL(request, context, location);
log.debug("Replacing wsdl:location '" + location.getValue() + "' with '" + req.toString() + "'");
location.setValue(req.toString());
}
}
// modify xsd:include schemaLocation
updateSchema(de, "include", request, context);
// modify xsd:import schemaLocation
updateSchema(de, "import", request, context);
// wsdl:definitions/wsdl:types/xsd:schema/(xsd:import|xsd:include)
NodeList types = de.getElementsByTagNameNS(NS_URI_WSDL, "types");
// is there a types here ?
if (types.getLength() != 0) {
// get the only wsdl:types element
Element typesElement = (Element) types.item(0);
// is there some xsd:schema out there ?
NodeList schemasList = typesElement.getElementsByTagNameNS(NS_URI_XSD, "schema");
for (int i = 0; i < schemasList.getLength(); i++) {
Element schema = (Element) schemasList.item(i);
updateSchema(schema, "include", request, context);
updateSchema(schema, "import", request, context);
}
}
}
/**
* @param request the Http Request
* @param context loading context
* @param location attribute to update
* @return return the new location value
*/
private String computeUpdatedURL(HttpServletRequest request, String context, Attr location) {
StringBuffer req = request.getRequestURL();
req.append("?" + PARAM_JWSDL);
req.append("&" + PARAM_FILENAME + "=" + location.getValue());
req.append("&" + PARAM_CONTEXT + "=" + context);
return req.toString();
}
/**
* @param schema The Element representing a Schema to be updated
* @param elementName the element name with "schemaLocation" attribute (can be "import" or "include")
* @param request the HTTP Request
* @param context loading context
*/
private void updateSchema(Element schema, String elementName, HttpServletRequest request, String context) {
NodeList elements = schema.getElementsByTagNameNS(NS_URI_XSD, elementName);
// modify xsd:include|xsd:import schemaLocation
for (int i = 0; i < elements.getLength(); i++) {
Element e = (Element) elements.item(i);
Attr location = e.getAttributeNode("schemaLocation");
if ((location != null) && (!location.getValue().startsWith("http://"))) {
// relative import
String req = computeUpdatedURL(request, context, location);
log.debug("Replacing xsd:schemaLocation '" + location.getValue() + "' with '" + req.toString() + "'");
location.setValue(req.toString());
}
}
}
/**
* @param wsdlFilename resource to load.
* @param context loading context
* @return Returns a Document created from the filename loaded in the
* context ClassLoader.
* @throws AxisFault if resource if not found or if resource is not XML.
*/
private Document getDocument(String wsdlFilename, String context) throws AxisFault {
// Check that the filename is only relative to META-INF/wsdl or
// WEB-INF/wsdl no deeper !
// TODO Security Check !
ClassLoader cl = Thread.currentThread().getContextClassLoader();
URL res = cl.getResource(context + "/" + wsdlFilename);
Document doc = null;
if (res != null) {
try {
doc = createDocument(res.openStream());
} catch (IOException ioe) {
throw new AxisFault("Cannot open requested URL : " + res);
}
} else {
throw new AxisFault("Cannot find requested document : " + wsdlFilename);
}
return doc;
}
/**
* @param stream supposed XML InputStream
* @return Returns the Document parsed from the given InputStream
* @throws AxisFault if parsing goes wrong.
*/
private Document createDocument(InputStream stream) throws AxisFault {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(stream);
} catch (ParserConfigurationException pce) {
throw new AxisFault(pce.getMessage(), pce);
} catch (SAXException se) {
throw new AxisFault(se.getMessage(), se);
} catch (IOException ioe) {
throw new AxisFault(ioe.getMessage(), ioe);
}
}
/**
* @param doc Document to update
* @return updated Document
* @throws AxisFault When Document cannot be parsed as a WSDL Definition
* instance
*/
private Document updateWSDLPortLocations(Document doc) throws AxisFault {
log.debug("Entering updateWSDL");
QName docQname = new QName(doc.getDocumentElement().getNamespaceURI(), doc.getDocumentElement().getLocalName());
// If this is a wsdl:definition
if (WSDL_DEFINITIONS_QNAME.equals(docQname)) {
try {
WSDLReader reader = getWSDLReader();
// get Definition from Document
Definition def = reader.readWSDL(null, doc);
/**
* 1. iterer sur le port-component pour prendre leur URL 2. les
* assigner en fonction du wsdl-port
*/
QName sQName = sd.getWSDL().getServiceQname();
Service s = def.getService(sQName);
if (s != null) {
List portsComp = sd.getPortComponents();
for (Iterator i = portsComp.iterator(); i.hasNext();) {
PortComponentDesc pcd = (PortComponentDesc) i.next();
URL endpoint = pcd.getEndpointURL();
QName portQName = pcd.getQName();
Port port = s.getPort(portQName.getLocalPart());
// maybe we have not found the requested Port
if (port != null) {
// Set the updated soap:address address
List ext = port.getExtensibilityElements();
for (Iterator it = ext.iterator(); it.hasNext();) {
ExtensibilityElement element = (ExtensibilityElement) it.next();
if (element.getElementType().equals(QNAME_SOAP_ADDRESS)) {
SOAPAddress sa = (SOAPAddress) element;
sa.setLocationURI(endpoint.toExternalForm());
log.debug("Update port soap:location with " + endpoint);
}
}
} else {
log.warn("Cannot find wsdl:port '" + portQName.getLocalPart() + "' in wsdl:service "
+ s.getQName());
}
}
}
return WSDLFactory.newInstance().newWSDLWriter().getDocument(def);
} catch (WSDLException wsdle) {
throw new AxisFault("Cannot read WSDL Document", wsdle);
}
} else {
// if we have something else (not a wsdl:definition)
// return the document unmodified
return doc;
}
}
/**
* @return Returns a configured WSDLReader
* @throws WSDLException if factory or reader cannot be instanciated.
*/
private WSDLReader getWSDLReader() throws WSDLException {
WSDLFactory factory = WSDLFactory.newInstance();
WSDLReader reader = factory.newWSDLReader();
reader.setFeature("javax.wsdl.importDocuments", false);
return reader;
}
/**
* @return Returns a configured WSDLWriter
* @throws WSDLException if factory or writer cannot be instanciated.
*/
private WSDLWriter getWSDLWriter() throws WSDLException {
WSDLFactory factory = WSDLFactory.newInstance();
return factory.newWSDLWriter();
}
/**
* Reports WSDL
* @param doc Document to write
* @param writer Servlet Writer to use
*/
public void reportWSDL(Document doc, PrintWriter writer) {
XMLUtils.PrettyDocumentToWriter(doc, writer);
}
/**
* Reports that we have no WSDL
* @param res HttpServletResponse
* @param writer PrintWriter
* @param moreDetailCode optional name of a message to provide more detail
* @param axisFault optional fault string, for extra info at debug time only
*/
public void reportNoWSDL(HttpServletResponse res, PrintWriter writer, String moreDetailCode, AxisFault axisFault) {
res.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
res.setContentType("text/html");
writer.println("" + Messages.getMessage("error00") + "
");
writer.println("" + Messages.getMessage("noWSDL00") + "
");
if (moreDetailCode != null) {
writer.println("" + Messages.getMessage(moreDetailCode) + "
");
}
if (axisFault != null && isDevelopment()) {
//dev systems only give fault dumps
writeFault(writer, axisFault);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy