001 /** 002 The contents of this file are subject to the Mozilla Public License Version 1.1 003 (the "License"); you may not use this file except in compliance with the License. 004 You may obtain a copy of the License at http://www.mozilla.org/MPL/ 005 Software distributed under the License is distributed on an "AS IS" basis, 006 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 007 specific language governing rights and limitations under the License. 008 009 The Original Code is "DefaultApplication.java". Description: 010 "An Application that does nothing with the message and returns an Application 011 Reject message in response." 012 013 The Initial Developer of the Original Code is University Health Network. Copyright (C) 014 2002. All Rights Reserved. 015 016 Contributor(s): ______________________________________. 017 018 Alternatively, the contents of this file may be used under the terms of the 019 GNU General Public License (the ?GPL?), in which case the provisions of the GPL are 020 applicable instead of those above. If you wish to allow use of your version of this 021 file only under the terms of the GPL and not to allow others to use your version 022 of this file under the MPL, indicate your decision by deleting the provisions above 023 and replace them with the notice and other provisions required by the GPL License. 024 If you do not delete the provisions above, a recipient may use your version of 025 this file under either the MPL or the GPL. 026 */ 027 028 package ca.uhn.hl7v2.app; 029 030 import java.io.IOException; 031 import java.util.Date; 032 import java.util.GregorianCalendar; 033 034 import ca.uhn.hl7v2.HL7Exception; 035 import ca.uhn.hl7v2.model.DataTypeException; 036 import ca.uhn.hl7v2.model.Message; 037 import ca.uhn.hl7v2.model.Segment; 038 import ca.uhn.hl7v2.model.Structure; 039 import ca.uhn.hl7v2.model.primitive.CommonTS; 040 import ca.uhn.hl7v2.parser.DefaultModelClassFactory; 041 import ca.uhn.hl7v2.util.MessageIDGenerator; 042 import ca.uhn.hl7v2.util.Terser; 043 import ca.uhn.log.HapiLog; 044 import ca.uhn.log.HapiLogFactory; 045 046 /** 047 * An Application that does nothing with the message and returns an Application 048 * Reject message in response. To be used when there are no other Applications 049 * that can process a given message. 050 * @author Bryan Tripp 051 */ 052 public class DefaultApplication implements Application { 053 054 private static final HapiLog log = HapiLogFactory.getHapiLog(DefaultApplication.class); 055 056 /** Creates a new instance of DefaultApplication */ 057 public DefaultApplication() { 058 } 059 060 /** 061 * Returns true. 062 */ 063 public boolean canProcess(Message in) { 064 return true; 065 } 066 067 /** 068 * Creates and returns an acknowledgement -- the details are determined by fillDetails(). 069 */ 070 public Message processMessage(Message in) throws ApplicationException { 071 Message out = null; 072 try { 073 //get default ACK 074 out = makeACK((Segment) in.get("MSH")); 075 fillDetails(out); 076 } catch (Exception e) { 077 throw new ApplicationException("Couldn't create response message: " + e.getMessage()); 078 } 079 return out; 080 } 081 082 /** 083 * Fills in the details of an Application Reject message, including response and 084 * error codes, and a text error message. This is the method to override if you want 085 * to respond differently. 086 */ 087 public void fillDetails(Message ack) throws ApplicationException { 088 try { 089 //populate MSA and ERR with generic error ... 090 Segment msa = (Segment) ack.get("MSA"); 091 Terser.set(msa, 1, 0, 1, 1, "AR"); 092 Terser.set( 093 msa, 094 3, 095 0, 096 1, 097 1, 098 "No appropriate destination could be found to which this message could be routed."); 099 //this is max length 100 101 //populate ERR segment if it exists (may not depending on version) 102 Structure s = ack.get("ERR"); 103 if (s != null) { 104 Segment err = (Segment) s; 105 Terser.set(err, 1, 0, 4, 1, "207"); 106 Terser.set(err, 1, 0, 4, 2, "Application Internal Error"); 107 Terser.set(err, 1, 0, 4, 3, "HL70357"); 108 } 109 110 } 111 catch (Exception e) { 112 throw new ApplicationException("Error trying to create Application Reject message: " + e.getMessage()); 113 } 114 } 115 116 /** 117 * Creates an ACK message with the minimum required information from an inbound message. 118 * Optional fields can be filled in afterwards, before the message is returned. Pleaase 119 * note that MSH-10, the outbound message control ID, is also set using the class 120 * <code>ca.uhn.hl7v2.util.MessageIDGenerator</code>. Also note that the ACK messages returned 121 * is the same version as the version stated in the inbound MSH if there is a generic ACK for that 122 * version, otherwise a version 2.4 ACK is returned. MSA-1 is set to AA by default. 123 * 124 * @param inboundHeader the MSH segment if the inbound message 125 * @throws IOException if there is a problem reading or writing the message ID file 126 * @throws DataTypeException if there is a problem setting ACK values 127 */ 128 public static Message makeACK(Segment inboundHeader) throws HL7Exception, IOException { 129 if (!inboundHeader.getName().equals("MSH")) 130 throw new HL7Exception( 131 "Need an MSH segment to create a response ACK (got " + inboundHeader.getName() + ")"); 132 133 //make ACK of correct version 134 String version = null; 135 try { 136 version = Terser.get(inboundHeader, 12, 0, 1, 1); 137 } 138 catch (HL7Exception e) { /* proceed with null */ 139 } 140 if (version == null) version = "2.4"; 141 142 String ackClassName = DefaultModelClassFactory.getVersionPackageName(version) + "message.ACK"; 143 144 Message out = null; 145 try { 146 Class ackClass = Class.forName(ackClassName); 147 out = (Message) ackClass.newInstance(); 148 } 149 catch (Exception e) { 150 throw new HL7Exception("Can't instantiate ACK of class " + ackClassName + ": " + e.getClass().getName()); 151 } 152 Terser terser = new Terser(out); 153 154 //populate outbound MSH using data from inbound message ... 155 Segment outHeader = (Segment) out.get("MSH"); 156 fillResponseHeader(inboundHeader, outHeader); 157 158 terser.set("/MSH-9", "ACK"); 159 terser.set("/MSH-12", version); 160 terser.set("/MSA-1", "AA"); 161 terser.set("/MSA-2", terser.get(inboundHeader, 10, 0, 1, 1)); 162 163 return out; 164 } 165 166 /** 167 * Populates certain required fields in a response message header, using 168 * information from the corresponding inbound message. The current time is 169 * used for the message time field, and <code>MessageIDGenerator</code> is 170 * used to create a unique message ID. Version and message type fields are 171 * not populated. 172 */ 173 public static void fillResponseHeader(Segment inbound, Segment outbound) throws HL7Exception, IOException { 174 if (!inbound.getName().equals("MSH") || !outbound.getName().equals("MSH")) 175 throw new HL7Exception("Need MSH segments. Got " + inbound.getName() + " and " + outbound.getName()); 176 177 //get MSH data from incoming message ... 178 String encChars = Terser.get(inbound, 2, 0, 1, 1); 179 String fieldSep = Terser.get(inbound, 1, 0, 1, 1); 180 String procID = Terser.get(inbound, 11, 0, 1, 1); 181 182 //populate outbound MSH using data from inbound message ... 183 Terser.set(outbound, 2, 0, 1, 1, encChars); 184 Terser.set(outbound, 1, 0, 1, 1, fieldSep); 185 GregorianCalendar now = new GregorianCalendar(); 186 now.setTime(new Date()); 187 Terser.set(outbound, 7, 0, 1, 1, CommonTS.toHl7TSFormat(now)); 188 Terser.set(outbound, 10, 0, 1, 1, MessageIDGenerator.getInstance().getNewID()); 189 Terser.set(outbound, 11, 0, 1, 1, procID); 190 } 191 192 }