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.IOException;
029import java.io.InputStream;
030import java.util.*;
031
032import ca.uhn.hl7v2.model.GenericMessage;
033import ca.uhn.hl7v2.parser.ModelClassFactory;
034import ca.uhn.hl7v2.parser.Parser;
035
036public enum Version {
037
038        V21("2.1"), // -
039        V22("2.2"), // -
040        V23("2.3"), // -
041        V231("2.3.1"), // -
042        V24("2.4"), // -
043        V25("2.5"), // -
044        V251("2.5.1"), // -
045        V26("2.6"), // -
046        V27("2.7"), // -
047        V271("2.7.1"), // -
048        V28("2.8"), // -
049        V281("2.8.1"); // -
050
051        private final String version;
052        private static ArrayList<Version> ourVersionsOnClasspath;
053        private static final Map<Version, Boolean> ourIsOnClasspath = new HashMap<>();
054
055        Version(String version) {
056                this.version = version;
057        }
058
059        /**
060         * Returns a version string (e.g. "2.1", or "2.5.1")
061         */
062        public String getVersion() {
063                return version;
064        }
065
066        public String getPackageVersion() {
067                return "v" + version.replace(".", "");
068        }
069
070        /**
071         * Returns <code>true</code> if theVersion is a valid HL7
072         * version string representing a known version, e.g. "2.4", "2.6"
073         */
074        public static boolean supportsVersion(String theVersion) {
075                return versionOf(theVersion) != null;
076        }
077
078        /**
079         * @param version The version string, e.g. "2.1" or "2.6"
080         */
081        public static Version versionOf(String version) {
082                for (Version v : Version.values()) {
083                        if (v.getVersion().equals(version)) {
084                                return v;
085                        }
086                }
087                return null;
088        }
089
090        /**
091         * @param someVersions set of versions to be tested
092         * @return <code>true</code> if someVersions contain all supported HL7 versions
093         */
094        public static boolean allVersions(Set<Version> someVersions) {
095                return someVersions != null && someVersions.size() == values().length;
096        }
097
098        /**
099         * Returns true if this version is greater than the specified version
100         */
101        public boolean isGreaterThan(Version theVersion) {
102                return compareTo(theVersion) > 0;
103        }
104
105        /**
106         * Returns the newest available version of the message structure classes
107         * on the classpath, or <code>null</code> if none are found
108         */
109        public static Version latestVersion() {
110                Version[] versions = Version.values();
111                if (versions.length > 0) {
112                        return versions[versions.length - 1];
113                } else {
114                        return null;
115                }
116        }
117
118        public static Version[] asOf(Version v) {
119                List<Version> versions = new ArrayList<>();
120                for (Version version : Version.values()) {
121                        if (version.compareTo(v) >= 0)
122                                versions.add(version);
123                }
124                return versions.toArray(new Version[0]);
125        }
126
127    public static Version[] except(Version... v) {
128        Set<Version> versions = new HashSet<>(Arrays.asList(Version.values()));
129        for (Version version : v) {
130            versions.remove(version);
131        }
132        return versions.toArray(new Version[0]);
133    }
134
135        public static Version[] before(Version v) {
136                List<Version> versions = new ArrayList<>();
137                for (Version version : Version.values()) {
138                        if (version.compareTo(v) < 0)
139                                versions.add(version);
140                }
141                return versions.toArray(new Version[0]);
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                        try (InputStream in = Parser.class.getClassLoader().getResourceAsStream(resource)) {
161                                retVal = in != null;
162                                ourIsOnClasspath.put(this, retVal);
163                        } catch (IOException e) {
164                                throw new RuntimeException(e);
165                        }
166                        // Ignore
167                }
168                return retVal;
169        }
170        
171        /**
172         * Returns a list of all versions for which the structure JARs have been
173         * found on the classpath.
174         */
175        public static synchronized List<Version> availableVersions() {
176                if (ourVersionsOnClasspath == null) {
177                        ourVersionsOnClasspath = new ArrayList<>();
178                        for (Version next : values()) {
179                                if (next.available()) {
180                                        ourVersionsOnClasspath.add(next);
181                                }
182                        }
183                }
184                return ourVersionsOnClasspath;
185        }
186        
187        /**
188         * <p>
189         * Returns the lowest version for which the structure classes are found
190         * on the classes. For instance, if <code>hapi-structures-v24-[version].jar</code>
191         * is the only structure JAR on the current JVM classpath, {@link Version#V24} will
192         * be returned.
193         * <p>
194         * <p>
195         * Returns <code>null</code> if none are found
196         * </p>
197         */
198        public static Version lowestAvailableVersion() {
199                List<Version> availableVersions = availableVersions();
200                if (availableVersions.size() >0) {
201                        return availableVersions.get(0);
202                } else {
203                        return null;
204                }
205        }
206
207        /**
208         * <p>
209         * Returns the highest version for which the structure classes are found
210         * on the classes. For instance, if <code>hapi-structures-v24-[version].jar</code>
211         * is the only structure JAR on the current JVM classpath, {@link Version#V24} will
212         * be returned.
213         * <p>
214         * </>
215         * If no structure JARs at all are found, returns a default value of
216         * {@link Version#V25}
217         * </p>
218         */
219        public static Version highestAvailableVersionOrDefault() {
220                List<Version> availableVersions = availableVersions();
221                if (availableVersions.size() >0) {
222                        return availableVersions.get(availableVersions.size() - 1);
223                } else {
224                        return Version.V25;
225                }
226        }
227
228        /**
229         * Construct and return a new {@link GenericMessage} for the given version
230         */
231        public GenericMessage newGenericMessage(ModelClassFactory mcf) {
232                switch (this) {
233                case V21:
234                        return new GenericMessage.V21(mcf);
235                case V22:
236                        return new GenericMessage.V22(mcf);
237                case V23:
238                        return new GenericMessage.V23(mcf);
239                case V231:
240                        return new GenericMessage.V231(mcf);
241                case V24:
242                        return new GenericMessage.V24(mcf);
243                case V25:
244                        return new GenericMessage.V25(mcf);
245                case V251:
246                        return new GenericMessage.V251(mcf);
247                case V26:
248                        return new GenericMessage.V26(mcf);
249                case V27:
250                        return new GenericMessage.V27(mcf);
251                case V271:
252                        return new GenericMessage.V271(mcf);
253                case V28:
254                        return new GenericMessage.V28(mcf);
255                case V281:
256                        return new GenericMessage.V281(mcf);
257                default:
258                        throw new Error("Unknown version (this is a HAPI bug): " + this.getVersion());
259                }
260        }
261        
262}