001package ca.uhn.hl7v2.conf.store;
002import java.util.StringTokenizer;
003import java.util.regex.Pattern;
004
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Created on 27-Aug-2003
010 * @author Neal Acharya
011 * Abstract class for used retreiving and validating codes from user defined and HL7 specific tables
012 * that correspond to a conformance profile.
013 */
014public abstract class AbstractCodeStore implements CodeStore {
015
016        private static Logger log = LoggerFactory.getLogger(AbstractCodeStore.class);
017        private WildcardPattern[] wildcards;
018
019        /**
020         * @param codeSystem
021         * @param code
022         * @return boolean
023         * @see ca.uhn.hl7v2.conf.store.CodeStore#isValidCode(java.lang.String, java.lang.String, java.lang.String)
024         *
025         * Validates the input code value against the input conformance profile and corresponding input
026         * codeSystem. Returns true if the code is valid and false if it isn't.
027         */
028        public boolean isValidCode(String codeSystem, String code) {
029                try {
030                        String[] validCodes = getValidCodes(codeSystem);
031                        boolean found = false;
032                        for (int i = 0; i < validCodes.length && !found; i++) {
033                                if (checkCode(code, validCodes[i])) {
034                                        found = true;
035                                } //end if
036                        } //end for
037                        return found;
038                } //end try
039                catch (Exception e) {
040                        log.error("Error checking code " + code + " in code system " + codeSystem, e);
041                        return false;
042                } //end catch
043        } //end method
044
045        /**
046         * Checks a code for an exact match, and using certain sequences where some 
047         * characters are wildcards (e.g. HL7nnnn).  If the pattern contains one of 
048         * " or ", " OR ", or "," each operand is checked.
049         */
050        private boolean checkCode(String code, String pattern) {
051                boolean match = false;
052                //mod by Neal acharya - Do full match on with the pattern.  If code matches pattern then return true
053        //else parse pattern to look for wildcard characters
054                if (code.equals(pattern)) {
055                        match = true;
056                } //end if 
057                else {
058                        if (pattern.indexOf(' ') >= 0 || pattern.indexOf(',') >= 0) {
059                                StringTokenizer tok = new StringTokenizer(pattern, ", ", false);
060                                while (tok.hasMoreTokens() && !match) {
061                                        String t = tok.nextToken();
062                                        if (!t.equalsIgnoreCase("or"))
063                                                match = checkCode(code, t);
064                                }//end while
065                        }//end if
066                        else {
067                                if (code.equals(pattern)) {
068                                        match = true;
069                                }//end if
070                                else {
071                                        WildcardPattern[] wc = getWildcards();
072                                        for (int i = 0; i < wc.length && !match; i++) {
073                                                if (pattern.equals(wc[i].pattern))
074                                                        match = wc[i].regex.matcher(code).matches();
075                                        }//end for
076                                }//end else
077                        }//end else
078                } //end else 
079                return match;
080        }//end method
081
082        /** Returns a list of wildcard-containing patterns and corresponding regular expressions */
083        private synchronized WildcardPattern[] getWildcards() {
084                if (wildcards == null) {
085                        wildcards = new WildcardPattern[4];
086                        wildcards[0] = new WildcardPattern("ISOnnnn", "ISO\\d\\d\\d\\d");
087                        wildcards[1] = new WildcardPattern("HL7nnnn", "HL7\\d\\d\\d\\d");
088                        wildcards[2] = new WildcardPattern("99zzz", "99[\\w]*");
089                        wildcards[3] = new WildcardPattern("NNxxx", "99[\\w]*");
090                }
091                return wildcards;
092        }
093
094        /** A struct of a wildcard-containing code pattern and corresponding regex */
095        private static class WildcardPattern {
096                public String pattern;
097                public Pattern regex;
098                public WildcardPattern(String p, String r) {
099                        pattern = p;
100                        regex = Pattern.compile(r);
101                }
102        }
103
104} //end class