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.consumer;
15  
16  import javax.servlet.ServletException;
17  import javax.servlet.http.HttpServlet;
18  
19  import uk.nhs.interoperability.capabilities.ITKProfileManager;
20  import uk.nhs.interoperability.infrastructure.ITKMessageProperties;
21  import uk.nhs.interoperability.infrastructure.ITKMessagingException;
22  import uk.nhs.interoperability.payload.DEWrappedMessage;
23  import uk.nhs.interoperability.payload.ITKMessage;
24  import uk.nhs.interoperability.payload.ITKSimpleMessageResponse;
25  import uk.nhs.interoperability.service.ITKService;
26  import uk.nhs.interoperability.service.ITKSimpleDOS;
27  import uk.nhs.interoperability.transport.ITKInfrastructureAck;
28  import uk.nhs.interoperability.util.ITKApplicationProperties;
29  import uk.nhs.interoperability.util.Logger;
30  import uk.nhs.interoperability.util.MessageQueue;
31  
32  /**
33   * The Class ITKServlet.
34   *
35   * @author Michael Odling-Smee
36   * @author Nicholas Jones
37   * @since 0.1
38   */
39  @SuppressWarnings("serial")
40  public abstract class ITKServlet extends HttpServlet {
41  	
42  	/** The profile manger. */
43  	private ITKProfileManager profileManger;
44  	//private ITKMessageSender itkMessageSender;
45  	/** The message queue. */
46  	private MessageQueue messageQueue;
47  	
48  	/** The audit identity. */
49  	private String auditIdentity;
50  	
51  	/** The dos. */
52  	protected ITKSimpleDOS dos;
53  	
54  	/* (non-Javadoc)
55  	 * @see javax.servlet.GenericServlet#init()
56  	 */
57  	@Override
58  	public void init() throws ServletException {
59  		try {
60  			this.dos = new ITKSimpleDOS();
61  			this.messageQueue = new MessageQueue();
62  			this.profileManger = new ITKProfileManagerImpl();
63  			//this.itkMessageSender = new ITKMessageSenderImpl();
64  			this.auditIdentity = ITKApplicationProperties.getProperty("audit.identity");
65  		} catch (Throwable t) {
66  			throw new ServletException("Could not instantiate ITKMessageConsumer instance", t);
67  		}
68  		super.init();
69  	}
70  	
71  	
72  	/**
73  	 * Send infrastructure ack.
74  	 *
75  	 * @param requestMessageProperties the request message properties
76  	 * @throws ITKMessagingException the iTK messaging exception
77  	 */
78  	protected void sendInfrastructureAck(ITKMessageProperties requestMessageProperties) throws ITKMessagingException {
79  		Logger.debug("Creating and sending an infrastructureAck");
80  		ITKMessage ack = new ITKInfrastructureAck(requestMessageProperties, this.auditIdentity);
81  		//this.itkMessageSender.sendAsync(ack);
82  		this.messageQueue.queue(ack);
83  	}
84  	
85  	/**
86  	 * Checks whether the profileId in as identified in the ITKMessagingProperties is
87  	 * supported by the recipient.
88  	 *
89  	 * @param itkMessageProperties The ITKMessageProperties holding a reference to the
90  	 * profileId of the message
91  	 * @throws ITKMessagingException the iTK messaging exception
92  	 */
93  	protected void checkProfileId(ITKMessageProperties itkMessageProperties) throws ITKMessagingException {
94  		if (itkMessageProperties != null && itkMessageProperties.getProfileId() != null) {
95  			String profileId = itkMessageProperties.getProfileId();
96  			int profileSupportLevel = this.profileManger.getProfileSupportLevel(profileId);
97  			if (profileSupportLevel == ITKProfileManager.DEPRECATED) {
98  				Logger.warn("Profile \"" + profileId + "\" is deprecated - it will be processed for now but sender should be informed that support may be withdrawn in the near future");
99  			} else if (profileSupportLevel != ITKProfileManager.ACCEPTED) {
100 				Logger.warn("Profile \"" + profileId + "\" is not accepted - message will be rejected");
101 				throw new ITKMessagingException(itkMessageProperties, ITKMessagingException.INVALID_MESSAGE_CODE, "Profile \"" + profileId + "\" is not supported - rejecting message " + itkMessageProperties.getBusinessPayloadId());
102 			}
103 			//Profile is accepted
104 			return;
105 		}
106 		throw new ITKMessagingException(itkMessageProperties, ITKMessagingException.INVALID_MESSAGE_CODE, "Request message profileId could not be determined - rejecting message");
107 	}
108 	
109 	/**
110 	 * Check service id.
111 	 *
112 	 * @param itkMessageProperties the itk message properties
113 	 * @throws ITKMessagingException the iTK messaging exception
114 	 */
115 	protected void checkServiceId(ITKMessageProperties itkMessageProperties) throws ITKMessagingException {
116 		String serviceId = itkMessageProperties.getServiceId();
117 		ITKService service = dos.getService(serviceId);
118 		if (service==null){
119 			Logger.warn("Service \"" + serviceId + "\" is not accepted - message will be rejected");
120 			throw new ITKMessagingException(itkMessageProperties, ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, 
121 					"Service \"" + serviceId + "\" is not supported - rejecting message " + itkMessageProperties.getBusinessPayloadId());
122 		}
123 	}
124 
125 
126 	/**
127 	 * Validate distribution envelope.
128 	 *
129 	 * @param itkMessageProperties the itk message properties
130 	 * @throws ITKMessagingException the iTK messaging exception
131 	 */
132 	protected void validateDistributionEnvelope(ITKMessageProperties itkMessageProperties)
133 			throws ITKMessagingException {
134 			
135 				//Check that the profileId is accepted by the recipient application
136 				this.checkProfileId(itkMessageProperties);
137 				
138 				//Check that the serviceId is accepted by the recipient application
139 				this.checkServiceId(itkMessageProperties);
140 				
141 				// TODO : CM_DE_009: Check that the distribution envelope count is ok (manifest count = payload count)
142 				
143 				// TODO : CM_DE_009: Check Authorisation based on DE AuditIdentity
144 				if (itkMessageProperties.getAuditIdentity().getURI().length()==0) {
145 					Logger.warn("Audit Identity not populated - message will be rejected");
146 					throw new ITKMessagingException(itkMessageProperties, ITKMessagingException.INVALID_MESSAGE_CODE, 
147 							"Audit Identity not populated - message will be rejected" );
148 				}
149 				// TODO : THIS EXAMPLE BASED ON TKWAutotest check - should be replaced with real lookup.
150 				if (itkMessageProperties.getAuditIdentity().getURI().contains("INVALID")) {
151 					Logger.warn("Audit Identity not populated - message will be rejected");
152 					throw new ITKMessagingException(itkMessageProperties, ITKMessagingException.INVALID_MESSAGE_CODE, 
153 							"Audit Identity not populated - message will be rejected" );
154 				}
155 				
156 				// CM_DE_003: Check that the businessPayloadId is present.
157 				if (itkMessageProperties.getBusinessPayloadId().length()==0) {
158 					Logger.warn("Business Payload Id not populated - message will be rejected");
159 					throw new ITKMessagingException(itkMessageProperties, ITKMessagingException.INVALID_MESSAGE_CODE, 
160 							"Business Payload Id not populated - message will be rejected" );
161 			
162 				}
163 			}
164 
165 
166 	/**
167 	 * Adds the itk wrappers.
168 	 *
169 	 * @param itkMessage the itk message
170 	 * @return the iTK message
171 	 * @throws ITKMessagingException the iTK messaging exception
172 	 */
173 	protected ITKMessage addITKWrappers(ITKMessage itkMessage) throws ITKMessagingException {
174 		
175 		ITKMessage wrappedMessage = itkMessage ;
176 		/*
177 		 * TODO - how to know when to wrap in DE?
178 		 * For now some fairly simple rules - also needs
179 		 * consolidating with the way it is managed via the
180 		 * async scenario via ITKTransportRoute
181 		 */
182 		if (itkMessage != null && !(itkMessage instanceof ITKSimpleMessageResponse)) {
183 			//Wrap in DE
184 			//itkMessage = new DEWrappedMessage(itkMessage);
185 	
186 			// Get the ITKService from the DirectoryOfService
187 			ITKService service = dos.getService(itkMessage.getMessageProperties().getServiceId());
188 			if (service==null){
189 				Logger.warn("Response Service not configured - message will be rejected");
190 				throw new ITKMessagingException(ITKMessagingException.PROCESSING_ERROR_NOT_RETRYABLE_CODE, 
191 						"Response Service not configured - message will be rejected" );
192 			}
193 	
194 			// Does the message need a wrapper?
195 			// TODO: Is wrapper type really dependent on the Route? Or the Service?
196 			
197 			// TODO: The logic below is copied from buildMessage but for now the route.getWrapperType check is removed and 
198 			//       therefore DE is added according to the check above. Need to resolve what this wrapper is dependent on in reality.
199 			//if (route.getWrapperType().equals(ITKTransportRoute.DISTRIBUTION_ENVELOPE)){
200 				Logger.trace("Adding distribution envelope wrapper");
201 				if(service.isBase64()){
202 					String b64DocText = javax.xml.bind.DatatypeConverter
203 							.printBase64Binary(itkMessage.getBusinessPayload().getBytes());
204 					itkMessage.setBusinessPayload(b64DocText);
205 				}
206 				wrappedMessage = new DEWrappedMessage(service, itkMessage, true); 
207 			//} else {
208 			//	Logger.trace("No DE wrapper required");
209 			//	wrappedMessage = itkMessage;
210 			//}
211 		}	
212 		return wrappedMessage;
213 	}
214 
215 }