001package ca.uhn.hl7v2.validation.app; 002 003import org.apache.log4j.NDC; 004import org.slf4j.LoggerFactory; 005 006import ca.uhn.hl7v2.HL7Exception; 007import ca.uhn.hl7v2.model.Message; 008import ca.uhn.hl7v2.parser.PipeParser; 009import 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 */ 021public 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}