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