
001package org.hl7.fhir.r4.context; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.Comparator; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009import java.util.Set; 010import java.util.UUID; 011 012import org.hl7.fhir.r4.model.CodeSystem; 013import org.hl7.fhir.r4.model.MetadataResource; 014import org.hl7.fhir.utilities.VersionUtilities; 015 016/** 017 * This manages a cached list of resources, and provides high speed access by URL / URL+version, and assumes that patch version doesn't matter for access 018 * note, though, that not all resources have semver versions 019 * 020 * @author graha 021 * 022 */ 023 024public class CanonicalResourceManager<T extends MetadataResource> { 025 026 public class MetadataResourceVersionComparator<T extends MetadataResource> implements Comparator<T> { 027 @Override 028 public int compare(T arg1, T arg2) { 029 String v1 = arg1.getVersion(); 030 String v2 = arg2.getVersion(); 031 if (v1 == null && v2 == null) { 032 return Integer.compare(list.indexOf(arg1), list.indexOf(arg2)); // retain original order 033 } else if (v1 == null) { 034 return -1; 035 } else if (v2 == null) { 036 return 1; 037 } else { 038 String mm1 = VersionUtilities.getMajMin(v1); 039 String mm2 = VersionUtilities.getMajMin(v2); 040 if (mm1 == null || mm2 == null) { 041 return v1.compareTo(v2); 042 } else { 043 return mm1.compareTo(mm2); 044 } 045 } 046 } 047 } 048 049 050 private boolean enforceUniqueId; 051 private List<T> list = new ArrayList<>(); 052 private Map<String, T> map = new HashMap<>(); 053 054 055 public CanonicalResourceManager(boolean enforceUniqueId) { 056 super(); 057 this.enforceUniqueId = enforceUniqueId; 058 } 059 060 public void copy(CanonicalResourceManager<T> source) { 061 list.clear(); 062 map.clear(); 063 list.addAll(source.list); 064 map.putAll(source.map); 065 } 066 067 public void see(T r) { 068 if (!r.hasId()) { 069 r.setId(UUID.randomUUID().toString()); 070 } 071 if (enforceUniqueId && map.containsKey(r.getId())) { 072 drop(r.getId()); 073 } 074 list.add(r); 075 map.put(r.getId(), r); // we do this so we can drop by id 076 077 if (r.hasUrl()) { 078 // first, this is the correct reosurce for this version (if it has a version) 079 if (r.hasVersion()) { 080 map.put(r.getUrl()+"|"+r.getVersion(), r); 081 } 082 updateList(r.getUrl(), r.getVersion()); 083 } 084 } 085 086 private void updateList(String url, String version) { 087 List<T> rl = new ArrayList<T>(); 088 for (T t : list) { 089 if (url.equals(t.getUrl()) && !rl.contains(t)) { 090 rl.add(t); 091 } 092 } 093 if (rl.size() > 0) { 094 // sort by version as much as we are able 095 Collections.sort(rl, new MetadataResourceVersionComparator<T>()); 096 // the current is the latest 097 map.put(url, rl.get(rl.size()-1)); 098 // now, also, the latest for major/minor 099 if (version != null) { 100 T latest = null; 101 for (T t : rl) { 102 if (VersionUtilities.versionsCompatible(t.getVersion(), version)) { 103 latest = t; 104 } 105 } 106 if (latest != null) { // might be null if it's not using semver 107 String lv = VersionUtilities.getMajMin(latest.getVersion()); 108 if (lv != null && !lv.equals(version)) 109 map.put(url+"|"+lv, rl.get(rl.size()-1)); 110 } 111 } 112 } 113 } 114 115 116 public T get(String url) { 117 return map.get(url); 118 } 119 120 public boolean has(String url) { 121 return map.containsKey(url); 122 } 123 124 public T get(String system, String version) { 125 if (map.containsKey(system+"|"+version)) 126 return map.get(system+"|"+version); 127 String mm = VersionUtilities.getMajMin(version); 128 if (mm != null) 129 return map.get(system+"|"+mm); 130 else 131 return null; 132 } 133 134 public boolean has(String system, String version) { 135 if (map.containsKey(system+"|"+version)) 136 return true; 137 String mm = VersionUtilities.getMajMin(version); 138 if (mm != null) 139 return map.containsKey(system+"|"+mm); 140 else 141 return false; 142 } 143 144 public int size() { 145 return list.size(); 146 } 147 148 public void drop(String id) { 149 T res = null; 150 do { 151 res = null; 152 for (T t : list) { 153 if (t.getId().equals(id)) { 154 res = t; 155 } 156 } 157 if (res != null) { 158 list.remove(res); 159 map.remove(id); 160 map.remove(res.getUrl()); 161 if (res.hasVersion()) { 162 map.remove(res.getUrl()+"|"+res.getVersion()); 163 String mm = VersionUtilities.getMajMin(res.getVersion()); 164 if (mm != null) { 165 map.remove(res.getUrl()+"|"+mm); 166 } 167 } 168 updateList(res.getUrl(), res.getVersion()); 169 } 170 } while (res != null); 171 } 172 173 174 public void listAll(List<T> result) { 175 result.addAll(list); 176 } 177 178 public void listAllM(List<MetadataResource> result) { 179 result.addAll(list); 180 } 181 182 public void clear() { 183 list.clear(); 184 map.clear(); 185 186 } 187 188 public List<T> getList() { 189 List<T> res = new ArrayList<>(); 190 for (T t : list) { 191 if (!res.contains(t)) { 192 res.add(t); 193 } 194 } 195 return res; 196 } 197 198 public Set<String> keys() { 199 return map.keySet(); 200 } 201 202 public boolean isEnforceUniqueId() { 203 return enforceUniqueId; 204 } 205 206}