001package ca.uhn.fhir.context;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2018 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.instance.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        private final FhirVersionEnum myEquivalent;
048        private final boolean myIsRi;
049        private final String myVersionClass;
050        private volatile Boolean myPresentOnClasspath;
051        private volatile IFhirVersion myVersionImplementation;
052        private String myFhirVersionString;
053
054        FhirVersionEnum(String theVersionClass, FhirVersionEnum theEquivalent, boolean theIsRi, IVersionProvider theVersionExtractor) {
055                myVersionClass = theVersionClass;
056                myEquivalent = theEquivalent;
057                myFhirVersionString = theVersionExtractor.provideVersion();
058                myIsRi = theIsRi;
059        }
060
061        public String getFhirVersionString() {
062                return myFhirVersionString;
063        }
064
065        public IFhirVersion getVersionImplementation() {
066                if (!isPresentOnClasspath()) {
067                        throw new IllegalStateException("Version " + name() + " is not present on classpath");
068                }
069                if (myVersionImplementation == null) {
070                        try {
071                                myVersionImplementation = (IFhirVersion) Class.forName(myVersionClass).newInstance();
072                        } catch (Exception e) {
073                                throw new InternalErrorException("Failed to instantiate FHIR version " + name(), e);
074                        }
075                }
076                return myVersionImplementation;
077        }
078
079        public boolean isEqualOrNewerThan(FhirVersionEnum theVersion) {
080                return ordinal() >= theVersion.ordinal();
081        }
082
083        public boolean isEquivalentTo(FhirVersionEnum theVersion) {
084                if (this.equals(theVersion)) {
085                        return true;
086                }
087                if (myEquivalent != null) {
088                        return myEquivalent.equals(theVersion);
089                }
090                return false;
091        }
092
093        public boolean isNewerThan(FhirVersionEnum theVersion) {
094                return !isEquivalentTo(theVersion) && ordinal() > theVersion.ordinal();
095        }
096
097        public boolean isOlderThan(FhirVersionEnum theVersion) {
098                return !isEquivalentTo(theVersion) && ordinal() < theVersion.ordinal();
099        }
100
101        /**
102         * Returns true if the given version is present on the classpath
103         */
104        public boolean isPresentOnClasspath() {
105                Boolean retVal = myPresentOnClasspath;
106                if (retVal == null) {
107                        try {
108                                Class.forName(myVersionClass);
109                                retVal = true;
110                        } catch (Exception e) {
111                                retVal = false;
112                        }
113                        myPresentOnClasspath = retVal;
114                }
115                return retVal;
116        }
117
118        /**
119         * Is this version using the HL7.org RI structures?
120         */
121        public boolean isRi() {
122                return myIsRi;
123        }
124
125        public FhirContext newContext() {
126                switch (this) {
127                        case DSTU2:
128                                return FhirContext.forDstu2();
129                        case DSTU2_HL7ORG:
130                                return FhirContext.forDstu2Hl7Org();
131                        case DSTU2_1:
132                                return FhirContext.forDstu2_1();
133                        case DSTU3:
134                                return FhirContext.forDstu3();
135                        case R4:
136                                return FhirContext.forR4();
137                }
138                throw new IllegalStateException("Unknown version: " + this); // should not happen
139        }
140
141        /**
142         * Returns the {@link FhirVersionEnum} which corresponds to a specific version of
143         * FHIR. Partial version strings (e.g. "3.0") are acceptable.
144         *
145         * @return Returns null if no version exists matching the given string
146         */
147        public static FhirVersionEnum forVersionString(String theVersionString) {
148                for (FhirVersionEnum next : values()) {
149                        if (next.getFhirVersionString().startsWith(theVersionString)) {
150                                return next;
151                        }
152                }
153                return null;
154        }
155
156        private interface IVersionProvider {
157                String provideVersion();
158        }
159
160        private static class Version implements IVersionProvider {
161
162                private String myVersion;
163
164                public Version(String theVersion) {
165                        super();
166                        myVersion = theVersion;
167                }
168
169                @Override
170                public String provideVersion() {
171                        return myVersion;
172                }
173
174        }
175
176        /**
177         * This class attempts to read the FHIR version from the actual model
178         * classes in order to supply an accurate version string even over time
179         */
180        private static class Dstu3Version implements IVersionProvider {
181
182                private String myVersion;
183
184                Dstu3Version() {
185                        try {
186                                Class<?> c = Class.forName("org.hl7.fhir.dstu3.model.Constants");
187                                myVersion = (String) c.getDeclaredField("VERSION").get(null);
188                        } catch (Exception e) {
189                                myVersion = "3.0.1";
190                        }
191                }
192
193                @Override
194                public String provideVersion() {
195                        return myVersion;
196                }
197
198        }
199
200        private static class R4Version implements IVersionProvider {
201
202                private String myVersion;
203
204                R4Version() {
205                        try {
206                                Class<?> c = Class.forName("org.hl7.fhir.r4.model.Constants");
207                                myVersion = (String) c.getDeclaredField("VERSION").get(null);
208                        } catch (Exception e) {
209                                myVersion = "4.0.0";
210                        }
211                }
212
213                @Override
214                public String provideVersion() {
215                        return myVersion;
216                }
217
218        }
219
220}