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 }