001 package ca.uhn.hl7v2.validation.app;
002
003 import org.apache.log4j.NDC;
004 import org.slf4j.LoggerFactory;
005
006 import ca.uhn.hl7v2.HL7Exception;
007 import ca.uhn.hl7v2.model.Message;
008 import ca.uhn.hl7v2.parser.PipeParser;
009 import ca.uhn.hl7v2.util.Terser;
010
011 /**
012 * An application intended for testing messages. The intended use is to route a copy
013 * of (selected) messages to a test application, which identifies and acts on problems independently
014 * of the normal error acknowledgement path (for example by notifying an administrator).
015 * This makes the most sense when used within an interface engine, for example if the
016 * sending nor receiving system use HAPI, but it is desired to route messages to HAPI in
017 * parallel so that they can be fully validated.
018 * @author Bryan Tripp
019 * @deprecated
020 */
021 public abstract class TestApplication implements ca.uhn.hl7v2.app.Application {
022
023 private PipeParser parser;
024
025 /** Creates a new instance of TestApplication */
026 public TestApplication() {
027 parser = new PipeParser();
028 }
029
030 /**
031 * Returns true if this Application wishes to accept the message. By returning
032 * true, this Application declares itself the recipient of the message, accepts
033 * responsibility for it, and must be able to respond appropriately to the sending system.
034 */
035 public abstract boolean canProcess(Message in);
036
037
038 /**
039 * <p>Calls test(Message in), routes resulting exceptions to configured destinations, and
040 * returns an ack (which should not normally be used since the test app is intended
041 * to operate in parallel with system-to-system communication). </p>
042 * <p>Notification routing is performed using log4j, so you need appropriate settings in a log4j
043 * config file (by default, ./log4j.properties). Different types of exceptions
044 * are all given the same severity (ERROR) but they have different loggers, based
045 * on the exception class name. Specifically, the loggers will be named
046 * ca.uhn.hl7v2.validation.error.{exception class name}. For example:
047 * "ca.uhn.hl7v2.validation.error.DataTypeException". Note that this allows default
048 * settings for all validation errors using the logger "ca.uhn.hl7v2.validation.error".
049 * The intent is for different exceptions to result in different actions, e.g. a
050 * ProfileNotHL7CompliantException should probably just be logged or ignored, while a
051 * ProfileNotFollowedException should probably be emailed to an administrator. </p>
052 */
053 public Message processMessage(Message in) throws HL7Exception {
054 String context = null;
055 try {
056 context = this.parser.encode(in);
057 } catch (HL7Exception e) {
058 context = "message not encodable";
059 }
060 //update logging context with message text
061 NDC.push(context);
062
063 LoggerFactory.getLogger("ca.uhn.hl7v2.validation.error").info("Testing message");
064
065 HL7Exception[] problems = test(in);
066 sendNotifications(problems);
067
068 NDC.pop();
069
070 Message ack = null;
071 try {
072 ack = ca.uhn.hl7v2.app.DefaultApplication.makeACK(in);
073 addProblemsToACK(ack, problems);
074 } catch (java.io.IOException e) {
075 throw new HL7Exception(e);
076 }
077 return ack;
078 }
079
080 /**
081 * <p>Send notification of problems to specified destinations (e.g. log file, email).
082 */
083 private void sendNotifications(HL7Exception[] problems) {
084 for (int i = 0; i < problems.length; i++) {
085 String exName = problems[i].getClass().getName();
086 String logName = "ca.uhn.hl7v2.validation.error" + exName.substring(exName.lastIndexOf('.'));
087 LoggerFactory.getLogger(logName).error("message validation failure", problems[i]);
088 }
089 }
090
091 private void addProblemsToACK(Message ack, HL7Exception[] problems) throws HL7Exception {
092 Terser t = new Terser(ack);
093
094 if (problems.length > 0) {
095 t.set("MSA-1", "AE");
096 t.set("MSA-3", "Errors were encountered while testing the message");
097 }
098 /*
099 Segment err = (Segment) ack.get("ERR");
100 for (int i = 0; i < problems.length; i++) {
101 // problems[i].populate(err); FIXME: broken! needs database
102 }
103 */
104 }
105
106 /**
107 * Tests the message in some way (as defined by implementing class).
108 * @return exceptions that describe any identified problems with the message
109 * @throws HL7Exception if the message can't be tested (not for errors disovered
110 * during testing)
111 */
112 public abstract HL7Exception[] test(Message in) throws HL7Exception;
113
114 }