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 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(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(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 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 getMetadata(Message theMessage) throws HL7Exception {
149            Map md = new HashMap();
150            Terser t = new Terser(theMessage);
151    
152            //snapshot so concurrent changes won't break our iteration
153            Object[] fields = getMetadataFields().toArray(new Object[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 getMetadataFields() {
182            return myMetadataFields;
183        }
184    
185    
186    }