1
2
3
4
5
6
7
8
9
10
11
12
13
14 package uk.nhs.interoperability.consumer;
15
16 import java.io.IOException;
17
18 import javax.servlet.ServletException;
19 import javax.servlet.http.HttpServletRequest;
20 import javax.servlet.http.HttpServletResponse;
21 import javax.xml.parsers.ParserConfigurationException;
22 import javax.xml.xpath.XPathConstants;
23 import javax.xml.xpath.XPathExpressionException;
24
25 import org.w3c.dom.Document;
26 import org.w3c.dom.Node;
27 import org.xml.sax.SAXException;
28
29 import uk.nhs.interoperability.capabilities.AuditException;
30 import uk.nhs.interoperability.capabilities.AuditService;
31 import uk.nhs.interoperability.infrastructure.ITKMessageProperties;
32 import uk.nhs.interoperability.infrastructure.ITKMessagePropertiesImpl;
33 import uk.nhs.interoperability.infrastructure.ITKMessagingException;
34 import uk.nhs.interoperability.infrastructure.ITKTransportPropertiesImpl;
35 import uk.nhs.interoperability.payload.ITKMessage;
36 import uk.nhs.interoperability.payload.ITKSimpleMessageResponse;
37 import uk.nhs.interoperability.payload.SimpleMessage;
38 import uk.nhs.interoperability.service.ITKSimpleAudit;
39 import uk.nhs.interoperability.transport.ITKTransportProperties;
40 import uk.nhs.interoperability.transport.WS.ITKSOAPException;
41 import uk.nhs.interoperability.transport.WS.WSSOAPMessageImpl;
42 import uk.nhs.interoperability.util.Logger;
43 import uk.nhs.interoperability.util.ServletUtils;
44 import uk.nhs.interoperability.util.xml.DomUtils;
45 import uk.nhs.interoperability.util.xml.XPaths;
46
47
48
49
50
51
52
53
54 @SuppressWarnings("serial")
55 public abstract class AbstractRoutedMessageServlet extends ITKServlet {
56
57
58
59 private ITKMessageConsumer messageConsumer;
60
61
62
63
64 @Override
65 public void init() throws ServletException {
66 this.messageConsumer = getMessageConsumer();
67 super.init();
68 }
69
70
71
72
73
74
75 public abstract ITKMessageConsumer getMessageConsumer();
76
77
78
79
80 @Override
81 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
82 Logger.debug("Received a routed message");
83
84 try {
85 byte[] requestMsgBytes = ServletUtils.readRequestContent(req);
86 if (requestMsgBytes == null) {
87 throw new ITKMessagingException(ITKMessagingException.INVALID_MESSAGE_CODE, "The request did not contain any content");
88 }
89 String requestString = new String(requestMsgBytes);
90 ITKMessage requestMsg = this.createRequestMessage(requestString);
91 ITKMessage responseMsg = this.processMessage(requestMsg);
92
93
94 this.sendInfrastructureAck(requestMsg.getMessageProperties());
95
96
97
98 ITKMessage response = new WSSOAPMessageImpl(null, responseMsg, WSSOAPMessageImpl.SYNCRESP);
99
100 resp.getWriter().write(response.getFullPayload());
101
102 return;
103 } catch (ITKMessagingException e) {
104 Logger.error("Could not process message", e);
105 resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
106
107
108
109
110
111 resp.getWriter().write(new ITKSOAPException(e).serialiseXML());
112 } catch (Throwable t) {
113 Logger.error("Could not process message - general error", t);
114 resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
115 resp.getWriter().write(t.getLocalizedMessage());
116 } finally {
117 Logger.debug("Completed processing");
118 }
119 }
120
121
122
123
124
125
126
127
128 private ITKMessage createRequestMessage(String requestString) throws ITKMessagingException {
129 ITKTransportProperties itkTransportProperties = null;
130 ITKMessagePropertiesImpl itkMessageProperties = null;
131 try {
132
133
134
135 Document doc = DomUtils.parse(requestString);
136
137 Logger.trace(DomUtils.serialiseToXML(doc, DomUtils.PRETTY_PRINT));
138
139
140
141 itkTransportProperties = ITKTransportPropertiesImpl.buildFromSoap(doc);
142
143
144
145 Document de = ITKMessagePropertiesImpl.extractDistributionEnvelopeFromSoap(doc);
146
147 itkMessageProperties = (ITKMessagePropertiesImpl) ITKMessagePropertiesImpl.build(de);
148
149 this.validateDistributionEnvelope(itkMessageProperties);
150
151 itkMessageProperties.setInboundTransportProperties(itkTransportProperties);
152
153
154
155
156 Document businessPayload = DomUtils.createDocumentFromNode((Node)XPaths.SOAP_WRAPPED_ITK_FIRST_PAYLOAD_XPATH.evaluate(doc, XPathConstants.NODE));
157
158 Logger.trace(DomUtils.serialiseToXML(businessPayload, DomUtils.PRETTY_PRINT));
159
160
161 ITKMessage requestMsg = new SimpleMessage();
162 requestMsg.setBusinessPayload(DomUtils.serialiseToXML(businessPayload));
163 requestMsg.setMessageProperties(itkMessageProperties);
164
165 return requestMsg;
166
167 } catch (XPathExpressionException e) {
168 throw new ITKMessagingException(itkTransportProperties, itkMessageProperties, ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, "Could not extract values from request", e);
169 } catch (IOException e) {
170 throw new ITKMessagingException(itkTransportProperties, itkMessageProperties, ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, "Could not parse request", e);
171 } catch (ParserConfigurationException e) {
172 throw new ITKMessagingException(itkTransportProperties, itkMessageProperties, ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, "XML parser configuration error", e);
173 } catch (SAXException e) {
174 throw new ITKMessagingException(itkTransportProperties, itkMessageProperties, ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, "Error parsing request XML", e);
175 }
176 }
177
178
179
180
181
182
183
184
185 private ITKMessage processMessage(ITKMessage requestMsg) throws ITKMessagingException {
186 ITKMessageProperties itkMessageProperties = requestMsg.getMessageProperties();
187 ITKTransportProperties itkTransportProperties = itkMessageProperties.getInboundTransportProperties();
188 try {
189
190 this.messageConsumer.onMessage(requestMsg);
191
192
193 ITKSimpleAudit.getInstance().auditEvent(AuditService.MESSAGE_RECEIPT_EVENT, System.currentTimeMillis(), itkMessageProperties);
194
195
196
197 return new ITKSimpleMessageResponse(itkMessageProperties, true);
198
199 } catch (AuditException e) {
200 throw new ITKMessagingException(itkTransportProperties, itkMessageProperties, ITKMessagingException.PROCESSING_ERROR_RETRYABLE_CODE, "Failed to write audit", e);
201 }
202 }
203
204
205 }