
001package org.hl7.fhir.r5.terminologies.utilities; 002 003import java.util.*; 004 005import org.hl7.fhir.r5.model.CodeableConcept; 006import org.hl7.fhir.r5.model.Coding; 007import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; 008import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; 009import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 010import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 011import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 012 013public class ValidationResult { 014 private ConceptDefinitionComponent definition; 015 private String preferredDisplay; 016 private String system; 017 private String version; 018 private IssueSeverity severity; 019 private List<String> messages = new ArrayList<>(); 020 private TerminologyServiceErrorClass errorClass; 021 private String txLink; 022 private String diagnostics; 023 private List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); 024 private CodeableConcept codeableConcept; 025 private Set<String> unknownSystems; 026 private boolean inactive; 027 private String status; 028 private String server; 029 private boolean errorIsDisplayIssue; 030 031 @Override 032 public String toString() { 033 return "ValidationResult [definition=" + definition + ", system=" + system + ", severity=" + severity + ", message=" + getMessage() + ", errorClass=" 034 + errorClass + ", txLink=" + txLink + "]"; 035 } 036 037 public ValidationResult(ValidationResult validationResult) { 038 this.definition = validationResult.definition == null ? null : validationResult.definition.copy(); 039 this.preferredDisplay = validationResult.preferredDisplay; 040 this.system = validationResult.system; 041 this.version = validationResult.version; 042 this.severity = validationResult.severity; 043 if (validationResult.messages != null) { 044 this.messages.addAll(validationResult.messages); 045 } 046 this.errorClass = validationResult.errorClass; 047 this.txLink = validationResult.txLink; 048 this.diagnostics = validationResult.diagnostics; 049 if (validationResult.issues != null) { 050 for (OperationOutcomeIssueComponent issue : validationResult.issues) { 051 this.issues.add(issue.copy()); 052 } 053 } 054 this.codeableConcept = validationResult.codeableConcept == null ? null : validationResult.codeableConcept.copy(); 055 this.unknownSystems = validationResult.unknownSystems == null ? null : new HashSet<>(validationResult.unknownSystems); 056 this.inactive = validationResult.inactive; 057 this.status = validationResult.status; 058 this.server = validationResult.server; 059 } 060 061 public ValidationResult(IssueSeverity severity, String message, List<OperationOutcomeIssueComponent> issues) { 062 this.severity = severity; 063 if (message != null) { 064 this.messages.add(message); 065 } 066 if (issues != null) { 067 this.issues.addAll(issues); 068 } 069 } 070 071 public ValidationResult(String system, String version, ConceptDefinitionComponent definition, String preferredDisplay) { 072 this.system = system; 073 this.version = version; 074 this.definition = definition; 075 this.preferredDisplay = preferredDisplay; 076 } 077 078 public ValidationResult(IssueSeverity severity, String message, String system, String version, ConceptDefinitionComponent definition, String preferredDisplay, List<OperationOutcomeIssueComponent> issues) { 079 this.severity = severity; 080 if (message != null) { 081 this.messages.add(message); 082 } 083 this.system = system; 084 this.version = version; 085 this.definition = definition; 086 this.preferredDisplay = preferredDisplay; 087 if (issues != null) { 088 this.issues.addAll(issues); 089 } 090 } 091 public ValidationResult(IssueSeverity severity, List<String> messages, String system, String version, ConceptDefinitionComponent definition, String preferredDisplay, List<OperationOutcomeIssueComponent> issues) { 092 this.severity = severity; 093 this.messages.addAll(messages); 094 this.system = system; 095 this.version = version; 096 this.definition = definition; 097 this.preferredDisplay = preferredDisplay; 098 if (issues != null) { 099 this.issues.addAll(issues); 100 } 101 } 102 103 public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass, List<OperationOutcomeIssueComponent> issues) { 104 this.severity = severity; 105 if (message != null) { 106 this.messages.add(message); 107 } 108 this.errorClass = errorClass; 109 if (issues != null) { 110 this.issues.addAll(issues); 111 } 112 } 113 114 public boolean isOk() { 115 return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING || errorIsDisplayIssue; 116 } 117 118 public String getSystem() { 119 return system; 120 } 121 122 public String getVersion() { 123 return version; 124 } 125 126 public String getDisplay() { 127 if (preferredDisplay != null) { 128 return preferredDisplay; 129 } else { 130 return definition == null ? null : definition.getDisplay(); 131 } 132 } 133 134 public void setDisplay(String display) { 135 this.preferredDisplay = display; 136 } 137 138 public void setSystem(String system) { 139 this.system = system; 140 } 141 142 public void setVersion(String version) { 143 this.version = version; 144 } 145 146 public String getCode() { 147 return definition == null ? null : definition.getCode(); 148 } 149 150 public String getDefinition() { 151 return definition == null ? null : definition.getDefinition(); 152 } 153 154 public void setDefinition(ConceptDefinitionComponent definition) { 155 this.definition = definition; 156 } 157 158 public ConceptDefinitionComponent asConceptDefinition() { 159 return definition; 160 } 161 162 public IssueSeverity getSeverity() { 163 return severity; 164 } 165 166 public String getMessage() { 167 if (messages.size() == 0) { 168 return null; 169 } 170 Collections.sort(messages); 171 return CommaSeparatedStringBuilder.join("; ", messages); 172 } 173 174 public String getTrimmedMessage() { 175 List<String> toTrim = new ArrayList<>(); 176 for (OperationOutcomeIssueComponent iss : getIssues()) { 177 toTrim.add(iss.getDetails().getText()); 178 } 179 List<String> trimmed = new ArrayList<>(); 180 trimmed.addAll(messages); 181 trimmed.removeAll(toTrim); 182 if (trimmed.size() == 0) { 183 return null; 184 } 185 Collections.sort(trimmed); 186 return CommaSeparatedStringBuilder.join("; ", trimmed); 187 } 188 189 public boolean IsNoService() { 190 return errorClass == TerminologyServiceErrorClass.NOSERVICE; 191 } 192 193 public TerminologyServiceErrorClass getErrorClass() { 194 return errorClass; 195 } 196 197 public ValidationResult setSeverity(IssueSeverity severity) { 198 this.severity = severity; 199 return this; 200 } 201 202 public ValidationResult setMessage(String message) { 203 this.messages.clear(); 204 if (message != null) { 205 this.messages.add(message); 206 } 207 return this; 208 } 209 210 public ValidationResult addMessage(String message) { 211 if (message != null) { 212 this.messages.add(message); 213 } 214 return this; 215 } 216 217 public ValidationResult setErrorClass(TerminologyServiceErrorClass errorClass) { 218 this.errorClass = errorClass; 219 return this; 220 } 221 222 public String getTxLink() { 223 return txLink; 224 } 225 226 public ValidationResult setTxLink(String txLink) { 227 this.txLink = txLink; 228 return this; 229 } 230 231 public boolean hasMessage() { 232 return !messages.isEmpty(); 233 } 234 235 public String getDiagnostics() { 236 return diagnostics; 237 } 238 239 public void setDiagnostics(String diagnostics) { 240 this.diagnostics = diagnostics; 241 } 242 243 public Coding asCoding() { 244 if (isOk() && definition != null && definition.getCode() != null) { 245 return new Coding(system, definition.getCode(), definition.getDisplay()); 246 } else { 247 return null; 248 } 249 } 250 251 public List<OperationOutcomeIssueComponent> getIssues() { 252 return issues; 253 } 254 255 public ValidationResult addCodeableConcept(CodeableConcept vcc) { 256 if (!vcc.isEmpty()) { 257 codeableConcept = vcc; 258 } 259 return this; 260 } 261 262 public CodeableConcept getCodeableConcept() { 263 return codeableConcept; 264 } 265 266 public Set<String> getUnknownSystems() { 267 return unknownSystems; 268 } 269 270 public ValidationResult setUnknownSystems(Set<String> unknownSystems) { 271 this.unknownSystems = unknownSystems; 272 return this; 273 } 274 275 public String unknownSystems() { 276 if (unknownSystems == null) { 277 return null; 278 } 279 if (unknownSystems.size() == 1) { 280 return unknownSystems.iterator().next(); 281 } else { 282 return String.join(",", unknownSystems); 283 } 284 } 285 286 public void setIssues(List<OperationOutcomeIssueComponent> issues) { 287 if (this.issues != null) { 288 issues.addAll(this.issues); 289 } 290 this.issues = issues; 291 292 } 293 294 public void trimPath(String prefix) { 295 if (issues != null) { 296 for (OperationOutcomeIssueComponent iss : issues) { 297 for (int i = iss.getLocation().size() -1; i >= 0; i--) { 298 var s = iss.getLocation().get(i).primitiveValue(); 299 if (prefix.equals(s)) { 300 iss.getLocation().remove(i); 301 } else if (s.startsWith(prefix+".")) { 302 iss.getLocation().get(i).setValueAsString(s.substring(prefix.length()+1)); 303 } 304 } 305 for (int i = iss.getExpression().size() -1; i >= 0; i--) { 306 var s = iss.getExpression().get(i).primitiveValue(); 307 if (prefix.equals(s)) { 308 iss.getExpression().remove(i); 309 } else if (s.startsWith(prefix+".")) { 310 iss.getExpression().get(i).setValueAsString(s.substring(prefix.length()+1)); 311 } 312 } 313 } 314 } 315 316 } 317 318 public boolean isInactive() { 319 return inactive; 320 } 321 322 public String getStatus() { 323 return status; 324 } 325 326 public ValidationResult setStatus(boolean inactive, String status) { 327 this.inactive = inactive; 328 if (!"inactive".equals(status)) { 329 this.status = status; 330 } 331 return this; 332 } 333 334 public boolean messageIsInIssues() { 335 // the message is sometimes a summary of the issues that are already tracked. 336 // this returns true in that case, so that duplication of messages is suppressed 337 338 for (String s : messages) { 339 boolean found = false; 340 for (OperationOutcomeIssueComponent iss : issues) { 341 if (iss.getSeverity().ordinal() <= getSeverity().ordinal() && s.equals(iss.getDetails().getText())) { 342 found = true; 343 } 344 } 345 if (!found) { 346 return false; 347 } 348 } 349 return true; 350 } 351 352 public String getServer() { 353 return server; 354 } 355 356 public void setServer(String server) { 357 this.server = server; 358 } 359 360 public boolean equals(Object otherObject) { 361 if (!(otherObject instanceof ValidationResult)) { 362 return false; 363 } 364 365 ValidationResult other = (ValidationResult) otherObject; 366 if (!Objects.equals(this.system, other.system)) { 367 return false; 368 } 369 if (!Objects.equals(this.version, other.version)) { 370 return false; 371 } 372 if (!Objects.equals(this.preferredDisplay, other.preferredDisplay)) { 373 return false; 374 } 375 if (!Objects.equals(this.severity, other.severity)) { 376 return false; 377 } 378 if (!Objects.equals(this.definition, other.definition)) { 379 return false; 380 } 381 if (!Objects.equals(this.messages, other.messages)) { 382 return false; 383 } 384 if (!Objects.equals(this.errorClass, other.errorClass)) { 385 return false; 386 } 387 if (!Objects.equals(this.txLink, other.txLink)) { 388 return false; 389 } 390 if (!Objects.equals(this.diagnostics, other.diagnostics)) { 391 return false; 392 } 393 if (!Objects.equals(this.issues, other.issues)) { 394 return false; 395 } 396 if (!Objects.equals(this.codeableConcept, other.codeableConcept)) { 397 return false; 398 } 399 if (!Objects.equals(this.unknownSystems, other.unknownSystems)) { 400 return false; 401 } 402 if (this.inactive != other.inactive) { 403 return false; 404 } 405 if (!Objects.equals(this.status, other.status)) { 406 return false; 407 } 408 if (!Objects.equals(this.server, other.server)) { 409 return false; 410 } 411 return true; 412 } 413 414 public boolean isErrorIsDisplayIssue() { 415 return errorIsDisplayIssue; 416 } 417 418 public ValidationResult setErrorIsDisplayIssue(boolean errorIsDisplayIssue) { 419 this.errorIsDisplayIssue = errorIsDisplayIssue; 420 return this; 421 } 422 423 424}