001package ca.uhn.fhir.context;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2019 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 * http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.model.api.IFhirVersion;
024import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
025
026public enum FhirVersionEnum {
027
028        /*
029         * ***********************
030         * Don't auto-sort this type!!!
031         *
032         * Or more accurately, entries should be sorted from OLDEST FHIR release
033         * to NEWEST FHIR release instead of alphabetically
034         * ***********************
035         */
036
037        DSTU2("ca.uhn.fhir.model.dstu2.FhirDstu2", null, false, new Version("1.0.2")),
038
039        DSTU2_HL7ORG("org.hl7.fhir.dstu2.hapi.ctx.FhirDstu2Hl7Org", DSTU2, true, new Version("1.0.2")),
040
041        DSTU2_1("org.hl7.fhir.dstu2016may.hapi.ctx.FhirDstu2_1", null, true, new Version("1.4.0")),
042
043        DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Dstu3Version()),
044
045        R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),
046
047        R5("org.hl7.fhir.r5.hapi.ctx.FhirR5", null, true, new R5Version());
048
049        private final FhirVersionEnum myEquivalent;
050        private final boolean myIsRi;
051        private final String myVersionClass;
052        private volatile Boolean myPresentOnClasspath;
053        private volatile IFhirVersion myVersionImplementation;
054        private String myFhirVersionString;
055
056        FhirVersionEnum(String theVersionClass, FhirVersionEnum theEquivalent, boolean theIsRi, IVersionProvider theVersionExtractor) {
057                myVersionClass = theVersionClass;
058                myEquivalent = theEquivalent;
059                myFhirVersionString = theVersionExtractor.provideVersion();
060                myIsRi = theIsRi;
061        }
062
063        public String getFhirVersionString() {
064                return myFhirVersionString;
065        }
066
067        public IFhirVersion getVersionImplementation() {
068                if (!isPresentOnClasspath()) {
069                        throw new IllegalStateException("Version " + name() + " is not present on classpath");
070                }
071                if (myVersionImplementation == null) {
072                        try {
073                                myVersionImplementation = (IFhirVersion) Class.forName(myVersionClass).newInstance();
074                        } catch (Exception e) {
075                                throw new InternalErrorException("Failed to instantiate FHIR version " + name(), e);
076                        }
077                }
078                return myVersionImplementation;
079        }
080
081        public boolean isEqualOrNewerThan(FhirVersionEnum theVersion) {
082                return ordinal() >= theVersion.ordinal();
083        }
084
085        public boolean isEquivalentTo(FhirVersionEnum theVersion) {
086                if (this.equals(theVersion)) {
087                        return true;
088                }
089                if (myEquivalent != null) {
090                        return myEquivalent.equals(theVersion);
091                }
092                return false;
093        }
094
095        public boolean isNewerThan(FhirVersionEnum theVersion) {
096                return !isEquivalentTo(theVersion) && ordinal() > theVersion.ordinal();
097        }
098
099        public boolean isOlderThan(FhirVersionEnum theVersion) {
100                return !isEquivalentTo(theVersion) && ordinal() < theVersion.ordinal();
101        }
102
103        /**
104         * Returns true if the given version is present on the classpath
105         */
106        public boolean isPresentOnClasspath() {
107                Boolean retVal = myPresentOnClasspath;
108                if (retVal == null) {
109                        try {
110                                Class.forName(myVersionClass);
111                                retVal = true;
112                        } catch (Exception e) {
113                                retVal = false;
114                        }
115                        myPresentOnClasspath = retVal;
116                }
117                return retVal;
118        }
119
120        /**
121         * Is this version using the HL7.org RI structures?
122         */
123        public boolean isRi() {
124                return myIsRi;
125        }
126
127        public FhirContext newContext() {
128                switch (this) {
129                        case DSTU2:
130                                return FhirContext.forDstu2();
131                        case DSTU2_HL7ORG:
132                                return FhirContext.forDstu2Hl7Org();
133                        case DSTU2_1:
134                                return FhirContext.forDstu2_1();
135                        case DSTU3:
136                                return FhirContext.forDstu3();
137                        case R4:
138                                return FhirContext.forR4();
139                        case R5:
140                                return FhirContext.forR5();
141                }
142                throw new IllegalStateException("Unknown version: " + this); // should not happen
143        }
144
145        /**
146         * Returns the {@link FhirVersionEnum} which corresponds to a specific version of
147         * FHIR. Partial version strings (e.g. "3.0") are acceptable.
148         *
149         * @return Returns null if no version exists matching the given string
150         */
151        public static FhirVersionEnum forVersionString(String theVersionString) {
152                for (FhirVersionEnum next : values()) {
153                        if (next.getFhirVersionString().startsWith(theVersionString)) {
154                                return next;
155                        }
156                }
157                return null;
158        }
159
160        private interface IVersionProvider {
161                String provideVersion();
162        }
163
164        private static class Version implements IVersionProvider {
165
166                private String myVersion;
167
168                public Version(String theVersion) {
169                        super();
170                        myVersion = theVersion;
171                }
172
173                @Override
174                public String provideVersion() {
175                        return myVersion;
176                }
177
178        }
179
180        /**
181         * This class attempts to read the FHIR version from the actual model
182         * classes in order to supply an accurate version string even over time
183         */
184        private static class Dstu3Version implements IVersionProvider {
185
186                private String myVersion;
187
188                Dstu3Version() {
189                        try {
190                                Class<?> c = Class.forName("org.hl7.fhir.dstu3.model.Constants");
191                                myVersion = (String) c.getDeclaredField("VERSION").get(null);
192                        } catch (Exception e) {
193                                myVersion = "3.0.1";
194                        }
195                }
196
197                @Override
198                public String provideVersion() {
199                        return myVersion;
200                }
201
202        }
203
204        private static class R4Version implements IVersionProvider {
205
206                private String myVersion;
207
208                R4Version() {
209                        try {
210                                Class<?> c = Class.forName("org.hl7.fhir.r4.model.Constants");
211                                myVersion = (String) c.getDeclaredField("VERSION").get(null);
212                        } catch (Exception e) {
213                                myVersion = "4.0.0";
214                        }
215                }
216
217                @Override
218                public String provideVersion() {
219                        return myVersion;
220                }
221
222        }
223
224        private static class R5Version implements IVersionProvider {
225
226                private String myVersion;
227
228                R5Version() {
229                        try {
230                                Class<?> c = Class.forName("org.hl7.fhir.r5.model.Constants");
231                                myVersion = (String) c.getDeclaredField("VERSION").get(null);
232                        } catch (Exception e) {
233                                myVersion = "5.0.0";
234                        }
235                }
236
237                @Override
238                public String provideVersion() {
239                        return myVersion;
240                }
241
242        }
243
244}