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;
034
035/**
036 * Abstract base class for {@link ModelClassFactory} implementations that read event maps from the
037 * file system.
038 * <p>
039 * The directory can be set using {@link #setEventMapDirectory(String)} and defaults to
040 * <code>ca/uhn/hl7v2/parser/eventmap/</code>. The file itself is a property file named after the
041 * HL7 version (e.g. <code>2.4.properties</code>).
042 * </p>
043 * 
044 * 
045 * @author Christian Ohr
046 */
047@SuppressWarnings("serial")
048public abstract class AbstractModelClassFactory implements ModelClassFactory {
049
050        protected static final String DEFAULT_EVENT_MAP_DIRECTORY = "ca/uhn/hl7v2/parser/eventmap/";
051
052        private String eventMapDirectory = DEFAULT_EVENT_MAP_DIRECTORY;
053        private Map<Version, Map<String, String>> eventMap;
054
055        /**
056         * @return the directory where to read the eventmap file from
057         */
058        public String getEventMapDirectory() {
059                return eventMapDirectory;
060        }
061
062        /**
063         * @param eventMapPrefix the directory where to read the eventmap file from
064         */
065        public void setEventMapDirectory(String eventMapPrefix) {
066                this.eventMapDirectory = eventMapPrefix;
067        }
068
069        /**
070         * @see ca.uhn.hl7v2.parser.ModelClassFactory#getMessageStructureForEvent(java.lang.String,
071         *      ca.uhn.hl7v2.Version)
072         */
073        public String getMessageStructureForEvent(String name, Version version) throws HL7Exception {
074                Map<String, String> p = getEventMapForVersion(version);
075                if (p == null)
076                        throw new HL7Exception("No map found for version " + version
077                                        + ". Only the following are available: " + getEventMap().keySet());
078                return p.get(name);
079        }
080
081        /**
082         * Returns the event map for a given HL7 version. In this map, the key is a message
083         * type and trigger event in the form <code>[type]_[trigger]</code>, for example:
084         * <code>ADT_A04</code>, and the values are the corresponding structure for this trigger,
085         * for example: <code>ADT_A01</code>.
086         *
087     * @param version the HL7 version
088         * @return Returns <code>null</code> if no event map is found for the given version
089     * @throws HL7Exception if the HL7 version is unknown
090         */
091        public Map<String, String> getEventMapForVersion(Version version) throws HL7Exception {
092                return getEventMap().get(version);
093        }
094
095        /**
096         * Initializes the event map once and returns it.
097         * <p>
098         * This method is package private for testing reasons.
099         *  
100         * @return the event map
101         * @throws HL7Exception
102         */
103        synchronized Map<Version, Map<String, String>> getEventMap() throws HL7Exception {
104                if (eventMap == null) {
105                        try {
106                                eventMap = loadMessageStructures();
107                        } catch (IOException e) {
108                                throw new HL7Exception("Could not load event map", e);
109                        }
110                }
111                return eventMap;
112        }
113
114        /**
115         * Load event map from a external resource
116         * 
117         * @return the event map
118         * @throws IOException
119         */
120        protected Map<Version, Map<String, String>> loadMessageStructures() throws IOException {
121                Map<Version, Map<String, String>> map = new HashMap<Version, Map<String, String>>();
122                for (Version v : Version.values()) {
123                        String resource = getEventMapDirectory() + v.getVersion() + ".properties";
124                        InputStream in = getResource(resource);
125                        if (in != null) {
126                                try {
127                                        Properties structures = new Properties();
128                                        structures.load(in);
129                                        
130                                        Map<String, String> structureMap = new HashMap<String, String>();
131                                        for(Map.Entry<Object, Object> next : structures.entrySet()) {
132                                                structureMap.put((String)next.getKey(), (String)next.getValue());
133                                        }
134                                        
135                                        map.put(v, Collections.unmodifiableMap(structureMap));
136                                } finally {
137                                        in.close();
138                                }
139                        }
140                }
141                return map;
142        }
143
144        private InputStream getResource(String resource) {
145                InputStream in = null;
146                ClassLoader loader = Thread.currentThread().getContextClassLoader();
147                if (loader != null) {
148                        in = loader.getResourceAsStream(resource);
149                }
150                if (in == null) {
151                        loader = AbstractModelClassFactory.class.getClassLoader();
152                        if (loader != null) {
153                                in = loader.getResourceAsStream(resource);
154                        }
155                }
156                if (in == null) {
157                        in = ClassLoader.getSystemResourceAsStream(resource);
158                }
159                return in;
160        }
161
162}