View Javadoc

1   /*
2      Licensed under the Apache License, Version 2.0 (the "License");
3      you may not use this file except in compliance with the License.
4      You may obtain a copy of the License at
5   
6        http://www.apache.org/licenses/LICENSE-2.0
7   
8      Unless required by applicable law or agreed to in writing, software
9      distributed under the License is distributed on an "AS IS" BASIS,
10     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11     See the License for the specific language governing permissions and
12     limitations under the License.
13  */
14  package uk.nhs.interoperability.infrastructure;
15  
16  import javax.xml.xpath.XPathExpressionException;
17  
18  import org.w3c.dom.Document;
19  
20  import com.xmlsolutions.annotation.Requirement;
21  
22  import uk.nhs.interoperability.transport.ITKTransportProperties;
23  import uk.nhs.interoperability.transport.ITKTransportRoute;
24  import uk.nhs.interoperability.transport.ITKTransportRouteImpl;
25  import uk.nhs.interoperability.transport.WS.SOAPUtils;
26  import uk.nhs.interoperability.util.Logger;
27  import uk.nhs.interoperability.util.xml.XPaths;
28  
29  /**
30   * The Class ITKTransportPropertiesImpl.
31   *
32   * @author Michael Odling-Smee
33   * @author Nicholas Jones
34   * @since 0.1
35   */
36  public class ITKTransportPropertiesImpl implements ITKTransportProperties {
37  	
38  	/** The transport from. */
39  	private String transportFrom;
40  	
41  	/** The transport to. */
42  	private String transportTo;
43  	
44  	/** The invoked url. */
45  	private String invokedUrl;
46  	
47  	/** The transport relates to. */
48  	private String transportRelatesTo;
49  	
50  	/** The transport reply to. */
51  	private String transportReplyTo;
52  	
53  	/** The transport fault to. */
54  	private String transportFaultTo;
55  	
56  	/** The transport action. */
57  	private String transportAction;
58  	
59  	/** The transport message id. */
60  	private String transportMessageId;
61  	
62  	/** The transport type. */
63  	private String transportType;
64  
65  	/**
66  	 * Instantiates a new iTK transport properties impl.
67  	 *
68  	 * @param transportType the transport type
69  	 */
70  	public ITKTransportPropertiesImpl(String transportType) {
71  		this.transportType = transportType;
72  	}
73  
74  	/* (non-Javadoc)
75  	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportFrom()
76  	 */
77  	public String getTransportFrom() {
78  		return transportFrom;
79  	}
80  
81  	/* (non-Javadoc)
82  	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportFrom(java.lang.String)
83  	 */
84  	public void setTransportFrom(String transportFrom) {
85  		this.transportFrom = transportFrom;
86  	}
87  
88  	/* (non-Javadoc)
89  	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportTo()
90  	 */
91  	public String getTransportTo() {
92  		return transportTo;
93  	}
94  
95  	/* (non-Javadoc)
96  	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportTo(java.lang.String)
97  	 */
98  	public void setTransportTo(String transportTo) {
99  		this.transportTo = transportTo;
100 	}
101 
102 	/* (non-Javadoc)
103 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getInvokedUrl()
104 	 */
105 	public String getInvokedUrl() {
106 		return invokedUrl;
107 	}
108 
109 	/* (non-Javadoc)
110 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setInvokedUrl(java.lang.String)
111 	 */
112 	public void setInvokedUrl(String invokedUrl) {
113 		this.invokedUrl = invokedUrl;
114 	}
115 
116 	/* (non-Javadoc)
117 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportRelatesTo()
118 	 */
119 	public String getTransportRelatesTo() {
120 		return transportRelatesTo;
121 	}
122 
123 	/* (non-Javadoc)
124 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportRelatesTo(java.lang.String)
125 	 */
126 	public void setTransportRelatesTo(String transportRelatesTo) {
127 		this.transportRelatesTo = transportRelatesTo;
128 	}
129 
130 	/* (non-Javadoc)
131 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportReplyTo()
132 	 */
133 	public String getTransportReplyTo() {
134 		return transportReplyTo;
135 	}
136 
137 	/* (non-Javadoc)
138 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportReplyTo(java.lang.String)
139 	 */
140 	public void setTransportReplyTo(String transportReplyTo) {
141 		this.transportReplyTo = transportReplyTo;
142 	}
143 
144 	/* (non-Javadoc)
145 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportFaultTo()
146 	 */
147 	public String getTransportFaultTo() {
148 		return transportFaultTo;
149 	}
150 
151 	/* (non-Javadoc)
152 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportFaultTo(java.lang.String)
153 	 */
154 	public void setTransportFaultTo(String transportFaultTo) {
155 		this.transportFaultTo = transportFaultTo;
156 	}
157 
158 	/* (non-Javadoc)
159 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportAction()
160 	 */
161 	public String getTransportAction() {
162 		return transportAction;
163 	}
164 
165 	/* (non-Javadoc)
166 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportAction(java.lang.String)
167 	 */
168 	public void setTransportAction(String transportAction) {
169 		this.transportAction = transportAction;
170 	}
171 
172 	/* (non-Javadoc)
173 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportMessageId()
174 	 */
175 	@Requirement(traceTo="WS-ADR-01", status="implemented")
176 	public String getTransportMessageId() {
177 		return transportMessageId;
178 	}
179 
180 	/* (non-Javadoc)
181 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportMessageId(java.lang.String)
182 	 */
183 	@Requirement(traceTo="WS-ADR-01", status="implemented")
184 	public void setTransportMessageId(String transportMessageId) {
185 		this.transportMessageId = transportMessageId;
186 	}
187 	
188 	/* (non-Javadoc)
189 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#setTransportType(java.lang.String)
190 	 */
191 	@Override
192 	public void setTransportType(String transportType) {
193 		this.transportType = transportType;
194 	}
195 	
196 	/* (non-Javadoc)
197 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportFaultToRoute()
198 	 */
199 	@Override
200 	public ITKTransportRoute getTransportFaultToRoute() {
201 		String address = SOAPUtils.resolveFaultToAddress(this);
202 		if (address != null) {
203 			return new ITKTransportRouteImpl(this.transportType, address);
204 		}
205 		return null;
206 	}
207 	
208 	/* (non-Javadoc)
209 	 * @see uk.nhs.interoperability.transport.ITKTransportProperties#getTransportReplyToRoute()
210 	 */
211 	@Override
212 	public ITKTransportRoute getTransportReplyToRoute() {
213 		String address = SOAPUtils.resolveReplyToAddress(this);
214 		Logger.trace("Reply to address " + address);
215 		if (address != null) {
216 			return new ITKTransportRouteImpl(this.transportType, address);
217 		}
218 		return null;
219 	}
220 	
221 	/**
222 	 * Builds the from soap.
223 	 *
224 	 * @param doc the doc
225 	 * @return the iTK transport properties
226 	 * @throws ITKMessagingException the iTK messaging exception
227 	 */
228 	@Requirement(traceTo="WS-EXT-03", status="not-started")
229 	public static ITKTransportProperties buildFromSoap(Document doc) throws ITKMessagingException {
230 		//Construct an empty itkTransportProperties
231 		ITKTransportProperties itkTransportProperties = new ITKTransportPropertiesImpl(ITKTransportRoute.HTTP_WS);
232 		
233 		try {
234 			//Extract some key properties from the SOAP envelope
235 
236 			// WS_SO_001 : Validate that the To Element exists
237 			String transportTo = XPaths.WSA_TO_XPATH.evaluate(doc);
238 			if (transportTo.length()==0) {
239 				Logger.warn("SOAP To Element not populated - message will be rejected");
240 				throw new ITKMessagingException(ITKMessagingException.INVALID_MESSAGE_CODE, 
241 						"SOAP To Element not populated - message will be rejected" );
242 			}
243 			// TODO : WS_SO_002 : Validate that the To Element is valid
244 			// Implementation below is only for testing
245 			if (transportTo.toUpperCase().contains("INVALID")) {
246 				Logger.warn("SOAP To Element is invalid - message will be rejected");
247 				throw new ITKMessagingException(ITKMessagingException.INVALID_MESSAGE_CODE, 
248 						"SOAP To Element is invalid - message will be rejected" );
249 			}
250 
251 			// WS_SO_003 : Validate that the Action Element exists
252 			String transportAction = XPaths.WSA_ACTION_XPATH.evaluate(doc);
253 			if (transportAction.length()==0) {
254 				Logger.warn("SOAP Action Element not populated - message will be rejected");
255 				throw new ITKMessagingException(ITKMessagingException.INVALID_MESSAGE_CODE, 
256 						"SOAP Action Element not populated - message will be rejected" );
257 			}
258 
259 			String transportMessageId = XPaths.WSA_MSGID_XPATH.evaluate(doc);
260 			String transportReplyTo = XPaths.WSA_REPLY_TO_XPATH.evaluate(doc);
261 			String transportFaultTo = XPaths.WSA_FAULT_TO_XPATH.evaluate(doc);
262 			String transportFrom = XPaths.WSA_FROM_XPATH.evaluate(doc);
263 			
264 			// Security header fields
265 			// WS_SO_004 : Validate that the Timestamp Element exists
266 			String timestamp = XPaths.WSA_SECURITY_TIMESTAMP_XPATH.evaluate(doc);
267 			if (timestamp.length()==0){
268 				Logger.warn("SOAP Timestamp Element missing - message will be rejected");
269 				throw new ITKMessagingException(ITKMessagingException.INVALID_MESSAGE_CODE, 
270 						"SOAP Timestamp Element missing - message will be rejected" );
271 			}
272 			
273 			// TODO: WS_SO_005 : Validate message expiry
274 			//String expires   = XPaths.WSA_SECURITY_EXPIRES_XPATH.evaluate(doc);
275 			
276 			// WS_SO_006 : Validate that the Username Element exists
277 			// TODO: Should we validate SOAP errors in here (first opportunity) or in the servlet?
278 			//       Currently RI does both - need to standardise.
279 			String username  = XPaths.WSA_SECURITY_USERNAME_XPATH.evaluate(doc);
280 			if (username.length()==0){
281 				Logger.warn("SOAP Username Element missing - message will be rejected");
282 				throw new ITKMessagingException(ITKMessagingException.ACCESS_DENIED_CODE, 
283 						"SOAP Username Element missing - message will be rejected" );
284 			}
285 
286 			// TODO: WS_SO_007 : Validate that expires is not before created
287 			//String created   = XPaths.WSA_SECURITY_CREATED_XPATH.evaluate(doc);
288 
289 			// @Requirement(traceTo={"WS-PAT-02","IFA-REL-01"})
290 			// TODO: WS_SO_010 : non-anonymous ReplyTo in Synchronous only pattern
291 			
292 			// TODO: WS_SO_013 : reject soap:mustUnderstand=1
293 
294 			// WS_SO_014 : Username must be valid for this service
295 			if (username.toUpperCase().contains("IINVALID")){
296 				Logger.warn("SOAP Username is invalid - message will be rejected");
297 				throw new ITKMessagingException(ITKMessagingException.ACCESS_DENIED_CODE, 
298 						"SOAP Username is invalid - message will be rejected" );
299 			}
300 
301 			
302 			/*
303 
304 			 * Set the WSA properties
305 			 * (not part of interface specification but useful internally within reference implementation)
306 			 */
307 			itkTransportProperties.setTransportMessageId(transportMessageId);
308 			itkTransportProperties.setTransportAction(transportAction);
309 			itkTransportProperties.setTransportFrom(transportFrom);
310 			itkTransportProperties.setTransportReplyTo(transportReplyTo);
311 			itkTransportProperties.setTransportFaultTo(transportFaultTo);
312 			itkTransportProperties.setTransportTo(transportTo);
313 			
314 			Logger.debug(itkTransportProperties.toString());
315 			
316 			return itkTransportProperties;
317 			
318 		} catch (XPathExpressionException e) {
319 			throw new ITKMessagingException(ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, "Could not extract values from request", e);
320 		} 
321 	}
322 	
323 	/* (non-Javadoc)
324 	 * @see java.lang.Object#toString()
325 	 */
326 	@Override
327 	public String toString() {
328 		return "[" + this.getClass().getCanonicalName() + "]"
329 					+ "\n\tMessage transport id " + this.getTransportMessageId()
330 					+ "\n\tMessage transport action " + this.getTransportAction()
331 					+ "\n\tMessage transport from " + this.getTransportFrom()
332 					+ "\n\tMessage transport to " + this.getTransportTo()
333 					+ "\n\tMessage transport replyTo " + this.getTransportReplyTo()
334 					+ "\n\tMessage transport faultTo " + this.getTransportFaultTo();
335 	}
336 }