001/** 002The contents of this file are subject to the Mozilla Public License Version 1.1 003(the "License"); you may not use this file except in compliance with the License. 004You may obtain a copy of the License at http://www.mozilla.org/MPL/ 005Software distributed under the License is distributed on an "AS IS" basis, 006WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 007specific language governing rights and limitations under the License. 008 009The Initial Developer of the Original Code is University Health Network. Copyright (C) 0102001. All Rights Reserved. 011 012Contributor(s): ______________________________________. 013 014Alternatively, the contents of this file may be used under the terms of the 015GNU General Public License (the "GPL"), in which case the provisions of the GPL are 016applicable instead of those above. If you wish to allow use of your version of this 017file only under the terms of the GPL and not to allow others to use your version 018of this file under the MPL, indicate your decision by deleting the provisions above 019and replace them with the notice and other provisions required by the GPL License. 020If you do not delete the provisions above, a recipient may use your version of 021this file under either the MPL or the GPL. 022*/ 023package ca.uhn.hl7v2.parser; 024 025import java.io.IOException; 026import java.io.InputStream; 027import java.util.Collections; 028import java.util.HashMap; 029import java.util.Map; 030import java.util.Properties; 031 032import ca.uhn.hl7v2.HL7Exception; 033import ca.uhn.hl7v2.Version; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037/** 038 * Abstract base class for {@link ModelClassFactory} implementations that read event maps from the 039 * file system. 040 * <p> 041 * The directory can be set using {@link #setEventMapDirectory(String)} and defaults to 042 * <code>ca/uhn/hl7v2/parser/eventmap/</code>. The file itself is a property file named after the 043 * HL7 version (e.g. <code>2.4.properties</code>). 044 * </p> 045 * 046 * 047 * @author Christian Ohr 048 */ 049@SuppressWarnings("serial") 050public abstract class AbstractModelClassFactory implements ModelClassFactory { 051 052 protected static final String DEFAULT_EVENT_MAP_DIRECTORY = "ca/uhn/hl7v2/parser/eventmap/"; 053 private static final Logger LOG = LoggerFactory.getLogger(AbstractModelClassFactory.class); 054 055 private String eventMapDirectory = DEFAULT_EVENT_MAP_DIRECTORY; 056 private Map<Version, Map<String, String>> eventMap; 057 058 059 /** 060 * @return the directory where to read the eventmap file from 061 */ 062 public String getEventMapDirectory() { 063 return eventMapDirectory; 064 } 065 066 /** 067 * @param eventMapPrefix the directory where to read the eventmap file from 068 */ 069 public void setEventMapDirectory(String eventMapPrefix) { 070 this.eventMapDirectory = eventMapPrefix; 071 } 072 073 /** 074 * @see ca.uhn.hl7v2.parser.ModelClassFactory#getMessageStructureForEvent(java.lang.String, 075 * ca.uhn.hl7v2.Version) 076 */ 077 public String getMessageStructureForEvent(String name, Version version) throws HL7Exception { 078 Map<String, String> p = getEventMapForVersion(version); 079 if (p == null) { 080 // Instead of throwing an Exception, Allow to parse as generic message if the structure library 081 // (and the contained event map) are not on the classpath. 082 LOG.debug("No event map found for version " + version); 083 return name; 084 // before: 085 // throw new HL7Exception("No map found for version " + version 086 // + ". Only the following are available: " + getEventMap().keySet()); 087 } else { 088 return p.get(name); 089 } 090 } 091 092 /** 093 * Returns the event map for a given HL7 version. In this map, the key is a message 094 * type and trigger event in the form <code>[type]_[trigger]</code>, for example: 095 * <code>ADT_A04</code>, and the values are the corresponding structure for this trigger, 096 * for example: <code>ADT_A01</code>. 097 * 098 * @param version the HL7 version 099 * @return Returns <code>null</code> if no event map is found for the given version 100 * @throws HL7Exception if the HL7 version is unknown 101 */ 102 public Map<String, String> getEventMapForVersion(Version version) throws HL7Exception { 103 return getEventMap().get(version); 104 } 105 106 /** 107 * Initializes the event map once and returns it. 108 * <p> 109 * This method is package private for testing reasons. 110 * 111 * @return the event map 112 * @throws HL7Exception 113 */ 114 synchronized Map<Version, Map<String, String>> getEventMap() throws HL7Exception { 115 if (eventMap == null) { 116 try { 117 eventMap = loadMessageStructures(); 118 } catch (IOException e) { 119 throw new HL7Exception("Could not load event map", e); 120 } 121 } 122 return eventMap; 123 } 124 125 /** 126 * Load event map from a external resource 127 * 128 * @return the event map 129 * @throws IOException 130 */ 131 protected Map<Version, Map<String, String>> loadMessageStructures() throws IOException { 132 Map<Version, Map<String, String>> map = new HashMap<Version, Map<String, String>>(); 133 for (Version v : Version.values()) { 134 String resource = getEventMapDirectory() + v.getVersion() + ".properties"; 135 InputStream in = getResource(resource); 136 if (in != null) { 137 try { 138 Properties structures = new Properties(); 139 structures.load(in); 140 141 Map<String, String> structureMap = new HashMap<String, String>(); 142 for(Map.Entry<Object, Object> next : structures.entrySet()) { 143 structureMap.put((String)next.getKey(), (String)next.getValue()); 144 } 145 146 map.put(v, Collections.unmodifiableMap(structureMap)); 147 } finally { 148 in.close(); 149 } 150 } 151 } 152 return map; 153 } 154 155 private InputStream getResource(String resource) { 156 InputStream in = null; 157 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 158 if (loader != null) { 159 in = loader.getResourceAsStream(resource); 160 } 161 if (in == null) { 162 loader = AbstractModelClassFactory.class.getClassLoader(); 163 if (loader != null) { 164 in = loader.getResourceAsStream(resource); 165 } 166 } 167 if (in == null) { 168 in = ClassLoader.getSystemResourceAsStream(resource); 169 } 170 return in; 171 } 172 173}