001package ca.uhn.hl7v2.hoh.raw.server;
002
003import java.io.IOException;
004import java.nio.charset.Charset;
005import java.util.Enumeration;
006import java.util.LinkedHashMap;
007
008import javax.servlet.ServletException;
009import javax.servlet.http.HttpServlet;
010import javax.servlet.http.HttpServletRequest;
011import javax.servlet.http.HttpServletResponse;
012
013import ca.uhn.hl7v2.hoh.api.DecodeException;
014import ca.uhn.hl7v2.hoh.api.IAuthorizationServerCallback;
015import ca.uhn.hl7v2.hoh.api.IMessageHandler;
016import ca.uhn.hl7v2.hoh.api.IResponseSendable;
017import ca.uhn.hl7v2.hoh.api.MessageMetadataKeys;
018import ca.uhn.hl7v2.hoh.api.MessageProcessingException;
019import ca.uhn.hl7v2.hoh.encoder.AuthorizationFailureException;
020import ca.uhn.hl7v2.hoh.encoder.Hl7OverHttpRequestDecoder;
021import ca.uhn.hl7v2.hoh.raw.api.RawReceivable;
022import ca.uhn.hl7v2.hoh.sign.ISigner;
023import ca.uhn.hl7v2.hoh.sign.SignatureVerificationException;
024import ca.uhn.hl7v2.hoh.util.HTTPUtils;
025
026public class HohRawServlet extends HttpServlet {
027
028        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HohRawServlet.class);
029        private static final long serialVersionUID = 1L;
030        private IAuthorizationServerCallback myAuthorizationCallback;
031        private IMessageHandler<String> myMessageHandler;
032        private ISigner mySigner;
033
034        /**
035         * {@inheritDoc}
036         */
037        @Override
038        protected void doGet(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException {
039
040                theResp.setStatus(400);
041                theResp.setContentType("text/html");
042
043                String message = "GET method is not supported by this server";
044                HTTPUtils.write400BadRequest(theResp.getOutputStream(), message, false);
045
046        }
047
048        /**
049         * {@inheritDoc}
050         */
051        @Override
052        protected void doPost(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException {
053
054                Hl7OverHttpRequestDecoder decoder = new Hl7OverHttpRequestDecoder();
055                decoder.setHeaders(new LinkedHashMap<String, String>());
056
057                Enumeration<?> headerNames = theReq.getHeaderNames();
058                while (headerNames.hasMoreElements()) {
059                        String nextName = (String) headerNames.nextElement();
060                        decoder.getHeaders().put(nextName, theReq.getHeader(nextName));
061                }
062
063                decoder.setPath(theReq.getRequestURI());
064                decoder.setAuthorizationCallback(myAuthorizationCallback);
065                decoder.setSigner(mySigner);
066
067                try {
068                        decoder.readContentsFromInputStreamAndDecode(theReq.getInputStream());
069                } catch (AuthorizationFailureException e) {
070                        ourLog.error("Authorization failed on request for {}", theReq.getRequestURI());
071                        theResp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
072                        HTTPUtils.write401Unauthorized(theResp.getOutputStream(), false);
073                        return;
074                } catch (DecodeException e) {
075                        ourLog.error("Request failure for " + theReq.getRequestURI(), e);
076                        theResp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
077                        HTTPUtils.write400BadRequest(theResp.getOutputStream(), e.getMessage(), false);
078                        return;
079                } catch (SignatureVerificationException e) {
080                        ourLog.error("Signature verification failed on request for {}", theReq.getRequestURI());
081                        theResp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
082                        HTTPUtils.write400SignatureVerificationFailed(theResp.getOutputStream(), false);
083                        return;
084                }
085
086                Charset charset = decoder.getCharset();
087                ourLog.debug("Message charset is {}", charset.displayName());
088
089                RawReceivable rawMessage = new RawReceivable(decoder.getMessage());
090                rawMessage.addMetadata(MessageMetadataKeys.REMOTE_HOST_ADDRESS.name(), theReq.getRemoteAddr());
091
092                IResponseSendable<String> response;
093                try {
094                        response = myMessageHandler.messageReceived(rawMessage);
095                } catch (MessageProcessingException e) {
096                        ourLog.error("Processing problem for " + theReq.getRequestURI(), e);
097                        theResp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
098                        HTTPUtils.write500InternalServerError(theResp.getOutputStream(), e.getMessage(), false);
099                        return;
100                }
101
102                theResp.setCharacterEncoding(charset.name());
103                theResp.setContentType(response.getEncodingStyle().getContentType());
104                theResp.setStatus(response.getResponseCode().getCode());
105
106                // n.b. don't ask for the writer until headers are set
107                response.writeMessage(theResp.getWriter());
108                theResp.flushBuffer();
109
110        }
111
112        /**
113         * If set, provides a callback which will be used to validate incoming
114         * credentials
115         */
116        public void setAuthorizationCallback(IAuthorizationServerCallback theAuthorizationCallback) {
117                myAuthorizationCallback = theAuthorizationCallback;
118        }
119
120        /**
121         * @param theMessageHandler
122         *            the messageHandler to set
123         */
124        public void setMessageHandler(IMessageHandler<String> theMessageHandler) {
125                myMessageHandler = theMessageHandler;
126        }
127
128        /**
129         * Sets the message signer if signature profile is being used
130         */
131        public void setSigner(ISigner theSigner) {
132                mySigner = theSigner;
133        }
134
135}