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}