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