001package ca.uhn.fhir.jpa.dao;
002
003/*-
004 * #%L
005 * HAPI FHIR Storage api
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
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 com.google.common.collect.Multimap;
024import com.google.common.collect.MultimapBuilder;
025import org.apache.commons.lang3.tuple.Pair;
026import org.hl7.fhir.instance.model.api.IIdType;
027
028import java.util.HashMap;
029import java.util.List;
030import java.util.Map;
031import java.util.stream.Collectors;
032
033public class IdSubstitutionMap {
034
035        private final Map<Entry, Entry> myMap = new HashMap<>();
036        private final Multimap<Entry, Entry> myReverseMap = MultimapBuilder.hashKeys().arrayListValues().build();
037
038
039        public boolean containsSource(IIdType theId) {
040                if (theId.isLocal()) {
041                        return false;
042                }
043                return myMap.containsKey(new Entry(theId));
044        }
045
046        public boolean containsSource(String theId) {
047                return myMap.containsKey(new Entry(theId));
048        }
049
050        public boolean containsTarget(IIdType theId) {
051                return myReverseMap.containsKey(new Entry(theId));
052        }
053
054        public boolean containsTarget(String theId) {
055                return myReverseMap.containsKey(new Entry(theId));
056        }
057
058        public IIdType getForSource(IIdType theId) {
059                Entry target = myMap.get(new Entry(theId));
060                if (target != null) {
061                        assert target.myId != null;
062                        return target.myId;
063                }
064                return null;
065        }
066
067
068        public IIdType getForSource(String theId) {
069                Entry target = myMap.get(new Entry(theId));
070                if (target != null) {
071                        assert target.myId != null;
072                        return target.myId;
073                }
074                return null;
075        }
076
077        public List<Pair<IIdType, IIdType>> entrySet() {
078                return myMap
079                        .entrySet()
080                        .stream()
081                        .map(t->Pair.of(t.getKey().myId, t.getValue().myId))
082                        .collect(Collectors.toList());
083        }
084
085        public void put(IIdType theSource, IIdType theTarget) {
086                myMap.put(new Entry(theSource), new Entry(theTarget));
087                myReverseMap.put(new Entry(theTarget), new Entry(theSource));
088        }
089
090        public boolean isEmpty() {
091                return myMap.isEmpty();
092        }
093
094
095        private static class Entry {
096
097                private final String myUnversionedId;
098                private final IIdType myId;
099
100                private Entry(String theId) {
101                        myId = null;
102                        myUnversionedId = theId;
103                }
104
105                private Entry(IIdType theId) {
106                        String unversionedId = toVersionlessValue(theId);
107                        myUnversionedId = unversionedId;
108                        myId = theId;
109                }
110
111                @Override
112                public boolean equals(Object theOther) {
113                        if (theOther instanceof Entry) {
114                                String otherUnversionedId = ((Entry) theOther).myUnversionedId;
115                                if (myUnversionedId.equals(otherUnversionedId)) {
116                                        return true;
117                                }
118                        }
119                        return false;
120                }
121
122                @Override
123                public int hashCode() {
124                        return myUnversionedId.hashCode();
125                }
126
127        }
128
129        static String toVersionlessValue(IIdType theId) {
130                boolean isPlaceholder = theId.getValue().startsWith("urn:");
131                String unversionedId;
132                if (isPlaceholder || (!theId.hasBaseUrl() && !theId.hasVersionIdPart()) || !theId.hasResourceType()) {
133                        unversionedId = theId.getValue();
134                } else {
135                        unversionedId = theId.toUnqualifiedVersionless().getValue();
136                }
137                return unversionedId;
138        }
139}