001/* 002 * Created on 3-May-2004 003 */ 004package ca.uhn.hl7v2.protocol.impl; 005 006import java.util.ArrayList; 007import java.util.HashMap; 008import java.util.List; 009import java.util.Map; 010 011import ca.uhn.hl7v2.HL7Exception; 012import ca.uhn.hl7v2.model.Message; 013import ca.uhn.hl7v2.parser.GenericParser; 014import ca.uhn.hl7v2.parser.Parser; 015import ca.uhn.hl7v2.protocol.Initiator; 016import ca.uhn.hl7v2.protocol.Processor; 017import ca.uhn.hl7v2.protocol.Transportable; 018import ca.uhn.hl7v2.util.Terser; 019 020/** 021 * Default implementation of <code>Initiator</code>. 022 * 023 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a> 024 * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:26 $ by $Author: jamesagnew $ 025 */ 026public class InitiatorImpl implements Initiator { 027 028 private final List<String> myMetadataFields; 029 private final Parser myParser; 030 private final Processor myProcessor; 031 private int myMaxRetries; 032 private long myRetryInterval; 033 private long myReceiveTimeout; 034 035 /** 036 * Creates an instance that uses a <code>GenericParser</code> 037 * @param theProcessor the <code>Processor</code> used to communicate 038 * with the remote system 039 */ 040 public InitiatorImpl(Processor theProcessor) { 041 myMetadataFields = new ArrayList<String>(20); 042 myMetadataFields.add("MSH-18"); //add character set by default 043 myParser = new GenericParser(); 044 myProcessor = theProcessor; 045 init(); 046 } 047 048 /** 049 * Creates an instance that uses the given <code>Parser</code> 050 * @param theParser parser to use for parsing and encoding messages 051 * @param theProcessor the <code>Processor</code> used to communicate 052 * with the remote system 053 */ 054 public InitiatorImpl(Parser theParser, Processor theProcessor) { 055 myMetadataFields = new ArrayList<String>(20); 056 myParser = theParser; 057 myProcessor = theProcessor; 058 init(); 059 } 060 061 private void init() { 062 myMaxRetries = 3; 063 myRetryInterval = 3000; 064 myReceiveTimeout = 10000; 065 } 066 067 068 /** 069 * @param theMaxRetries max number of retries for initial message delivery 070 */ 071 public void setMaxRetries(int theMaxRetries) { 072 myMaxRetries = theMaxRetries; 073 } 074 075 public int getMaxRetries() { 076 return myMaxRetries; 077 } 078 079 /** 080 * @param theRetryIntervalMillis milliseconds between retries of message delivery 081 */ 082 public void setRetryInterval(long theRetryIntervalMillis) { 083 myRetryInterval = theRetryIntervalMillis; 084 } 085 086 public long getRetryInterval() { 087 return myRetryInterval; 088 } 089 090 /** 091 * @param theReceiveTimeout the length of time we wait for responses (defaults 092 * to 10 seconds) 093 */ 094 public void setReceiveTimeout(long theReceiveTimeout) { 095 myReceiveTimeout = theReceiveTimeout; 096 } 097 098 public long getReceiveTimeout() { 099 return myReceiveTimeout; 100 } 101 102 /** 103 * @see ca.uhn.hl7v2.protocol.Initiator#sendAndReceive(ca.uhn.hl7v2.model.Message) 104 */ 105 public Message sendAndReceive(Message theMessage) throws HL7Exception { 106 Terser t = new Terser(theMessage); 107 String appAckNeeded = t.get("/MSH-16"); 108 String msgId = t.get("/MSH-10"); 109 110 String messageText = getParser().encode(theMessage); 111 Map<String, Object> metadata = getMetadata(theMessage); 112 Transportable out = new TransportableImpl(messageText, metadata); 113 114 if (needAck(appAckNeeded)) { 115 myProcessor.reserve(msgId, getReceiveTimeout()); 116 } 117 118 myProcessor.send(out, getMaxRetries(), getRetryInterval()); 119 120 Message in = null; 121 if (needAck(appAckNeeded)) { 122 Transportable received = myProcessor.receive(msgId, getReceiveTimeout()); 123 if (received != null && received.getMessage() != null) { 124 in = getParser().parse(received.getMessage()); 125 } 126 } 127 128 return in; 129 } 130 131 /** 132 * @param theAckCode from MSH-16 133 * @return true if the code indicates that we should wait for an ACK and try 134 * to return it to the caller 135 */ 136 private boolean needAck(String theAckCode) { 137 boolean need = false; 138 if (theAckCode == null 139 || theAckCode.equals("") 140 || theAckCode.equals(Processor.AL) 141 || theAckCode.equals(Processor.ER)) 142 { 143 need = true; 144 } 145 return need; 146 } 147 148 private Map<String, Object> getMetadata(Message theMessage) throws HL7Exception { 149 Map<String, Object> md = new HashMap<String, Object>(); 150 Terser t = new Terser(theMessage); 151 152 //snapshot so concurrent changes won't break our iteration 153 String[] fields = getMetadataFields().toArray(new String[0]); 154 155 for (int i = 0; i < fields.length; i++) { 156 String field = fields[i].toString(); 157 String val = t.get(field); 158 md.put(field, val); 159 } 160 161 return md; 162 } 163 164 /** 165 * @see ca.uhn.hl7v2.protocol.Initiator#getParser() 166 */ 167 public Parser getParser() { 168 return myParser; 169 } 170 171 /** 172 * @see ca.uhn.hl7v2.protocol.Initiator#getUnderlyingProcessor() 173 */ 174 public Processor getUnderlyingProcessor() { 175 return myProcessor; 176 } 177 178 /** 179 * @see ca.uhn.hl7v2.protocol.Initiator#getMetadataFields() 180 */ 181 public List<String> getMetadataFields() { 182 return myMetadataFields; 183 } 184 185 186}