/**
* 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());
}
}