001/*-
002 * #%L
003 * HAPI FHIR - Master Data Management
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.mdm.model;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.fhirpath.IFhirPath;
024import org.hl7.fhir.instance.model.api.IBase;
025import org.hl7.fhir.instance.model.api.IBaseResource;
026import org.hl7.fhir.instance.model.api.IPrimitiveType;
027import org.hl7.fhir.r4.model.Identifier;
028
029import java.util.List;
030import java.util.Objects;
031import java.util.stream.Collectors;
032
033public class CanonicalEID {
034
035        private String mySystem;
036        private String myUse;
037        private String myValue;
038
039        public CanonicalEID(String theSystem, String theValue, String theUse) {
040                mySystem = theSystem;
041                myUse = theUse;
042                myValue = theValue;
043        }
044
045        /**
046         * Constructor is private as we expect you to use the factory method.
047         */
048        @SuppressWarnings("rawtypes")
049        private CanonicalEID(IFhirPath theFhirPath, IBase theIBase) {
050                List<IPrimitiveType> value = theFhirPath.evaluate(theIBase, "value", IPrimitiveType.class);
051                List<IPrimitiveType> system = theFhirPath.evaluate(theIBase, "system", IPrimitiveType.class);
052                List<IPrimitiveType> use = theFhirPath.evaluate(theIBase, "use", IPrimitiveType.class);
053
054                myUse = use.isEmpty() ? null : use.get(0).getValueAsString();
055                myValue = value.isEmpty() ? null : value.get(0).getValueAsString();
056                mySystem = system.isEmpty() ? null : system.get(0).getValueAsString();
057        }
058
059        /**
060         * Get the appropriate FHIRPath expression to extract the EID identifier value, regardless of resource type.
061         * e.g. if theBaseResource is a patient, and the MDM EID system is test-system, this will return
062         *
063         * Patient.identifier.where(system='test-system').value
064         *
065         */
066        private static String buildEidFhirPath(
067                        FhirContext theFhirContext, String theEidSystem, IBaseResource theBaseResource) {
068                return theFhirContext.getResourceType(theBaseResource) + ".identifier.where(system='" + theEidSystem + "')";
069        }
070
071        public Identifier toR4() {
072                return new Identifier()
073                                .setUse(Identifier.IdentifierUse.fromCode(myUse))
074                                .setSystem(mySystem)
075                                .setValue(myValue);
076        }
077
078        public org.hl7.fhir.dstu3.model.Identifier toDSTU3() {
079                return new org.hl7.fhir.dstu3.model.Identifier()
080                                .setUse(org.hl7.fhir.dstu3.model.Identifier.IdentifierUse.fromCode(myUse))
081                                .setSystem(mySystem)
082                                .setValue(myValue);
083        }
084
085        public org.hl7.fhir.r5.model.Identifier toR5() {
086                return new org.hl7.fhir.r5.model.Identifier()
087                                .setUse(org.hl7.fhir.r5.model.Identifier.IdentifierUse.fromCode(myUse))
088                                .setSystem(mySystem)
089                                .setValue(myValue);
090        }
091
092        public String getSystem() {
093                return mySystem;
094        }
095
096        public String getUse() {
097                return myUse;
098        }
099
100        public String getValue() {
101                return myValue;
102        }
103
104        public void setSystem(String theSystem) {
105                mySystem = theSystem;
106        }
107
108        public void setUse(String theUse) {
109                myUse = theUse;
110        }
111
112        private void setValue(String theValue) {
113                myValue = theValue;
114        }
115
116        @Override
117        public String toString() {
118                return mySystem + '|' + myValue;
119        }
120
121        /**
122         * A Factory method to generate a {@link CanonicalEID} object from an incoming resource.
123         *
124         * @param theFhirContext the {@link FhirContext} of the application, used to generate a FHIRPath parser.
125         * @param theEidSystem the enterprise identifier system URI used by this instance.
126         * @param theBaseResource the {@link IBaseResource} from which you would like to extract EIDs.
127         *
128         * @return an optional {@link CanonicalEID} object, representing a resource identifier that matched the given eidSystem.
129         */
130        public static List<CanonicalEID> extractFromResource(
131                        FhirContext theFhirContext, String theEidSystem, IBaseResource theBaseResource) {
132                IFhirPath fhirPath = theFhirContext.newFhirPath();
133                String eidPath = buildEidFhirPath(theFhirContext, theEidSystem, theBaseResource);
134                List<IBase> evaluate = fhirPath.evaluate(theBaseResource, eidPath, IBase.class);
135
136                return evaluate.stream().map(ibase -> new CanonicalEID(fhirPath, ibase)).collect(Collectors.toList());
137        }
138
139        @Override
140        public boolean equals(Object o) {
141                if (!(o instanceof CanonicalEID)) {
142                        return false;
143                }
144                CanonicalEID otherEid = (CanonicalEID) o;
145                return Objects.equals(otherEid.getSystem(), this.getSystem())
146                                && Objects.equals(otherEid.getValue(), this.getValue())
147                                && Objects.equals(otherEid.getUse(), this.getUse());
148        }
149
150        @Override
151        public int hashCode() {
152                return Objects.hash(mySystem, myValue, myUse);
153        }
154}