001 /*
002 * Created on 3-May-2004
003 */
004 package ca.uhn.hl7v2.protocol.impl;
005
006 import java.util.ArrayList;
007 import java.util.HashMap;
008 import java.util.List;
009 import java.util.Map;
010
011 import ca.uhn.hl7v2.HL7Exception;
012 import ca.uhn.hl7v2.model.Message;
013 import ca.uhn.hl7v2.parser.GenericParser;
014 import ca.uhn.hl7v2.parser.Parser;
015 import ca.uhn.hl7v2.protocol.Initiator;
016 import ca.uhn.hl7v2.protocol.Processor;
017 import ca.uhn.hl7v2.protocol.Transportable;
018 import 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 */
026 public 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 }