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    }