Coverage Report - ca.uhn.hl7v2.util.FileCodeMapper
 
Classes in this File Line Coverage Branch Coverage Complexity
FileCodeMapper
0%
0/89
0%
0/32
3.889
FileCodeMapper$1
0%
0/5
0%
0/2
3.889
FileCodeMapper$2
0%
0/7
0%
0/6
3.889
 
 1  
 package ca.uhn.hl7v2.util;
 2  
 
 3  
 import java.io.BufferedReader;
 4  
 import java.io.File;
 5  
 import java.io.FileFilter;
 6  
 import java.io.FileReader;
 7  
 import java.io.FilenameFilter;
 8  
 import java.io.IOException;
 9  
 import java.util.HashMap;
 10  
 import java.util.Map;
 11  
 import java.util.StringTokenizer;
 12  
 
 13  
 import org.slf4j.Logger;
 14  
 import org.slf4j.LoggerFactory;
 15  
 
 16  
 import ca.uhn.hl7v2.ErrorCode;
 17  
 import ca.uhn.hl7v2.HL7Exception;
 18  
 
 19  
 /**
 20  
  * <p>Implements CodeMapper using files to store code values.  Files are arranged
 21  
  * in the following directory structure.  The base directory is called "codemap".
 22  
  * This should be created under the hapi.home directory (see Home class; defaults to .).
 23  
  * Under the base directory, there should be one directory for each interface, and
 24  
  * each of these directories should be named after the interface.  For example if you
 25  
  * had interfaces to pharmacy and lab systems you might have the following directories:</p>
 26  
  * <p> <hapi.home>/codemap/pharmacy<br>
 27  
  * <hapi.home>/codemap/lab</p>
 28  
  * <p>Each directory should contain two files per HL7 table, named after the table numbers as
 29  
  * follows: "hl7nnnn.li" and "hl7nnnn.il", where nnnn is the 4 digit table number.  The .il
 30  
  * file contains maps from interface codes to local codes, and the .li file contains maps from
 31  
  * local codes to interface codes (these unfortunately may not be symmetrical).</p>
 32  
  * <p>Each line of a file contains a single code map, with the "from" value and the "to" value
 33  
  * separated by a tab.  For example, the file <hapi.home>/lab/HL70001.li (to map local codes to interface
 34  
  * codes for the HL7 admnistrative sex table in your lab system interface) might contain the
 35  
  * following line: </p>
 36  
  * <p>male&tab;M</p>
 37  
  * <p>This means that the local code "male" maps to the interface code "M".</p>
 38  
  * <p>Lines that start with "//" are treated as comments.</p>
 39  
  * @author Bryan Tripp
 40  
  */
 41  
 public class FileCodeMapper extends CodeMapper {
 42  
 
 43  0
     private static final Logger log = LoggerFactory.getLogger(FileCodeMapper.class);
 44  
 
 45  0
     private boolean throwIfNoMatch = false;
 46  
     File baseDir;
 47  
     private Map<String, Map<String, Map<String, String>>> interfaceToLocal;
 48  
     private Map<String, Map<String, Map<String, String>>> localToInterface;
 49  
 
 50  
     /**
 51  
      * Creates a new instance of FileCodeMapper.  You should probably not
 52  
      * construct a FileCodeMapper directly.  Use CodeMapper.getInstance()
 53  
      * instead ... this will ensure that only a single instance is created,
 54  
      * which is important for performance because code maps are loaded from
 55  
      * disk every time this constructor is called.
 56  
      */
 57  0
     public FileCodeMapper() throws HL7Exception {
 58  0
         baseDir = new File(Home.getHomeDirectory().getAbsolutePath() + "/codemap");
 59  0
         refreshCache();
 60  0
     }
 61  
 
 62  
     /**
 63  
      * If values are cached in such a way that they are not guaranteed to be current, a call
 64  
      * to this method refreshes the values.
 65  
      */
 66  
     public void refreshCache() throws HL7Exception {
 67  0
         localToInterface = new HashMap<String, Map<String, Map<String, String>>>(10);
 68  0
         interfaceToLocal = new HashMap<String, Map<String, Map<String, String>>>(10);
 69  
 
 70  0
         log.info("Refreshing cache");
 71  
 
 72  
         try {
 73  
             //get list of child directories
 74  0
             File[] interfaceDirs = this.baseDir.listFiles(new FileFilter() {
 75  
                 public boolean accept(File pathname) {
 76  0
                     boolean acc = false;
 77  0
                     if (pathname.isDirectory())
 78  0
                         acc = true;
 79  0
                     return acc;
 80  
                 }
 81  
             });
 82  
 
 83  
             //loop through directories and set up maps
 84  0
             for (int i = 0; i < interfaceDirs.length; i++) {
 85  
 
 86  0
                 log.info(
 87  0
                     "Checking directory {} for interface code maps.", interfaceDirs[i].getName());
 88  
 
 89  
                 //get list of .li (local -> interface) and .il (interface -> local) files
 90  0
                 File[] mapFiles = interfaceDirs[i].listFiles(new FilenameFilter() {
 91  
                     public boolean accept(File dir, String name) {
 92  0
                         boolean acc = false;
 93  0
                         if (name.toUpperCase().startsWith("HL7")) {
 94  0
                             if (name.substring(name.lastIndexOf('.')).equals(".li")
 95  0
                                 || name.substring(name.lastIndexOf('.')).equals(".il"))
 96  0
                                 acc = true;
 97  
                         }
 98  0
                         return acc;
 99  
                     }
 100  
                 });
 101  
 
 102  
                 //read map entries from each file and add to hash maps for li and il codes
 103  0
                 HashMap<String, Map<String, String>> li = new HashMap<String, Map<String, String>>(50);
 104  0
                 HashMap<String, Map<String, String>> il = new HashMap<String, Map<String, String>>(50);
 105  0
                 for (int j = 0; j < mapFiles.length; j++) {
 106  0
                     log.info("Reading map entries from file {}", mapFiles[j]);
 107  
 
 108  0
                     String fName = mapFiles[j].getName();
 109  0
                     String tableName = fName.substring(0, fName.lastIndexOf('.'));
 110  0
                     String mapDirection = fName.substring(fName.lastIndexOf('.') + 1);
 111  
 
 112  
                     //read values and store in HashMap
 113  0
                         Map<String, String> codeMap = new HashMap<String, String>(25);
 114  0
                     BufferedReader in = null;
 115  
                     try {
 116  0
                                 in = new BufferedReader(new FileReader(mapFiles[j]));
 117  0
                                 while (in.ready()) {
 118  0
                                     String line = in.readLine();
 119  0
                                     if (!line.startsWith("//")) {
 120  0
                                         StringTokenizer tok = new StringTokenizer(line, "\t", false);
 121  0
                                         String from = null;
 122  0
                                         String to = null;
 123  0
                                         if (tok.hasMoreTokens())
 124  0
                                             from = tok.nextToken();
 125  0
                                         if (tok.hasMoreTokens())
 126  0
                                             to = tok.nextToken();
 127  0
                                         if (from != null && to != null)
 128  0
                                             codeMap.put(from, to);
 129  
                                     }
 130  0
                                 }
 131  
                     }
 132  
                     finally {
 133  0
                             if (in != null) in.close();
 134  
                     }
 135  
 
 136  
                     //add to appropriate map for this interface
 137  0
                     if (mapDirection.equals("il")) {
 138  0
                         il.put(tableName.toUpperCase(), codeMap);
 139  0
                         log.debug("Adding {} codes to interface -> local map for {} in {} interface",
 140  0
                                 new Object[] {codeMap.size(), tableName, interfaceDirs[i].getName()});
 141  
                     }
 142  
                     else {
 143  0
                         li.put(tableName.toUpperCase(), codeMap);
 144  0
                         log.debug("Adding {} codes to local -> interface map for {} in {} interface",
 145  0
                                 new Object[] {codeMap.size(), tableName, interfaceDirs[i].getName()});
 146  
                     }
 147  
                 }
 148  
 
 149  
                 //add maps for this interface (this directory) to global list
 150  0
                 interfaceToLocal.put(interfaceDirs[i].getName(), il);
 151  0
                 localToInterface.put(interfaceDirs[i].getName(), li);
 152  
             }
 153  
 
 154  
         }
 155  0
         catch (IOException e) {
 156  0
             throw new HL7Exception(
 157  
                 "Can't read interface code maps from disk", e);
 158  0
         }
 159  0
     }
 160  
 
 161  
     /**
 162  
      * Returns the local code for the given interface code as it appears in
 163  
      * the given interface.
 164  
      */
 165  
     public String getLocalCode(String interfaceName, int hl7Table, String interfaceCode) throws HL7Exception {
 166  0
         String localCode = null;
 167  
         try {
 168  0
             Map<String, Map<String, String>> interfaceMap = interfaceToLocal.get(interfaceName);
 169  0
             localCode = getCode(interfaceMap, hl7Table, interfaceCode);
 170  
         }
 171  0
         catch (NullPointerException npe) {
 172  0
             if (this.throwIfNoMatch)
 173  0
                 throw new HL7Exception(
 174  
                     "No local mapping for the interface code "
 175  
                         + interfaceCode
 176  
                         + " for HL7 table "
 177  
                         + hl7Table
 178  
                         + " for the interface '"
 179  
                         + interfaceName
 180  
                         + "'",
 181  
                     ErrorCode.TABLE_VALUE_NOT_FOUND);
 182  0
         }
 183  0
         return localCode;
 184  
     }
 185  
 
 186  
     /**
 187  
      * Common code for getLocalcode and getInterfaceCode
 188  
      */
 189  
     private String getCode(Map<String, Map<String, String>> interfaceMap, int hl7Table, String code) {
 190  0
         String ret = null;
 191  
 
 192  
         //get map for the given table
 193  0
         StringBuffer tableName = new StringBuffer();
 194  0
         tableName.append("HL7");
 195  0
         if (hl7Table < 1000)
 196  0
             tableName.append("0");
 197  0
         if (hl7Table < 100)
 198  0
             tableName.append("0");
 199  0
         if (hl7Table < 10)
 200  0
             tableName.append("0");
 201  0
         tableName.append(hl7Table);
 202  0
         Map<String, String> tableMap = interfaceMap.get(tableName.toString());
 203  
 
 204  
         //get code
 205  0
         ret = tableMap.get(code).toString();
 206  0
         return ret;
 207  
     }
 208  
 
 209  
     /**
 210  
      * Returns the interface code for the given local code, for use in the context
 211  
      * of the given interface.
 212  
      */
 213  
     public String getInterfaceCode(String interfaceName, int hl7Table, String localCode) throws HL7Exception {
 214  0
         String interfaceCode = null;
 215  
         try {
 216  0
             Map<String, Map<String, String>> interfaceMap = localToInterface.get(interfaceName);
 217  0
             interfaceCode = getCode(interfaceMap, hl7Table, localCode);
 218  
         }
 219  0
         catch (NullPointerException npe) {
 220  0
             if (this.throwIfNoMatch)
 221  0
                 throw new HL7Exception(
 222  
                     "No interface mapping for the local code "
 223  
                         + localCode
 224  
                         + " for HL7 table "
 225  
                         + hl7Table
 226  
                         + " for the interface '"
 227  
                         + interfaceName
 228  
                         + "'",
 229  
                     ErrorCode.TABLE_VALUE_NOT_FOUND);
 230  0
         }
 231  0
         return interfaceCode;
 232  
     }
 233  
 
 234  
     /**
 235  
      * Determines what happens if no matching code is found during a lookup.  If set to true,
 236  
      * an HL7Exception is thrown if there is no match.  If false, null is returned.  The default
 237  
      * is false.
 238  
      */
 239  
     public void throwExceptionIfNoMatch(boolean throwException) {
 240  0
         this.throwIfNoMatch = throwException;
 241  0
     }
 242  
 
 243  
     /**
 244  
      * Test harness.
 245  
      */
 246  
     public static void main(String args[]) {
 247  
         try {
 248  
             //FileCodeMapper mapper = new FileCodeMapper();
 249  0
             CodeMapper.getInstance().throwExceptionIfNoMatch(true);
 250  0
             System.out.println("Local code for M is " + CodeMapper.getLocal("test", 1, "M"));
 251  0
             System.out.println("Interface code for female is " + CodeMapper.getInt("test", 1, "female"));
 252  
 
 253  
         }
 254  0
         catch (HL7Exception e) {
 255  0
             e.printStackTrace();
 256  0
         }
 257  0
     }
 258  
 
 259  
 }