
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.MetadataResource; 013import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 014import org.hl7.fhir.utilities.VersionUtilities; 015 016/** 017 * This manages a cached list of resources, and provides high speed access by 018 * URL / URL+version, and assumes that patch version doesn't matter for access 019 * note, though, that not all resources have semver versions 020 * 021 * @author graha 022 * 023 */ 024 025@MarkedToMoveToAdjunctPackage 026public class CanonicalResourceManager<T extends MetadataResource> { 027 028 public class MetadataResourceVersionComparator<T extends MetadataResource> implements Comparator<T> { 029 @Override 030 public int compare(T arg1, T arg2) { 031 String v1 = arg1.getVersion(); 032 String v2 = arg2.getVersion(); 033 if (v1 == null && v2 == null) { 034 return Integer.compare(list.indexOf(arg1), list.indexOf(arg2)); // retain original order 035 } else if (v1 == null) { 036 return -1; 037 } else if (v2 == null) { 038 return 1; 039 } else { 040 String mm1 = VersionUtilities.getMajMin(v1); 041 String mm2 = VersionUtilities.getMajMin(v2); 042 if (mm1 == null || mm2 == null) { 043 return v1.compareTo(v2); 044 } else { 045 return mm1.compareTo(mm2); 046 } 047 } 048 } 049 } 050 051 private boolean enforceUniqueId; 052 private List<T> list = new ArrayList<>(); 053 private Map<String, T> map = new HashMap<>(); 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 public T get(String url) { 116 return map.get(url); 117 } 118 119 public boolean has(String url) { 120 return map.containsKey(url); 121 } 122 123 public T get(String system, String version) { 124 if (map.containsKey(system + "|" + version)) 125 return map.get(system + "|" + version); 126 String mm = VersionUtilities.getMajMin(version); 127 if (mm != null) 128 return map.get(system + "|" + mm); 129 else 130 return null; 131 } 132 133 public boolean has(String system, String version) { 134 if (map.containsKey(system + "|" + version)) 135 return true; 136 String mm = VersionUtilities.getMajMin(version); 137 if (mm != null) 138 return map.containsKey(system + "|" + mm); 139 else 140 return false; 141 } 142 143 public int size() { 144 return list.size(); 145 } 146 147 public void drop(String id) { 148 T res = null; 149 do { 150 res = null; 151 for (T t : list) { 152 if (t.getId().equals(id)) { 153 res = t; 154 } 155 } 156 if (res != null) { 157 list.remove(res); 158 map.remove(id); 159 map.remove(res.getUrl()); 160 if (res.hasVersion()) { 161 map.remove(res.getUrl() + "|" + res.getVersion()); 162 String mm = VersionUtilities.getMajMin(res.getVersion()); 163 if (mm != null) { 164 map.remove(res.getUrl() + "|" + mm); 165 } 166 } 167 updateList(res.getUrl(), res.getVersion()); 168 } 169 } while (res != null); 170 } 171 172 public void listAll(List<T> result) { 173 result.addAll(list); 174 } 175 176 public void listAllM(List<MetadataResource> result) { 177 result.addAll(list); 178 } 179 180 public void clear() { 181 list.clear(); 182 map.clear(); 183 184 } 185 186 public List<T> getList() { 187 List<T> res = new ArrayList<>(); 188 for (T t : list) { 189 if (!res.contains(t)) { 190 res.add(t); 191 } 192 } 193 return res; 194 } 195 196 public Set<String> keys() { 197 return map.keySet(); 198 } 199 200 public boolean isEnforceUniqueId() { 201 return enforceUniqueId; 202 } 203 204}