View Javadoc

1   /*
2    * Created on 10-May-2004
3    */
4   package ca.uhn.hl7v2.protocol.impl;
5   
6   import java.io.IOException;
7   
8   import ca.uhn.hl7v2.HL7Exception;
9   import ca.uhn.hl7v2.app.DefaultApplication;
10  import ca.uhn.hl7v2.model.Message;
11  import ca.uhn.hl7v2.model.Segment;
12  import ca.uhn.hl7v2.parser.GenericParser;
13  import ca.uhn.hl7v2.parser.Parser;
14  import ca.uhn.hl7v2.protocol.AcceptValidator;
15  import ca.uhn.hl7v2.protocol.Processor;
16  import ca.uhn.hl7v2.protocol.ProcessorContext;
17  import ca.uhn.hl7v2.protocol.Transportable;
18  import ca.uhn.hl7v2.util.Terser;
19  import ca.uhn.log.HapiLog;
20  import ca.uhn.log.HapiLogFactory;
21  
22  /**
23   * Checks whether messages can be accepted and creates appropriate
24   * ACK messages.  
25   * 
26   * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
27   * @version $Revision: 1.2 $ updated on $Date: 2004/05/24 16:25:33 $ by $Author: bryan_tripp $
28   */
29  public class AcceptAcknowledger {
30  
31      private static final HapiLog log = HapiLogFactory.getHapiLog(AcceptAcknowledger.class);
32      
33      private static Parser ourParser = new GenericParser();
34      
35      /** 
36       * Validates the given message against our accept validators, attempts to commit
37       * the message to safe storage, and returns an ACK message indicating acceptance 
38       * or rejection at the accept level (see enhanced mode processing rules in HL7 
39       * chapter 2, v2.5).  
40       */
41      public static AcceptACK validate(ProcessorContext theContext, Transportable theMessage) throws HL7Exception {
42          AcceptACK ruling = null;
43          
44          AcceptValidator[] validators = theContext.getValidators();
45          for (int i = 0; i < validators.length && ruling == null; i++) {
46              AcceptValidator.AcceptRuling vr = validators[i].check(theMessage);            
47              if (!vr.isAcceptable()) {
48                  String description = (vr.getReasons().length > 0) ? vr.getReasons()[0] : null;
49                  Transportable ack = makeAcceptAck(theMessage, vr.getAckCode(), vr.getErrorCode(), description);
50                  ruling = new AcceptACK(false, ack);
51              }
52          }
53          
54          if (ruling == null) {
55              try {
56                  theContext.getSafeStorage().store(theMessage);
57                  Transportable ack = makeAcceptAck(theMessage, Processor.CA, HL7Exception.MESSAGE_ACCEPTED, "");
58                  ruling = new AcceptACK(true, ack);
59              } catch (HL7Exception e) {
60                  log.error(e);
61                  int code = HL7Exception.APPLICATION_INTERNAL_ERROR;
62                  Transportable ack = makeAcceptAck(theMessage, Processor.CR, code, e.getMessage());
63                  ruling = new AcceptACK(false, ack);
64              }
65          }        
66          
67          return ruling;
68      }
69  
70  
71      private static Transportable makeAcceptAck(Transportable theMessage, String theAckCode, int theErrorCode, String theDescription) throws HL7Exception {
72          
73          Segment header = ourParser.getCriticalResponseData(theMessage.getMessage());
74          Message out;
75          try {
76              out = DefaultApplication.makeACK(header);
77          } catch (IOException e) {
78              throw new HL7Exception(e);
79          }
80          
81          Terser t = new Terser(out);
82          t.set("/MSA-1", theAckCode);
83  
84          //TODO: when 2.5 is available, use 2.5 fields for remaining problems 
85          if (theErrorCode != HL7Exception.MESSAGE_ACCEPTED) {
86              t.set("/MSA-3", theDescription.substring(0, Math.min(80, theDescription.length())));            
87              t.set("/ERR-1-4-1", String.valueOf(theErrorCode));
88              t.set("/ERR-1-4-3", "HL70357");
89          }
90          
91          String originalEncoding = ourParser.getEncoding(theMessage.getMessage());
92          String ackText = ourParser.encode(out, originalEncoding);
93          return new TransportableImpl(ackText);
94      }    
95      
96      
97      /**
98       * A structure for decisions as to whether a message can be accepted, 
99       * along with a corresponding accept or reject acknowlegement message. 
100      *  
101      * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
102      * @version $Revision: 1.2 $ updated on $Date: 2004/05/24 16:25:33 $ by $Author: bryan_tripp $
103      */
104     public static class AcceptACK {
105         private Transportable myAck;
106         private boolean myIsAcceptable;
107         
108         public AcceptACK(boolean isAcceptable, Transportable theAck) {
109             myIsAcceptable = isAcceptable;
110             myAck = theAck;
111         }
112         
113         public boolean isAcceptable() {
114             return myIsAcceptable;
115         }
116         
117         public Transportable getMessage() {
118             return myAck;
119         }
120     }
121 
122 }