/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.openejb.server.axis; import org.apache.axis.AxisEngine; import org.apache.axis.AxisFault; import org.apache.axis.Constants; import org.apache.axis.Message; import org.apache.axis.MessageContext; import org.apache.axis.SOAPPart; import org.apache.axis.handlers.soap.SOAPService; import org.apache.axis.message.SOAPEnvelope; import org.apache.axis.soap.SOAPConstants; import org.apache.axis.transport.http.HTTPConstants; import org.apache.axis.utils.Messages; import org.apache.openejb.server.ServerRuntimeException; import org.apache.openejb.server.httpd.HttpListener; import org.apache.openejb.server.httpd.HttpRequest; import org.apache.openejb.server.httpd.HttpResponse; import org.apache.openejb.server.webservices.WsConstants; import org.apache.openejb.server.webservices.saaj.SaajUniverse; import org.apache.openejb.util.LogCategory; import org.apache.openejb.util.Logger; import org.w3c.dom.Element; import javax.servlet.http.HttpServletResponse; import javax.wsdl.OperationType; import javax.xml.soap.MimeHeader; import javax.xml.soap.MimeHeaders; import javax.xml.soap.SOAPMessage; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URL; import java.util.Iterator; import java.util.Map; public class AxisWsContainer implements HttpListener { private static final Logger logger = Logger.getInstance(LogCategory.AXIS, AxisWsContainer.class); public static final String REQUEST = AxisWsContainer.class.getName() + "@Request"; public static final String RESPONSE = AxisWsContainer.class.getName() + "@Response"; public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema"; private final URL wsdlLocation; private final SOAPService service; private final ClassLoader classLoader; private final Map wsdlMap; public AxisWsContainer(final URL wsdlURL, final SOAPService service, final Map wsdlMap, final ClassLoader classLoader) { this.wsdlLocation = wsdlURL; this.service = service; this.wsdlMap = wsdlMap; if (classLoader == null) { this.classLoader = Thread.currentThread().getContextClassLoader(); } else { this.classLoader = classLoader; } } public void onMessage(final HttpRequest request, final HttpResponse response) throws Exception { final SaajUniverse universe = new SaajUniverse(); universe.set(SaajUniverse.AXIS1); try { doService(request, response); } finally { universe.unset(); } } protected void doService(final HttpRequest req, final HttpResponse res) throws Exception { final org.apache.axis.MessageContext messageContext = new org.apache.axis.MessageContext(null); req.setAttribute(WsConstants.MESSAGE_CONTEXT, messageContext); messageContext.setClassLoader(classLoader); Message responseMessage; String contentType = req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); final String contentLocation = req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION); final InputStream inputStream = req.getInputStream(); final Message requestMessage = new Message(inputStream, false, contentType, contentLocation); messageContext.setRequestMessage(requestMessage); messageContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO, req.getURI().getPath()); messageContext.setProperty(org.apache.axis.MessageContext.TRANS_URL, req.getURI().toString()); messageContext.setService(service); messageContext.setProperty(REQUEST, req); messageContext.setProperty(RESPONSE, res); messageContext.setProperty(AxisEngine.PROP_DISABLE_PRETTY_XML, Boolean.TRUE); final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); try { try { final String characterEncoding = (String) requestMessage.getProperty(SOAPMessage.CHARACTER_SET_ENCODING); if (characterEncoding != null) { messageContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, characterEncoding); } else { messageContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8"); } final String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION); if (soapAction != null) { messageContext.setUseSOAPAction(true); messageContext.setSOAPActionURI(soapAction); } final SOAPEnvelope env = requestMessage.getSOAPEnvelope(); if (env != null && env.getSOAPConstants() != null) { messageContext.setSOAPConstants(env.getSOAPConstants()); } final SOAPService service = messageContext.getService(); Thread.currentThread().setContextClassLoader(classLoader); service.invoke(messageContext); responseMessage = messageContext.getResponseMessage(); } catch (final AxisFault fault) { if (req.getMethod().equals(HttpRequest.Method.GET.name()) && req.getParameters().isEmpty()) { String serviceName = req.getURI().getRawPath(); serviceName = serviceName.substring(serviceName.lastIndexOf("/") + 1); printServiceInfo(res, serviceName); return; } else { responseMessage = handleFault(fault, res, messageContext); } } catch (final Exception e) { responseMessage = handleException(messageContext, res, e); } //TODO investigate and fix operation == null! if (messageContext.getOperation() != null) { if (messageContext.getOperation().getMep() == OperationType.ONE_WAY) { // No content, so just indicate accepted res.setStatus(HttpServletResponse.SC_ACCEPTED); return; } else if (responseMessage == null) { responseMessage = handleException(messageContext, null, new ServerRuntimeException("No response for non-one-way operation")); } } else if (responseMessage == null) { res.setStatus(HttpServletResponse.SC_ACCEPTED); return; } try { final SOAPConstants soapConstants = messageContext.getSOAPConstants(); final String contentType1 = responseMessage.getContentType(soapConstants); res.setContentType(contentType1); // Transfer MIME headers to HTTP headers for response message. final MimeHeaders responseMimeHeaders = responseMessage.getMimeHeaders(); for (final Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) { final MimeHeader responseMimeHeader = (MimeHeader) i.next(); res.setHeader(responseMimeHeader.getName(), responseMimeHeader.getValue()); } //TODO discuss this with dims. // // synchronize the character encoding of request and response // String responseEncoding = (String) messageContext.getProperty( // SOAPMessage.CHARACTER_SET_ENCODING); // if (responseEncoding != null) { // try { // responseMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, // responseEncoding); // } catch (SOAPException e) { // log.info(Messages.getMessage("exception00"), e); // } // } //determine content type from message response contentType = responseMessage.getContentType(messageContext. getSOAPConstants()); responseMessage.writeTo(res.getOutputStream()); } catch (final Exception e) { logger.warning(Messages.getMessage("exception00"), e); } } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } private Message handleException(final MessageContext context, final HttpResponse res, final Exception e) { Message responseMessage; //other exceptions are internal trouble responseMessage = context.getResponseMessage(); res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); Message responseMsg = responseMessage; logger.warning(Messages.getMessage("exception00"), e); if (responseMsg == null) { final AxisFault fault = AxisFault.makeFault(e); //log the fault final Element runtimeException = fault.lookupFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); if (runtimeException != null) { logger.debug(Messages.getMessage("axisFault00"), fault); //strip runtime details fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); } responseMsg = new Message(fault); } responseMessage = responseMsg; final SOAPPart soapPart = (SOAPPart) responseMessage.getSOAPPart(); soapPart.getMessage().setMessageContext(context); return responseMessage; } private Message handleFault(final AxisFault fault, final HttpResponse res, final MessageContext context) { Message responseMessage; final Element runtimeException = fault.lookupFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); logger.warning(Messages.getMessage("axisFault00"), fault); if (runtimeException != null) { //strip runtime details fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); } final int status = fault.getFaultCode().getLocalPart().startsWith("Server.Unauth") ? HttpServletResponse.SC_UNAUTHORIZED : HttpServletResponse.SC_INTERNAL_SERVER_ERROR; if (status == HttpServletResponse.SC_UNAUTHORIZED) { // unauth access results in authentication request // TODO: less generic realm choice? res.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\""); } res.setStatus(status); responseMessage = context.getResponseMessage(); if (responseMessage == null) { responseMessage = new Message(fault); final SOAPPart soapPart = (SOAPPart) responseMessage.getSOAPPart(); soapPart.getMessage().setMessageContext(context); } return responseMessage; } public void getWsdl(final HttpRequest request, final HttpResponse response) throws Exception { final URI realLocation = request.getURI(); // log.info("Request at " + realLocation); final String query = realLocation.getQuery(); if (query == null || !query.toLowerCase().startsWith("wsdl")) { throw new IllegalStateException("request must contain a wsdl or WSDL parameter: " + request.getParameters()); } final String locationKey; if (query.length() > 4) { locationKey = query.substring(5); } else { locationKey = wsdlLocation.toString(); } final Object wsdl = wsdlMap.get(locationKey); if (wsdl == null) { throw new IllegalStateException("No wsdl or schema known at location: " + locationKey); } final URI updated = new URI(realLocation.getScheme(), realLocation.getUserInfo(), realLocation.getHost(), realLocation.getPort(), null, //try null for no path null, null); final String replaced = ((String) wsdl).replaceAll(WsConstants.LOCATION_REPLACEMENT_TOKEN, updated.toString()); response.getOutputStream().write(replaced.getBytes()); response.getOutputStream().flush(); } public void destroy() { } /** * print a snippet of service info. * * @param response response * @param serviceName Name of the service */ private void printServiceInfo(final HttpResponse response, final String serviceName) throws IOException { response.setContentType("text/html; charset=utf-8"); final StringBuffer output = new StringBuffer("<h1>") .append(serviceName).append("</h1>\n"); output.append("<p>").append(Messages.getMessage("axisService00")) .append("</p>\n"); output.append( "<i>").append( Messages.getMessage("perhaps00")).append( "</i>\n"); response.getOutputStream().write(output.toString().getBytes()); } }