001/* 002 * Created on 10-May-2004 003 */ 004package ca.uhn.hl7v2.protocol.impl; 005 006import java.io.IOException; 007 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011import ca.uhn.hl7v2.AcknowledgmentCode; 012import ca.uhn.hl7v2.ErrorCode; 013import ca.uhn.hl7v2.HL7Exception; 014import ca.uhn.hl7v2.model.Message; 015import ca.uhn.hl7v2.model.Segment; 016import ca.uhn.hl7v2.parser.GenericParser; 017import ca.uhn.hl7v2.parser.Parser; 018import ca.uhn.hl7v2.protocol.AcceptValidator; 019import ca.uhn.hl7v2.protocol.Processor; 020import ca.uhn.hl7v2.protocol.ProcessorContext; 021import ca.uhn.hl7v2.protocol.Transportable; 022import ca.uhn.hl7v2.util.DeepCopy; 023 024/** 025 * Checks whether messages can be accepted and creates appropriate 026 * ACK messages. 027 * 028 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a> 029 * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:26 $ by $Author: jamesagnew $ 030 */ 031public class AcceptAcknowledger { 032 033 private static final Logger log = LoggerFactory.getLogger(AcceptAcknowledger.class); 034 035 private static Parser ourParser = new GenericParser(); 036 037 /** 038 * Validates the given message against our accept validators, attempts to commit 039 * the message to safe storage, and returns an ACK message indicating acceptance 040 * or rejection at the accept level (see enhanced mode processing rules in HL7 041 * chapter 2, v2.5). 042 */ 043 public static AcceptACK validate(ProcessorContext theContext, Transportable theMessage) throws HL7Exception { 044 AcceptACK ruling = null; 045 046 AcceptValidator[] validators = theContext.getValidators(); 047 for (int i = 0; i < validators.length && ruling == null; i++) { 048 AcceptValidator.AcceptRuling vr = validators[i].check(theMessage); 049 if (!vr.isAcceptable()) { 050 String description = (vr.getReasons().length > 0) ? vr.getReasons()[0] : null; 051 Transportable ack = makeAcceptAck(theMessage, vr.getAckCode(), ErrorCode.errorCodeFor(vr.getErrorCode()), description); 052 ruling = new AcceptACK(false, ack); 053 } 054 } 055 056 if (ruling == null) { 057 try { 058 theContext.getSafeStorage().store(theMessage); 059 Transportable ack = makeAcceptAck(theMessage, Processor.CA, ErrorCode.MESSAGE_ACCEPTED, ""); 060 ruling = new AcceptACK(true, ack); 061 } catch (HL7Exception e) { 062 log.error(e.getMessage(), e); 063 Transportable ack = makeAcceptAck(theMessage, Processor.CR, ErrorCode.APPLICATION_INTERNAL_ERROR, e.getMessage()); 064 ruling = new AcceptACK(false, ack); 065 } 066 } 067 068 return ruling; 069 } 070 071 072 private static Transportable makeAcceptAck(Transportable theMessage, String theAckCode, ErrorCode theErrorCode, String theDescription) throws HL7Exception { 073 Segment header = ourParser.getCriticalResponseData(theMessage.getMessage()); 074 Message dummy = header.getMessage(); 075 // MSH header refers to dummy, but not the other way round! 076 DeepCopy.copy(header, (Segment)dummy.get("MSH")); 077 078 try { 079 HL7Exception hl7e = new HL7Exception(theDescription, theErrorCode); 080 AcknowledgmentCode code = theAckCode == null ? 081 AcknowledgmentCode.CR : 082 AcknowledgmentCode.valueOf(theAckCode); 083 Message out = dummy.generateACK(code, hl7e); 084 String originalEncoding = ourParser.getEncoding(theMessage.getMessage()); 085 String ackText = ourParser.encode(out, originalEncoding); 086 return new TransportableImpl(ackText); 087 } catch (IOException e) { 088 throw new HL7Exception(e); 089 } 090 091 } 092 093 094 /** 095 * A structure for decisions as to whether a message can be accepted, 096 * along with a corresponding accept or reject acknowlegement message. 097 * 098 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a> 099 * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:26 $ by $Author: jamesagnew $ 100 */ 101 public static class AcceptACK { 102 private Transportable myAck; 103 private boolean myIsAcceptable; 104 105 public AcceptACK(boolean isAcceptable, Transportable theAck) { 106 myIsAcceptable = isAcceptable; 107 myAck = theAck; 108 } 109 110 public boolean isAcceptable() { 111 return myIsAcceptable; 112 } 113 114 public Transportable getMessage() { 115 return myAck; 116 } 117 } 118 119}