View Javadoc

1   /**
2   The contents of this file are subject to the Mozilla Public License Version 1.1 
3   (the "License"); you may not use this file except in compliance with the License. 
4   You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
5   Software distributed under the License is distributed on an "AS IS" basis, 
6   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
7   specific language governing rights and limitations under the License. 
8   
9   The Original Code is "DefaultApplication.java".  Description: 
10  "An Application that does nothing with the message and returns an Application 
11   Reject message in response." 
12  
13  The Initial Developer of the Original Code is University Health Network. Copyright (C) 
14  2002.  All Rights Reserved. 
15  
16  Contributor(s): ______________________________________. 
17  
18  Alternatively, the contents of this file may be used under the terms of the 
19  GNU General Public License (the  "GPL"), in which case the provisions of the GPL are 
20  applicable instead of those above.  If you wish to allow use of your version of this 
21  file only under the terms of the GPL and not to allow others to use your version 
22  of this file under the MPL, indicate your decision by deleting  the provisions above 
23  and replace  them with the notice and other provisions required by the GPL License.  
24  If you do not delete the provisions above, a recipient may use your version of 
25  this file under either the MPL or the GPL. 
26   */
27  
28  package ca.uhn.hl7v2.app;
29  
30  import java.io.IOException;
31  import java.util.Date;
32  import java.util.GregorianCalendar;
33  
34  import ca.uhn.hl7v2.HL7Exception;
35  import ca.uhn.hl7v2.model.DataTypeException;
36  import ca.uhn.hl7v2.model.Message;
37  import ca.uhn.hl7v2.model.Segment;
38  import ca.uhn.hl7v2.model.Structure;
39  import ca.uhn.hl7v2.model.primitive.CommonTS;
40  import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
41  import ca.uhn.hl7v2.parser.ModelClassFactory;
42  import ca.uhn.hl7v2.parser.Parser;
43  import ca.uhn.hl7v2.util.MessageIDGenerator;
44  import ca.uhn.hl7v2.util.Terser;
45  
46  /**
47   * An Application that does nothing with the message and returns an Application
48   * Reject message in response. To be used when there are no other Applications
49   * that can process a given message.
50   * 
51   * @author Bryan Tripp
52   */
53  public class DefaultApplication implements Application {
54  
55  	/** Creates a new instance of DefaultApplication */
56  	public DefaultApplication() {
57  	}
58  
59  	/**
60  	 * Returns true.
61  	 */
62  	public boolean canProcess(Message in) {
63  		return true;
64  	}
65  
66  	/**
67  	 * Creates and returns an acknowledgement -- the details are determined by
68  	 * fillDetails().
69  	 */
70  	public Message processMessage(Message in) throws ApplicationException {
71  		try {
72  			// get default ACK
73  			Message out = makeACK(in);
74  			fillDetails(out);
75  			return out;
76  		} catch (Exception e) {
77  			throw new ApplicationException("Couldn't create response message: "
78  					+ e.getMessage());
79  		}
80  
81  	}
82  
83  	/**
84  	 * Fills in the details of an Application Reject message, including response
85  	 * and error codes, and a text error message. This is the method to override
86  	 * if you want to respond differently.
87  	 */
88  	public void fillDetails(Message ack) throws ApplicationException {
89  		try {
90  			// populate MSA and ERR with generic error ...
91  			Segment msa = (Segment) ack.get("MSA");
92  			Terser.set(msa, 1, 0, 1, 1, "AR");
93  			Terser.set(
94  					msa,
95  					3,
96  					0,
97  					1,
98  					1,
99  					"No appropriate destination could be found to which this message could be routed.");
100 			// this is max length
101 
102 			// populate ERR segment if it exists (may not depending on version)
103 			Structure s = ack.get("ERR");
104 			if (s != null) {
105 				Segment err = (Segment) s;
106 				Terser.set(err, 1, 0, 4, 1, "207");
107 				Terser.set(err, 1, 0, 4, 2, "Application Internal Error");
108 				Terser.set(err, 1, 0, 4, 3, "HL70357");
109 			}
110 
111 		} catch (Exception e) {
112 			throw new ApplicationException(
113 					"Error trying to create Application Reject message: "
114 							+ e.getMessage());
115 		}
116 	}
117 
118 	/**
119 	 * Creates an ACK message with the minimum required information from an
120 	 * inbound message. Optional fields can be filled in afterwards, before the
121 	 * message is returned. Please note that MSH-10, the outbound message
122 	 * control ID, is also set using the class
123 	 * <code>ca.uhn.hl7v2.util.MessageIDGenerator</code>. Also note that the ACK
124 	 * messages returned is the same version as the version stated in the
125 	 * inbound MSH if there is a generic ACK for that version, otherwise a
126 	 * version 2.4 ACK is returned. MSA-1 is set to AA by default.
127 	 * 
128 	 * @param inboundHeader
129 	 *            the MSH segment if the inbound message
130 	 * @throws IOException
131 	 *             if there is a problem reading or writing the message ID file
132 	 * @throws DataTypeException
133 	 *             if there is a problem setting ACK values
134 	 */
135 	public static Message makeACK(Message message) throws HL7Exception, IOException {
136 		return makeACK((Segment)message.get("MSH"));
137 	}
138 	
139 	public static Message makeACK(Segment inboundHeader) throws HL7Exception,
140 			IOException {
141 		if (!inboundHeader.getName().equals("MSH"))
142 			throw new HL7Exception(
143 					"Need an MSH segment to create a response ACK (got "
144 							+ inboundHeader.getName() + ")");
145 
146 		// make ACK of correct version
147 		Class<? extends Message> clazz = null;
148 		try {
149 			Message inbound = inboundHeader.getMessage();
150 			Parser p = inbound.getParser();
151 			ModelClassFactory mcf = p != null ? p.getFactory() : new DefaultModelClassFactory();
152 			String version = inbound.getVersion();
153 			if (version == null)
154 				version = "2.4";
155 			clazz = mcf.getMessageClass("ACK", version, false);
156 			Message out = clazz.newInstance();
157 			Terser terser = new Terser(out);
158 
159 			// populate outbound MSH using data from inbound message ...
160 			Segment outHeader = (Segment) out.get("MSH");
161 			fillResponseHeader(inboundHeader, outHeader);
162 
163 			terser.set("/MSH-9-1", "ACK");
164 			terser.set("/MSH-9-2", Terser.get(inboundHeader, 9, 0, 2, 1));
165 			terser.set("/MSH-12", Terser.get(inboundHeader, 12, 0, 1, 1));
166 			terser.set("/MSA-1", "AA");
167 			terser.set("/MSA-2", Terser.get(inboundHeader, 10, 0, 1, 1));
168 			return out;
169 
170 		} catch (Exception e) {
171 			throw new HL7Exception("Can't instantiate ACK of class "
172 					+ clazz.getName(), e);
173 		}
174 
175 	}
176 
177 	/**
178 	 * Populates certain required fields in a response message header, using
179 	 * information from the corresponding inbound message. The current time is
180 	 * used for the message time field, and <code>MessageIDGenerator</code> is
181 	 * used to create a unique message ID. Version and message type fields are
182 	 * not populated.
183 	 */
184 	public static void fillResponseHeader(Segment inbound, Segment outbound)
185 			throws HL7Exception, IOException {
186 		if (!inbound.getName().equals("MSH")
187 				|| !outbound.getName().equals("MSH"))
188 			throw new HL7Exception("Need MSH segments.  Got "
189 					+ inbound.getName() + " and " + outbound.getName());
190 
191 		// get MSH data from incoming message ...
192 		String encChars = Terser.get(inbound, 2, 0, 1, 1);
193 		String fieldSep = Terser.get(inbound, 1, 0, 1, 1);
194 		String procID = Terser.get(inbound, 11, 0, 1, 1);
195 
196 		// populate outbound MSH using data from inbound message ...
197 		Terser.set(outbound, 2, 0, 1, 1, encChars);
198 		Terser.set(outbound, 1, 0, 1, 1, fieldSep);
199 		GregorianCalendar now = new GregorianCalendar();
200 		now.setTime(new Date());
201 		Terser.set(outbound, 7, 0, 1, 1, CommonTS.toHl7TSFormat(now));
202 		Terser.set(outbound, 10, 0, 1, 1, MessageIDGenerator.getInstance()
203 				.getNewID());
204 		Terser.set(outbound, 11, 0, 1, 1, procID);
205 
206 		// revert sender and receiver
207 		Terser.set(outbound, 3, 0, 1, 1, Terser.get(inbound, 5, 0, 1, 1));
208 		Terser.set(outbound, 4, 0, 1, 1, Terser.get(inbound, 6, 0, 1, 1));
209 		Terser.set(outbound, 5, 0, 1, 1, Terser.get(inbound, 3, 0, 1, 1));
210 		Terser.set(outbound, 6, 0, 1, 1, Terser.get(inbound, 4, 0, 1, 1));
211 	}
212 
213 }