package at.gv.egovernment.moa.spss.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.X509Certificate;
import javax.servlet.http.HttpServletRequest;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.apache.axis.AxisFault;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import at.gv.egovernment.moa.logging.LogMsg;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.logging.LoggingContext;
import at.gv.egovernment.moa.logging.LoggingContextManager;
import at.gv.egovernment.moa.spss.MOASystemException;
import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider;
import at.gv.egovernment.moa.spss.server.transaction.TransactionContext;
import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager;
import at.gv.egovernment.moa.spss.server.transaction.TransactionIDGenerator;
import at.gv.egovernment.moa.spss.util.MessageProvider;
/**
* An handler that is invoked on each web service request and performs some
* central message handling.
*
* Mainly sets up the TransactionContext
for the current
* transaction (i.e. web service request).
*
* @author Patrick Peck
* @author Stefan Knirsch
* @version $Id$
*/
public class AxisHandler extends BasicHandler {
/** The resource names of the messages to load. */
private static final String MOA_SPSS_WSDL_RESOURCE_ = "/resources/wsdl/MOA-SPSS-1.2.wsdl";
/** The property name for accessing the HTTP request. */
private static final String REQUEST_PROPERTY = HTTPConstants.MC_HTTP_SERVLETREQUEST;
/** The property name for accessing the X509 client certificate chain. */
private static final String X509_CERTIFICATE_PROPERTY = "javax.servlet.request.X509Certificate";
/** The property name for accessing the SOAP action header. */
private static final String SOAP_ACTION_HEADER = "soapaction";
/**
* Handle an invocation of this handler.
*
* @param msgContext Information about this request/response.
* @throws AxisFault An error occurred during processing of the request.
* @see org.apache.axis.Handler#invoke(MessageContext)
*/
public void invoke(MessageContext msgContext) throws AxisFault {
if (!msgContext.getPastPivot()) {
handleRequest(msgContext);
} else {
handleResponse(msgContext);
}
}
/**
* This method is called by invoke
to handle incoming requests.
*
* @param msgContext The context as provided to invoke
.
* @throws AxisFault An error occurred during processing of the request.
*/
private void handleRequest(MessageContext msgContext) throws AxisFault {
try {
// generate a unique transaction id and build the TransactionContext
// for this request
HttpServletRequest request =
(HttpServletRequest) msgContext.getProperty(REQUEST_PROPERTY);
X509Certificate[] clientCert =
(X509Certificate[]) request.getAttribute(X509_CERTIFICATE_PROPERTY);
ConfigurationProvider configuration =
ConfigurationProvider.getInstance();
TransactionContext context =
new TransactionContext(
TransactionIDGenerator.nextID(),
clientCert,
configuration);
context.setRequestName((String) request.getHeader(SOAP_ACTION_HEADER));
setUpContexts(context);
// log some information about the request
info(
"handler.00",
new Object[] {
context.getTransactionID(),
msgContext.getTargetService()});
info("handler.01", new Object[] { request.getRemoteAddr()});
if (clientCert != null) {
info(
"handler.02",
new Object[] {
clientCert[0].getSubjectDN(),
clientCert[0].getSerialNumber(),
clientCert[0].getIssuerDN()});
} else {
info("handler.03", null);
}
if (Logger.isDebugEnabled()) {
String msg = msgContext.getCurrentMessage().getSOAPPartAsString();
Logger.debug(new LogMsg(msg));
}
} catch (MOASystemException e) {
MOASystemException se = new MOASystemException("2900", null, e);
AxisFault fault = AxisFault.makeFault(se);
fault.setFaultDetail(new Element[] { se.toErrorResponse()});
throw fault;
} catch (Throwable t) {
MOASystemException e = new MOASystemException("2900", null, t);
AxisFault fault = AxisFault.makeFault(e);
fault.setFaultDetail(new Element[] { e.toErrorResponse()});
throw fault;
}
}
/**
* This method is called by invoke
to handle outgoing
* responses.
*
* @param msgContext The context as provided to invoke
.
* @throws AxisFault An error occurred during processing of the response.
*/
private void handleResponse(MessageContext msgContext) throws AxisFault {
info("handler.04", null);
if (Logger.isDebugEnabled()) {
String msg = msgContext.getCurrentMessage().getSOAPPartAsString();
Logger.debug(new LogMsg(msg));
}
tearDownContexts();
}
/**
* Called, when the processing of the web service fails.
*
* @param msgContext Information about the current request.
* @see org.apache.axis.Handler#onFault(org.apache.axis.MessageContext)
*/
public void onFault(MessageContext msgContext) {
info("handler.05", null);
tearDownContexts();
}
/**
* Set up the thread-local contexts (TransactionContext
and
* LoggingContext
).
*
* @param context The TransactionContext
to set for the current
* request.
*/
private void setUpContexts(TransactionContext context) {
// set the transaction context in the TransactionContextManager
TransactionContextManager tcm = TransactionContextManager.getInstance();
tcm.setTransactionContext(context);
// set the logging context in the LoggingContextManager
LoggingContextManager lcm = LoggingContextManager.getInstance();
LoggingContext lc = new LoggingContext(context.getTransactionID());
lcm.setLoggingContext(lc);
}
/**
* Tear down the thread-local contexts.
*/
private void tearDownContexts() {
// unset the transaction context
TransactionContextManager tcm = TransactionContextManager.getInstance();
tcm.setTransactionContext(null);
// unset the logging context
LoggingContextManager lcm = LoggingContextManager.getInstance();
lcm.setLoggingContext(null);
}
/**
* Generate the WSDL into the msgContext
.
*
* The code of this method is more or less copied from the
* org.apache.axis.handlers.soap.SOAPService
class contained in
* the 1.1 release of Axis to allow for a missing wsdlFile
(so
* that a resource by the same name is searched for in the classpath). The
* implementation of this method should be obsolete if Axis 1.1 or higher is
* used.
*
* @param msgContext The MessageContext
that will contain the
* WSDL description of the current web service.
* @throws AxisFault An error occurred producing the WSDL.
*/
public void generateWSDL(MessageContext msgContext) throws AxisFault {
InputStream instream = null;
try {
String filename = MOA_SPSS_WSDL_RESOURCE_;
File file = new File(filename);
if (file.exists()) {
//if this resolves to a file, load it
instream = new FileInputStream(filename);
} else {
//else load a named resource in our classloader.
instream = this.getClass().getResourceAsStream(filename);
if (instream == null) {
String errorText = Messages.getMessage("wsdlFileMissing", filename);
throw new AxisFault(errorText);
}
}
Document doc = XMLUtils.newDocument(instream);
msgContext.setProperty("WSDL", doc);
} catch (Exception e) {
throw AxisFault.makeFault(e);
} finally {
if (instream != null) {
try {
instream.close();
} catch (IOException e) {
// ok to do nothing here
}
}
}
}
/**
* Utility function to issue an info message to the log.
*
* @param messageId The ID of the message to log.
* @param parameters Additional message parameters.
*/
private static void info(String messageId, Object[] parameters) {
MessageProvider msg = MessageProvider.getInstance();
Logger.info(new LogMsg(msg.getMessage(messageId, parameters)));
}
}