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.*;
030
031import ca.uhn.hl7v2.model.GenericMessage;
032import ca.uhn.hl7v2.parser.ModelClassFactory;
033import ca.uhn.hl7v2.parser.Parser;
034
035public enum Version {
036
037        V21("2.1"), // -
038        V22("2.2"), // -
039        V23("2.3"), // -
040        V231("2.3.1"), // -
041        V24("2.4"), // -
042        V25("2.5"), // -
043        V251("2.5.1"), // -
044        V26("2.6"), // -
045        V27("2.7"), // -
046        V271("2.7.1"), // -
047        V28("2.8"), // -
048        V281("2.8.1"); // -
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        Set<Version> versions = new HashSet<Version>(Arrays.asList(Version.values()));
128        for (Version version : v) {
129            versions.remove(version);
130        }
131        return versions.toArray(new Version[versions.size()]);
132    }
133
134        public static Version[] before(Version v) {
135                List<Version> versions = new ArrayList<Version>();
136                for (Version version : Version.values()) {
137                        if (version.compareTo(v) < 0)
138                                versions.add(version);
139                }
140                return versions.toArray(new Version[versions.size()]);
141        }
142
143        public String modelPackageName() {
144        String classname = getClass().getName();
145        String p = classname.substring(0, classname.lastIndexOf("."));
146                return String
147                                .format("%s.model.%s.", p, getPackageVersion());
148        }
149
150        /**
151         * Returns <code>true</code> if the structure
152         * classes for this particular version are available
153         * on the classpath.
154         */
155        public synchronized boolean available() {
156                Boolean retVal = ourIsOnClasspath.get(this);
157                if (retVal == null) {
158                        String resource = "ca/uhn/hl7v2/parser/eventmap/" + getVersion() + ".properties";
159            InputStream in = Parser.class.getClassLoader().getResourceAsStream(resource);
160            try {
161                            retVal = in != null;
162                            ourIsOnClasspath.put(this, retVal);
163            } finally {
164                if (in != null) {
165                    try {
166                        in.close();
167                    } catch (Exception e) {
168                        // Ignore
169                    }
170                }
171            }
172                }
173                return retVal;
174        }
175        
176        /**
177         * Returns a list of all versions for which the structure JARs have been
178         * found on the classpath.
179         */
180        public static synchronized List<Version> availableVersions() {
181                if (ourVersionsOnClasspath == null) {
182                        ourVersionsOnClasspath = new ArrayList<Version>();
183                        for (Version next : values()) {
184                                if (next.available()) {
185                                        ourVersionsOnClasspath.add(next);
186                                }
187                        }
188                }
189                return ourVersionsOnClasspath;
190        }
191        
192        /**
193         * <p>
194         * Returns the lowest version for which the structure classes are found
195         * on the classes. For instance, if <code>hapi-structures-v24-[version].jar</code>
196         * is the only structure JAR on the current JVM classpath, {@link Version#V24} will
197         * be returned.
198         * <p>
199         * <p>
200         * Returns <code>null</code> if none are found
201         * </p>
202         */
203        public static Version lowestAvailableVersion() {
204                List<Version> availableVersions = availableVersions();
205                if (availableVersions.size() >0) {
206                        return availableVersions.get(0);
207                } else {
208                        return null;
209                }
210        }
211
212        /**
213         * <p>
214         * Returns the highest version for which the structure classes are found
215         * on the classes. For instance, if <code>hapi-structures-v24-[version].jar</code>
216         * is the only structure JAR on the current JVM classpath, {@link Version#V24} will
217         * be returned.
218         * <p>
219         * </>
220         * If no structure JARs at all are found, returns a default value of
221         * {@link Version#V25}
222         * </p>
223         */
224        public static Version highestAvailableVersionOrDefault() {
225                List<Version> availableVersions = availableVersions();
226                if (availableVersions.size() >0) {
227                        return availableVersions.get(availableVersions.size() - 1);
228                } else {
229                        return Version.V25;
230                }
231        }
232
233        /**
234         * Construct and return a new {@link GenericMessage} for the given version
235         */
236        public GenericMessage newGenericMessage(ModelClassFactory mcf) {
237                switch (this) {
238                case V21:
239                        return new GenericMessage.V21(mcf);
240                case V22:
241                        return new GenericMessage.V22(mcf);
242                case V23:
243                        return new GenericMessage.V23(mcf);
244                case V231:
245                        return new GenericMessage.V231(mcf);
246                case V24:
247                        return new GenericMessage.V24(mcf);
248                case V25:
249                        return new GenericMessage.V25(mcf);
250                case V251:
251                        return new GenericMessage.V251(mcf);
252                case V26:
253                        return new GenericMessage.V26(mcf);
254                case V27:
255                        return new GenericMessage.V27(mcf);
256                case V271:
257                        return new GenericMessage.V271(mcf);
258                case V28:
259                        return new GenericMessage.V28(mcf);
260                case V281:
261                        return new GenericMessage.V281(mcf);
262                default:
263                        throw new Error("Unknown version (this is a HAPI bug): " + this.getVersion());
264                }
265        }
266        
267}