001    package ca.uhn.hl7v2.conf.store;
002    import java.io.IOException;
003    import ca.uhn.hl7v2.conf.ProfileException;
004    import ca.uhn.log.*;
005    import java.util.regex.*;
006    import java.util.StringTokenizer;
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     */
014    public abstract class AbstractCodeStore implements CodeStore {
015    
016            private static HapiLog log = HapiLogFactory.getHapiLog(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