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 Original Code is "Version.java".  Description: 
010"An enumeration of supported HL7 versions" 
011
012The Initial Developer of the Original Code is University Health Network. Copyright (C) 
0132012.  All Rights Reserved. 
014
015Contributor(s): ______________________________________. 
016
017Alternatively, the contents of this file may be used under the terms of the 
018GNU General Public License (the  "GPL"), in which case the provisions of the GPL are 
019applicable instead of those above.  If you wish to allow use of your version of this 
020file only under the terms of the GPL and not to allow others to use your version 
021of this file under the MPL, indicate your decision by deleting  the provisions above 
022and replace  them with the notice and other provisions required by the GPL License.  
023If you do not delete the provisions above, a recipient may use your version of 
024this file under either the MPL or the GPL. 
025 */
026package ca.uhn.hl7v2;
027
028import java.io.InputStream;
029import java.util.ArrayList;
030import java.util.HashMap;
031import java.util.List;
032import java.util.Map;
033import java.util.Set;
034
035import ca.uhn.hl7v2.model.GenericMessage;
036import ca.uhn.hl7v2.parser.ModelClassFactory;
037import ca.uhn.hl7v2.parser.Parser;
038
039public enum Version {
040
041        V21("2.1"), // -
042        V22("2.2"), // -
043        V23("2.3"), // -
044        V231("2.3.1"), // -
045        V24("2.4"), // -
046        V25("2.5"), // -
047        V251("2.5.1"), // -
048        V26("2.6"); // -
049
050        private String version;
051        private static ArrayList<Version> ourVersionsOnClasspath;
052        private static final Map<Version, Boolean> ourIsOnClasspath = new HashMap<Version, Boolean>();
053
054        Version(String version) {
055                this.version = version;
056        }
057
058        /**
059         * Returns a version string (e.g. "2.1", or "2.5.1")
060         */
061        public String getVersion() {
062                return version;
063        }
064
065        public String getPackageVersion() {
066                return "v" + version.replace(".", "");
067        }
068
069        /**
070         * Returns <code>true</code> if theVersion is a valid HL7
071         * version string representing a known version, e.g. "2.4", "2.6"
072         */
073        public static boolean supportsVersion(String theVersion) {
074                return versionOf(theVersion) != null;
075        }
076
077        /**
078         * @param version The version string, e.g. "2.1" or "2.6"
079         */
080        public static Version versionOf(String version) {
081                for (Version v : Version.values()) {
082                        if (v.getVersion().equals(version)) {
083                                return v;
084                        }
085                }
086                return null;
087        }
088
089        /**
090         * @param someVersions set of versions to be tested
091         * @return <code>true</code> if someVersions contain all supported HL7 versions
092         */
093        public static boolean allVersions(Set<Version> someVersions) {
094                return someVersions != null && someVersions.size() == values().length;
095        }
096
097        /**
098         * Returns true if this version is greater than the specified version
099         */
100        public boolean isGreaterThan(Version theVersion) {
101                return compareTo(theVersion) > 0;
102        }
103
104        /**
105         * Returns the newest available version of the message structure classes
106         * on the classpath, or <code>null</code> if none are found
107         */
108        public static Version latestVersion() {
109                Version[] versions = Version.values();
110                if (versions.length > 0) {
111                        return versions[versions.length - 1];
112                } else {
113                        return null;
114                }
115        }
116
117        public static Version[] asOf(Version v) {
118                List<Version> versions = new ArrayList<Version>();
119                for (Version version : Version.values()) {
120                        if (version.compareTo(v) >= 0)
121                                versions.add(version);
122                }
123                return versions.toArray(new Version[versions.size()]);
124        }
125
126        public static Version[] except(Version v) {
127                List<Version> versions = new ArrayList<Version>();
128                for (Version version : Version.values()) {
129                        if (version.compareTo(v) != 0)
130                                versions.add(version);
131                }
132                return versions.toArray(new Version[versions.size()]);
133        }
134
135        public static Version[] before(Version v) {
136                List<Version> versions = new ArrayList<Version>();
137                for (Version version : Version.values()) {
138                        if (version.compareTo(v) < 0)
139                                versions.add(version);
140                }
141                return versions.toArray(new Version[versions.size()]);
142        }
143
144        public String modelPackageName() {
145        String classname = getClass().getName();
146        String p = classname.substring(0, classname.lastIndexOf("."));
147                return String
148                                .format("%s.model.%s.", p, getPackageVersion());
149        }
150
151        /**
152         * Returns <code>true</code> if the structure
153         * classes for this particular version are available
154         * on the classpath.
155         */
156        public synchronized boolean available() {
157                Boolean retVal = ourIsOnClasspath.get(this);
158                if (retVal == null) {
159                        String resource = "ca/uhn/hl7v2/parser/eventmap/" + getVersion() + ".properties";
160            InputStream in = Parser.class.getClassLoader().getResourceAsStream(resource);
161            try {
162                            retVal = in != null;
163                            ourIsOnClasspath.put(this, retVal);
164            } finally {
165                if (in != null) {
166                    try {
167                        in.close();
168                    } catch (Exception e) {
169                        // Ignore
170                    }
171                }
172            }
173                }
174                return retVal;
175        }
176        
177        /**
178         * Returns a list of all versions for which the structure JARs have been
179         * found on the classpath.
180         */
181        public static synchronized List<Version> availableVersions() {
182                if (ourVersionsOnClasspath == null) {
183                        ourVersionsOnClasspath = new ArrayList<Version>();
184                        for (Version next : values()) {
185                                if (next.available()) {
186                                        ourVersionsOnClasspath.add(next);
187                                }
188                        }
189                }
190                return ourVersionsOnClasspath;
191        }
192        
193        /**
194         * <p>
195         * Returns the lowest version for which the structure classes are found
196         * on the classes. For instance, if <code>hapi-structures-v24-[version].jar</code>
197         * is the only structure JAR on the current JVM classpath, {@link Version#V24} will
198         * be returned.
199         * <p>
200         * <p>
201         * Returns <code>null</code> if none are found
202         * </p>
203         */
204        public static Version lowestAvailableVersion() {
205                List<Version> availableVersions = availableVersions();
206                if (availableVersions.size() >0) {
207                        return availableVersions.get(0);
208                } else {
209                        return null;
210                }
211        }
212
213        /**
214         * <p>
215         * Returns the highest version for which the structure classes are found
216         * on the classes. For instance, if <code>hapi-structures-v24-[version].jar</code>
217         * is the only structure JAR on the current JVM classpath, {@link Version#V24} will
218         * be returned.
219         * <p>
220         * </>
221         * If no structure JARs at all are found, returns a default value of
222         * {@link Version#V25}
223         * </p>
224         */
225        public static Version highestAvailableVersionOrDefault() {
226                List<Version> availableVersions = availableVersions();
227                if (availableVersions.size() >0) {
228                        return availableVersions.get(availableVersions.size() - 1);
229                } else {
230                        return Version.V25;
231                }
232        }
233
234        /**
235         * Construct and return a new {@link GenericMessage} for the given version
236         */
237        public GenericMessage newGenericMessage(ModelClassFactory mcf) {
238                switch (this) {
239                case V21:
240                        return new GenericMessage.V21(mcf);
241                case V22:
242                        return new GenericMessage.V22(mcf);
243                case V23:
244                        return new GenericMessage.V23(mcf);
245                case V231:
246                        return new GenericMessage.V231(mcf);
247                case V24:
248                        return new GenericMessage.V24(mcf);
249                case V25:
250                        return new GenericMessage.V25(mcf);
251                case V251:
252                        return new GenericMessage.V251(mcf);
253                case V26:
254                        return new GenericMessage.V26(mcf);
255                default:
256                        throw new Error("Unknown version (this is a HAPI bug): " + this.getVersion());
257                }
258        }
259        
260}