View Javadoc
1   /**
2   The contents of this file are subject to the Mozilla Public License Version 1.1
3   (the "License"); you may not use this file except in compliance with the License.
4   You may obtain a copy of the License at http://www.mozilla.org/MPL/
5   Software distributed under the License is distributed on an "AS IS" basis,
6   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
7   specific language governing rights and limitations under the License.
8   
9   The Initial Developer of the Original Code is University Health Network. Copyright (C)
10  2001.  All Rights Reserved.
11  
12  Contributor(s): ______________________________________.
13  
14  Alternatively, the contents of this file may be used under the terms of the
15  GNU General Public License (the  "GPL"), in which case the provisions of the GPL are
16  applicable instead of those above.  If you wish to allow use of your version of this
17  file only under the terms of the GPL and not to allow others to use your version
18  of this file under the MPL, indicate your decision by deleting  the provisions above
19  and replace  them with the notice and other provisions required by the GPL License.
20  If you do not delete the provisions above, a recipient may use your version of
21  this file under either the MPL or the GPL.
22  */
23  package ca.uhn.hl7v2.parser;
24  
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.Map;
30  import java.util.Properties;
31  
32  import ca.uhn.hl7v2.HL7Exception;
33  import ca.uhn.hl7v2.Version;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  /**
38   * Abstract base class for {@link ModelClassFactory} implementations that read event maps from the
39   * file system.
40   * <p>
41   * The directory can be set using {@link #setEventMapDirectory(String)} and defaults to
42   * <code>ca/uhn/hl7v2/parser/eventmap/</code>. The file itself is a property file named after the
43   * HL7 version (e.g. <code>2.4.properties</code>).
44   * </p>
45   * 
46   * 
47   * @author Christian Ohr
48   */
49  @SuppressWarnings("serial")
50  public abstract class AbstractModelClassFactory implements ModelClassFactory {
51  
52  	protected static final String DEFAULT_EVENT_MAP_DIRECTORY = "ca/uhn/hl7v2/parser/eventmap/";
53  	private static final Logger LOG = LoggerFactory.getLogger(AbstractModelClassFactory.class);
54  
55  	private String eventMapDirectory = DEFAULT_EVENT_MAP_DIRECTORY;
56  	private Map<Version, Map<String, String>> eventMap;
57  
58  
59  	/**
60  	 * @return the directory where to read the eventmap file from
61  	 */
62  	public String getEventMapDirectory() {
63  		return eventMapDirectory;
64  	}
65  
66  	/**
67  	 * @param eventMapPrefix the directory where to read the eventmap file from
68  	 */
69  	public void setEventMapDirectory(String eventMapPrefix) {
70  		this.eventMapDirectory = eventMapPrefix;
71  	}
72  
73  	/**
74  	 * @see ca.uhn.hl7v2.parser.ModelClassFactory#getMessageStructureForEvent(java.lang.String,
75  	 *      ca.uhn.hl7v2.Version)
76  	 */
77  	public String getMessageStructureForEvent(String name, Version version) throws HL7Exception {
78  		Map<String, String> p = getEventMapForVersion(version);
79  		if (p == null) {
80  			// Instead of throwing an Exception, Allow to parse as generic message if the structure library
81  			// (and the contained event map) are not on the classpath.
82  			LOG.debug("No event map found for version " + version);
83  			return name;
84  			// before:
85  			// throw new HL7Exception("No map found for version " + version
86  			//		+ ". Only the following are available: " + getEventMap().keySet());
87  		} else {
88  			return p.get(name);
89  		}
90  	}
91  
92  	/**
93  	 * Returns the event map for a given HL7 version. In this map, the key is a message
94  	 * type and trigger event in the form <code>[type]_[trigger]</code>, for example:
95  	 * <code>ADT_A04</code>, and the values are the corresponding structure for this trigger,
96  	 * for example: <code>ADT_A01</code>.
97  	 *
98       * @param version the HL7 version
99  	 * @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<>();
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<>();
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 }