
001package org.hl7.fhir.r5.comparison; 002 003import java.io.IOException; 004import java.util.HashMap; 005import java.util.Map; 006import java.util.UUID; 007 008import org.hl7.fhir.exceptions.DefinitionException; 009import org.hl7.fhir.exceptions.FHIRException; 010import org.hl7.fhir.exceptions.FHIRFormatError; 011import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.CanonicalResourceComparison; 012import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison; 013import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison; 014import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison; 015import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison; 016import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; 017import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation.AnotationType; 018import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider; 019import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 020import org.hl7.fhir.r5.context.IWorkerContext; 021import org.hl7.fhir.r5.model.Base; 022import org.hl7.fhir.r5.model.CanonicalResource; 023import org.hl7.fhir.r5.model.CapabilityStatement; 024import org.hl7.fhir.r5.model.CodeSystem; 025import org.hl7.fhir.r5.model.Resource; 026import org.hl7.fhir.r5.model.StructureDefinition; 027import org.hl7.fhir.r5.model.ValueSet; 028import org.hl7.fhir.r5.renderers.utils.RenderingContext; 029import org.hl7.fhir.r5.utils.UserDataNames; 030import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 031import org.hl7.fhir.utilities.i18n.RenderingI18nContext; 032 033@MarkedToMoveToAdjunctPackage 034public class ComparisonSession { 035 036 037 private Map<String, ResourceComparison> compares = new HashMap<>(); 038 private IWorkerContext contextLeft; 039 private IWorkerContext contextRight; 040 private String sessiondId; 041 private int count; 042 private boolean debug; 043 private boolean annotate; 044 private String title; 045 private ProfileKnowledgeProvider pkpLeft; 046 private ProfileKnowledgeProvider pkpRight; 047 private RenderingI18nContext i18n; 048 049 public ComparisonSession(RenderingI18nContext i18n, IWorkerContext contextLeft, IWorkerContext contextRight, String title, ProfileKnowledgeProvider pkpLeft, ProfileKnowledgeProvider pkpRight) { 050 super(); 051 this.contextLeft = contextLeft; 052 this.contextRight = contextRight; 053 this.sessiondId = UUID.randomUUID().toString().toLowerCase(); 054 this.title = title; 055 this.pkpLeft = pkpLeft; 056 this.pkpRight = pkpRight; 057 this.i18n = i18n; 058 debug = false; 059 } 060 061 public IWorkerContext getContextLeft() { 062 return contextLeft; 063 } 064 065 public IWorkerContext getContextRight() { 066 return contextRight; 067 } 068 069 public String getTitle() { 070 return title; 071 } 072 073 public ResourceComparison compare(String left, Resource leftSource, String right, Resource rightSource) throws DefinitionException, FHIRFormatError, IOException { 074 CanonicalResource l = (CanonicalResource) contextLeft.fetchResource(Resource.class, left, leftSource); 075 if (l == null) { 076 throw new DefinitionException("Unable to resolve "+left); 077 } 078 CanonicalResource r = (CanonicalResource) contextRight.fetchResource(Resource.class, right, rightSource); 079 if (r == null) { 080 throw new DefinitionException("Unable to resolve "+right); 081 } 082 return compare(l, r); 083 } 084 085 public ResourceComparison compare(CanonicalResource left, CanonicalResource right) throws DefinitionException, FHIRFormatError, IOException { 086 if (left != null && right != null) { 087 String key = key(left.getUrl(), left.getVersion(), right.getUrl(), right.getVersion()); 088 if (compares.containsKey(key)) { 089 // if null then the comparison is in progress. 090 // this can happen when profiles refer to each other 091 return compares.get(key); 092 } 093 compares.put(key, null); 094 try { 095 if (left instanceof CodeSystem && right instanceof CodeSystem) { 096 CodeSystemComparer cs = new CodeSystemComparer(this); 097 CodeSystemComparison csc = cs.compare((CodeSystem) left, (CodeSystem) right); 098 compares.put(key, csc); 099 return csc; 100 } else if (left instanceof ValueSet && right instanceof ValueSet) { 101 ValueSetComparer cs = new ValueSetComparer(this); 102 ValueSetComparison csc = cs.compare((ValueSet) left, (ValueSet) right); 103 compares.put(key, csc); 104 return csc; 105 } else if (left instanceof StructureDefinition && right instanceof StructureDefinition) { 106 StructureDefinitionComparer cs = new StructureDefinitionComparer(this, new ProfileUtilities(contextLeft, null, pkpLeft), new ProfileUtilities(contextRight, null, pkpRight)); 107 ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right); 108 compares.put(key, csc); 109 return csc; 110 } else if (left instanceof CapabilityStatement && right instanceof CapabilityStatement) { 111 CapabilityStatementComparer cs = new CapabilityStatementComparer(this); 112 CapabilityStatementComparison csc = cs.compare((CapabilityStatement) left, (CapabilityStatement) right); 113 compares.put(key, csc); 114 return csc; 115 } else { 116 throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType()); 117 } 118 } catch (Throwable e) { 119 if (debug) { 120 e.printStackTrace(); 121 } 122 ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e); 123 compares.put(key, csc); 124 return csc; 125 } 126 } else if (left != null) { 127 markDeleted(null, left.fhirType(), left); // todo: waht? 128 String key = key(left.getUrl(), left.getVersion(), left.getUrl(), left.getVersion()); 129 if (compares.containsKey(key)) { 130 return compares.get(key); 131 } 132 ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right); 133 compares.put(key, csc); 134 return csc; 135 } else { 136 markAdded(right); 137 String key = key(right.getUrl(), right.getVersion(), right.getUrl(), right.getVersion()); 138 if (compares.containsKey(key)) { 139 return compares.get(key); 140 } 141 ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right); 142 compares.put(key, csc); 143 return csc; 144 } 145 } 146 147 private String key(String urlL, String verL, String urlR, String verR) { 148 return urlL+"|"+verL+"||"+urlR+"|"+verR; 149 } 150 151 public void identify(CanonicalResource res) { 152 count++; 153 res.setId(sessiondId+"-"+count); 154 res.setUrl("http://hl7.org/fhir/comparison/"+res.fhirType()+"/"+res.getId()); 155 } 156 157 public void identify(ResourceComparison res) { 158 count++; 159 } 160 161 public boolean isDebug() { 162 return debug; 163 } 164 165 public void setDebug(boolean debug) { 166 this.debug = debug; 167 } 168 169 public Map<String, ResourceComparison> getCompares() { 170 return compares; 171 } 172 173 public ProfileKnowledgeProvider getPkpLeft() { 174 return pkpLeft; 175 } 176 177 public ProfileKnowledgeProvider getPkpRight() { 178 return pkpRight; 179 } 180 181 public boolean isAnnotate() { 182 return annotate; 183 } 184 185 public RenderingI18nContext getI18n() { 186 return i18n; 187 } 188 189 public void setAnnotate(boolean annotate) { 190 this.annotate = annotate; 191 } 192 193 private VersionComparisonAnnotation getAnnotation(Base b) { 194 if (b == null) { 195 return null; 196 } 197 if (b.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { 198 return (VersionComparisonAnnotation) b.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); 199 } else { 200 VersionComparisonAnnotation vca = new VersionComparisonAnnotation(AnotationType.NoChange); 201 b.setUserData(UserDataNames.COMP_VERSION_ANNOTATION, vca); 202 return vca; 203 } 204 } 205 206 public void markAdded(Base focus) { 207 if (isAnnotate()) { 208 getAnnotation(focus).added(); 209 } 210 } 211 212 public void markChanged(Base focus, Base original) { 213 if (isAnnotate()) { 214 getAnnotation(focus).changed(original); 215 } 216 } 217 218 public void markDeleted(Base parent, String name, Base other) { 219 if (isAnnotate() && other != null) { 220 VersionComparisonAnnotation annotation = getAnnotation(parent); 221 if (annotation != null) { 222 annotation.deleted(name, other); 223 } 224 annotation = getAnnotation(other); 225 if (annotation != null) { 226 annotation.deleted(); 227 } 228 } 229 } 230 231 public void annotate(Base base, CanonicalResourceComparison<? extends CanonicalResource> comp) { 232 if (isAnnotate()) { 233 getAnnotation(base).comp(comp); 234 } 235 } 236}