001package org.hl7.fhir.utilities.validation; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032 033 034/* 035 Copyright (c) 2011+, HL7, Inc 036 All rights reserved. 037 038 Redistribution and use in source and binary forms, with or without modification, 039 are permitted provided that the following conditions are met: 040 041 * Redistributions of source code must retain the above copyright notice, this 042 list of conditions and the following disclaimer. 043 * Redistributions in binary form must reproduce the above copyright notice, 044 this list of conditions and the following disclaimer in the documentation 045 and/or other materials provided with the distribution. 046 * Neither the name of HL7 nor the names of its contributors may be used to 047 endorse or promote products derived from this software without specific 048 prior written permission. 049 050 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 051 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 052 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 053 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 054 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 055 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 056 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 057 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 058 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 059 POSSIBILITY OF SUCH DAMAGE. 060 061 */ 062 063import java.util.Comparator; 064import java.util.EnumMap; 065 066import org.apache.commons.lang3.builder.ToStringBuilder; 067import org.apache.commons.lang3.builder.ToStringStyle; 068import org.hl7.fhir.exceptions.FHIRException; 069import org.hl7.fhir.utilities.Utilities; 070 071public class ValidationMessage implements Comparator<ValidationMessage>, Comparable<ValidationMessage> 072{ 073 public enum Source { 074 ExampleValidator, 075 ProfileValidator, 076 ResourceValidator, 077 InstanceValidator, 078 Template, 079 Schema, 080 Schematron, 081 Publisher, 082 LinkChecker, 083 Ontology, 084 ProfileComparer, 085 TerminologyEngine, 086 QuestionnaireResponseValidator 087 } 088 089 public enum IssueSeverity { 090 /** 091 * The issue caused the action to fail, and no further checking could be performed. 092 */ 093 FATAL, 094 /** 095 * The issue is sufficiently important to cause the action to fail. 096 */ 097 ERROR, 098 /** 099 * The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired. 100 */ 101 WARNING, 102 /** 103 * The issue has no relation to the degree of success of the action. 104 */ 105 INFORMATION, 106 /** 107 * added to help the parsers with the generic types 108 */ 109 NULL; 110 public static IssueSeverity fromCode(String codeString) throws FHIRException { 111 if (codeString == null || "".equals(codeString)) 112 return null; 113 if ("fatal".equals(codeString)) 114 return FATAL; 115 if ("error".equals(codeString)) 116 return ERROR; 117 if ("warning".equals(codeString)) 118 return WARNING; 119 if ("information".equals(codeString)) 120 return INFORMATION; 121 else 122 throw new FHIRException("Unknown IssueSeverity code '"+codeString+"'"); 123 } 124 public String toCode() { 125 switch (this) { 126 case FATAL: return "fatal"; 127 case ERROR: return "error"; 128 case WARNING: return "warning"; 129 case INFORMATION: return "information"; 130 case NULL: return null; 131 default: return "?"; 132 } 133 } 134 public String getSystem() { 135 switch (this) { 136 case FATAL: return "http://hl7.org/fhir/issue-severity"; 137 case ERROR: return "http://hl7.org/fhir/issue-severity"; 138 case WARNING: return "http://hl7.org/fhir/issue-severity"; 139 case INFORMATION: return "http://hl7.org/fhir/issue-severity"; 140 case NULL: return null; 141 default: return "?"; 142 } 143 } 144 public String getDefinition() { 145 switch (this) { 146 case FATAL: return "The issue caused the action to fail, and no further checking could be performed."; 147 case ERROR: return "The issue is sufficiently important to cause the action to fail."; 148 case WARNING: return "The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired."; 149 case INFORMATION: return "The issue has no relation to the degree of success of the action."; 150 case NULL: return null; 151 default: return "?"; 152 } 153 } 154 public String getDisplay() { 155 switch (this) { 156 case FATAL: return "Fatal"; 157 case ERROR: return "Error"; 158 case WARNING: return "Warning"; 159 case INFORMATION: return "Information"; 160 case NULL: return null; 161 default: return "?"; 162 } 163 } 164 public boolean isError() { 165 return this == FATAL || this == ERROR; 166 } 167 public boolean isHint() { 168 return this == INFORMATION; 169 } 170 } 171 172 public enum IssueType { 173 /** 174 * Content invalid against the specification or a profile. 175 */ 176 INVALID, 177 DELETED, 178 /** 179 * A structural issue in the content such as wrong namespace, or unable to parse the content completely, or invalid json syntax. 180 */ 181 STRUCTURE, 182 /** 183 * A required element is missing. 184 */ 185 REQUIRED, 186 /** 187 * An element value is invalid. 188 */ 189 VALUE, 190 /** 191 * A content validation rule failed - e.g. a schematron rule. 192 */ 193 INVARIANT, 194 /** 195 * An authentication/authorization/permissions issue of some kind. 196 */ 197 SECURITY, 198 /** 199 * The client needs to initiate an authentication process. 200 */ 201 LOGIN, 202 /** 203 * The user or system was not able to be authenticated (either there is no process, or the proferred token is unacceptable). 204 */ 205 MULTIPLEMATCHES, 206 UNKNOWN, 207 /** 208 * User session expired; a login may be required. 209 */ 210 EXPIRED, 211 /** 212 * The user does not have the rights to perform this action. 213 */ 214 FORBIDDEN, 215 /** 216 * Some information was not or may not have been returned due to business rules, consent or privacy rules, or access permission constraints. This information may be accessible through alternate processes. 217 */ 218 SUPPRESSED, 219 /** 220 * Processing issues. These are expected to be final e.g. there is no point resubmitting the same content unchanged. 221 */ 222 PROCESSING, 223 /** 224 * The resource or profile is not supported. 225 */ 226 NOTSUPPORTED, 227 /** 228 * An attempt was made to create a duplicate record. 229 */ 230 DUPLICATE, 231 /** 232 * The reference provided was not found. In a pure RESTful environment, this would be an HTTP 404 error, but this code may be used where the content is not found further into the application architecture. 233 */ 234 NOTFOUND, 235 /** 236 * Provided content is too long (typically, this is a denial of service protection type of error). 237 */ 238 TOOLONG, 239 /** 240 * The code or system could not be understood, or it was not valid in the context of a particular ValueSet.code. 241 */ 242 CODEINVALID, 243 /** 244 * An extension was found that was not acceptable, could not be resolved, or a modifierExtension was not recognized. 245 */ 246 EXTENSION, 247 /** 248 * The operation was stopped to protect server resources; e.g. a request for a value set expansion on all of SNOMED CT. 249 */ 250 TOOCOSTLY, 251 /** 252 * The content/operation failed to pass some business rule, and so could not proceed. 253 */ 254 BUSINESSRULE, 255 /** 256 * Content could not be accepted because of an edit conflict (i.e. version aware updates) (In a pure RESTful environment, this would be an HTTP 404 error, but this code may be used where the conflict is discovered further into the application architecture.) 257 */ 258 CONFLICT, 259 /** 260 * Not all data sources typically accessed could be reached, or responded in time, so the returned information may not be complete. 261 */ 262 INCOMPLETE, 263 /** 264 * Transient processing issues. The system receiving the error may be able to resubmit the same content once an underlying issue is resolved. 265 */ 266 TRANSIENT, 267 /** 268 * A resource/record locking failure (usually in an underlying database). 269 */ 270 LOCKERROR, 271 /** 272 * The persistent store is unavailable; e.g. the database is down for maintenance or similar action. 273 */ 274 NOSTORE, 275 /** 276 * An unexpected internal error has occurred. 277 */ 278 EXCEPTION, 279 /** 280 * An internal timeout has occurred. 281 */ 282 TIMEOUT, 283 /** 284 * The system is not prepared to handle this request due to load management. 285 */ 286 THROTTLED, 287 /** 288 * A message unrelated to the processing success of the completed operation (examples of the latter include things like reminders of password expiry, system maintenance times, etc.). 289 */ 290 INFORMATIONAL, 291 /** 292 * added to help the parsers with the generic types 293 */ 294 NULL; 295 public static IssueType fromCode(String codeString) throws FHIRException { 296 if (codeString == null || "".equals(codeString)) 297 return null; 298 if ("invalid".equals(codeString)) 299 return INVALID; 300 if ("structure".equals(codeString)) 301 return STRUCTURE; 302 if ("required".equals(codeString)) 303 return REQUIRED; 304 if ("value".equals(codeString)) 305 return VALUE; 306 if ("invariant".equals(codeString)) 307 return INVARIANT; 308 if ("security".equals(codeString)) 309 return SECURITY; 310 if ("login".equals(codeString)) 311 return LOGIN; 312 if ("unknown".equals(codeString)) 313 return UNKNOWN; 314 if ("expired".equals(codeString)) 315 return EXPIRED; 316 if ("forbidden".equals(codeString)) 317 return FORBIDDEN; 318 if ("suppressed".equals(codeString)) 319 return SUPPRESSED; 320 if ("processing".equals(codeString)) 321 return PROCESSING; 322 if ("not-supported".equals(codeString)) 323 return NOTSUPPORTED; 324 if ("duplicate".equals(codeString)) 325 return DUPLICATE; 326 if ("not-found".equals(codeString)) 327 return NOTFOUND; 328 if ("too-long".equals(codeString)) 329 return TOOLONG; 330 if ("code-invalid".equals(codeString)) 331 return CODEINVALID; 332 if ("extension".equals(codeString)) 333 return EXTENSION; 334 if ("too-costly".equals(codeString)) 335 return TOOCOSTLY; 336 if ("business-rule".equals(codeString)) 337 return BUSINESSRULE; 338 if ("conflict".equals(codeString)) 339 return CONFLICT; 340 if ("incomplete".equals(codeString)) 341 return INCOMPLETE; 342 if ("transient".equals(codeString)) 343 return TRANSIENT; 344 if ("lock-error".equals(codeString)) 345 return LOCKERROR; 346 if ("no-store".equals(codeString)) 347 return NOSTORE; 348 if ("exception".equals(codeString)) 349 return EXCEPTION; 350 if ("timeout".equals(codeString)) 351 return TIMEOUT; 352 if ("throttled".equals(codeString)) 353 return THROTTLED; 354 if ("informational".equals(codeString)) 355 return INFORMATIONAL; 356 else 357 throw new FHIRException("Unknown IssueType code '"+codeString+"'"); 358 } 359 public String toCode() { 360 switch (this) { 361 case INVALID: return "invalid"; 362 case STRUCTURE: return "structure"; 363 case REQUIRED: return "required"; 364 case VALUE: return "value"; 365 case INVARIANT: return "invariant"; 366 case SECURITY: return "security"; 367 case LOGIN: return "login"; 368 case UNKNOWN: return "unknown"; 369 case EXPIRED: return "expired"; 370 case FORBIDDEN: return "forbidden"; 371 case SUPPRESSED: return "suppressed"; 372 case PROCESSING: return "processing"; 373 case NOTSUPPORTED: return "not-supported"; 374 case DUPLICATE: return "duplicate"; 375 case NOTFOUND: return "not-found"; 376 case TOOLONG: return "too-long"; 377 case CODEINVALID: return "code-invalid"; 378 case EXTENSION: return "extension"; 379 case TOOCOSTLY: return "too-costly"; 380 case BUSINESSRULE: return "business-rule"; 381 case CONFLICT: return "conflict"; 382 case INCOMPLETE: return "incomplete"; 383 case TRANSIENT: return "transient"; 384 case LOCKERROR: return "lock-error"; 385 case NOSTORE: return "no-store"; 386 case EXCEPTION: return "exception"; 387 case TIMEOUT: return "timeout"; 388 case THROTTLED: return "throttled"; 389 case INFORMATIONAL: return "informational"; 390 case NULL: return null; 391 default: return "?"; 392 } 393 } 394 public String getSystem() { 395 switch (this) { 396 case INVALID: return "http://hl7.org/fhir/issue-type"; 397 case STRUCTURE: return "http://hl7.org/fhir/issue-type"; 398 case REQUIRED: return "http://hl7.org/fhir/issue-type"; 399 case VALUE: return "http://hl7.org/fhir/issue-type"; 400 case INVARIANT: return "http://hl7.org/fhir/issue-type"; 401 case SECURITY: return "http://hl7.org/fhir/issue-type"; 402 case LOGIN: return "http://hl7.org/fhir/issue-type"; 403 case UNKNOWN: return "http://hl7.org/fhir/issue-type"; 404 case EXPIRED: return "http://hl7.org/fhir/issue-type"; 405 case FORBIDDEN: return "http://hl7.org/fhir/issue-type"; 406 case SUPPRESSED: return "http://hl7.org/fhir/issue-type"; 407 case PROCESSING: return "http://hl7.org/fhir/issue-type"; 408 case NOTSUPPORTED: return "http://hl7.org/fhir/issue-type"; 409 case DUPLICATE: return "http://hl7.org/fhir/issue-type"; 410 case NOTFOUND: return "http://hl7.org/fhir/issue-type"; 411 case TOOLONG: return "http://hl7.org/fhir/issue-type"; 412 case CODEINVALID: return "http://hl7.org/fhir/issue-type"; 413 case EXTENSION: return "http://hl7.org/fhir/issue-type"; 414 case TOOCOSTLY: return "http://hl7.org/fhir/issue-type"; 415 case BUSINESSRULE: return "http://hl7.org/fhir/issue-type"; 416 case CONFLICT: return "http://hl7.org/fhir/issue-type"; 417 case INCOMPLETE: return "http://hl7.org/fhir/issue-type"; 418 case TRANSIENT: return "http://hl7.org/fhir/issue-type"; 419 case LOCKERROR: return "http://hl7.org/fhir/issue-type"; 420 case NOSTORE: return "http://hl7.org/fhir/issue-type"; 421 case EXCEPTION: return "http://hl7.org/fhir/issue-type"; 422 case TIMEOUT: return "http://hl7.org/fhir/issue-type"; 423 case THROTTLED: return "http://hl7.org/fhir/issue-type"; 424 case INFORMATIONAL: return "http://hl7.org/fhir/issue-type"; 425 case NULL: return null; 426 default: return "?"; 427 } 428 } 429 public String getDefinition() { 430 switch (this) { 431 case INVALID: return "Content invalid against the specification or a profile."; 432 case STRUCTURE: return "A structural issue in the content such as wrong namespace, or unable to parse the content completely, or invalid json syntax."; 433 case REQUIRED: return "A required element is missing."; 434 case VALUE: return "An element value is invalid."; 435 case INVARIANT: return "A content validation rule failed - e.g. a schematron rule."; 436 case SECURITY: return "An authentication/authorization/permissions issue of some kind."; 437 case LOGIN: return "The client needs to initiate an authentication process."; 438 case UNKNOWN: return "The user or system was not able to be authenticated (either there is no process, or the proferred token is unacceptable)."; 439 case EXPIRED: return "User session expired; a login may be required."; 440 case FORBIDDEN: return "The user does not have the rights to perform this action."; 441 case SUPPRESSED: return "Some information was not or may not have been returned due to business rules, consent or privacy rules, or access permission constraints. This information may be accessible through alternate processes."; 442 case PROCESSING: return "Processing issues. These are expected to be final e.g. there is no point resubmitting the same content unchanged."; 443 case NOTSUPPORTED: return "The resource or profile is not supported."; 444 case DUPLICATE: return "An attempt was made to create a duplicate record."; 445 case NOTFOUND: return "The reference provided was not found. In a pure RESTful environment, this would be an HTTP 404 error, but this code may be used where the content is not found further into the application architecture."; 446 case TOOLONG: return "Provided content is too long (typically, this is a denial of service protection type of error)."; 447 case CODEINVALID: return "The code or system could not be understood, or it was not valid in the context of a particular ValueSet.code."; 448 case EXTENSION: return "An extension was found that was not acceptable, could not be resolved, or a modifierExtension was not recognized."; 449 case TOOCOSTLY: return "The operation was stopped to protect server resources; e.g. a request for a value set expansion on all of SNOMED CT."; 450 case BUSINESSRULE: return "The content/operation failed to pass some business rule, and so could not proceed."; 451 case CONFLICT: return "Content could not be accepted because of an edit conflict (i.e. version aware updates) (In a pure RESTful environment, this would be an HTTP 404 error, but this code may be used where the conflict is discovered further into the application architecture.)"; 452 case INCOMPLETE: return "Not all data sources typically accessed could be reached, or responded in time, so the returned information may not be complete."; 453 case TRANSIENT: return "Transient processing issues. The system receiving the error may be able to resubmit the same content once an underlying issue is resolved."; 454 case LOCKERROR: return "A resource/record locking failure (usually in an underlying database)."; 455 case NOSTORE: return "The persistent store is unavailable; e.g. the database is down for maintenance or similar action."; 456 case EXCEPTION: return "An unexpected internal error has occurred."; 457 case TIMEOUT: return "An internal timeout has occurred."; 458 case THROTTLED: return "The system is not prepared to handle this request due to load management."; 459 case INFORMATIONAL: return "A message unrelated to the processing success of the completed operation (examples of the latter include things like reminders of password expiry, system maintenance times, etc.)."; 460 case NULL: return null; 461 default: return "?"; 462 } 463 } 464 public String getDisplay() { 465 switch (this) { 466 case INVALID: return "Invalid Content"; 467 case STRUCTURE: return "Structural Issue"; 468 case REQUIRED: return "Required element missing"; 469 case VALUE: return "Element value invalid"; 470 case INVARIANT: return "Validation rule failed"; 471 case SECURITY: return "Security Problem"; 472 case LOGIN: return "Login Required"; 473 case UNKNOWN: return "Unknown User"; 474 case EXPIRED: return "Session Expired"; 475 case FORBIDDEN: return "Forbidden"; 476 case SUPPRESSED: return "Information Suppressed"; 477 case PROCESSING: return "Processing Failure"; 478 case NOTSUPPORTED: return "Content not supported"; 479 case DUPLICATE: return "Duplicate"; 480 case NOTFOUND: return "Not Found"; 481 case TOOLONG: return "Content Too Long"; 482 case CODEINVALID: return "Invalid Code"; 483 case EXTENSION: return "Unacceptable Extension"; 484 case TOOCOSTLY: return "Operation Too Costly"; 485 case BUSINESSRULE: return "Business Rule Violation"; 486 case CONFLICT: return "Edit Version Conflict"; 487 case INCOMPLETE: return "Incomplete Results"; 488 case TRANSIENT: return "Transient Issue"; 489 case LOCKERROR: return "Lock Error"; 490 case NOSTORE: return "No Store Available"; 491 case EXCEPTION: return "Exception"; 492 case TIMEOUT: return "Timeout"; 493 case THROTTLED: return "Throttled"; 494 case INFORMATIONAL: return "Informational Note"; 495 case NULL: return null; 496 default: return "?"; 497 } 498 } 499 } 500 501 502 private Source source; 503 private int line; 504 private int col; 505 private String location; // fhirPath 506 private String message; 507 private String messageId; // source, for grouping 508 private IssueType type; 509 private IssueSeverity level; 510 private String html; 511 private String locationLink; 512 private String txLink; 513 public String sliceHtml; 514 public String[] sliceText; 515 private boolean slicingHint; 516 private boolean signpost; 517 private boolean criticalSignpost; 518 519 520 /** 521 * Constructor 522 */ 523 public ValidationMessage() { 524 // nothing 525 } 526 527 public ValidationMessage(Source source, IssueType type, String path, String message, IssueSeverity level) { 528 super(); 529 this.line = -1; 530 this.col = -1; 531 this.location = path; 532 if (message == null) 533 throw new Error("message is null"); 534 this.message = message; 535 this.html = Utilities.escapeXml(message); 536 this.level = level; 537 this.source = source; 538 this.type = type; 539 if (level == IssueSeverity.NULL) 540 determineLevel(path); 541 if (type == null) 542 throw new Error("A type must be provided"); 543 } 544 545 public ValidationMessage(Source source, IssueType type, int line, int col, String path, String message, IssueSeverity level) { 546 super(); 547 this.line = line; 548 this.col = col; 549 this.location = path; 550 this.message = message; 551 this.html = Utilities.escapeXml(message); 552 this.level = level; 553 this.source = source; 554 this.type = type; 555 if (level == IssueSeverity.NULL) 556 determineLevel(path); 557 if (type == null) 558 throw new Error("A type must be provided"); 559 } 560 561 public ValidationMessage(Source source, IssueType type, String path, String message, String html, IssueSeverity level) { 562 super(); 563 this.line = -1; 564 this.col = -1; 565 this.location = path; 566 if (message == null) 567 throw new Error("message is null"); 568 this.message = message; 569 this.html = html; 570 this.level = level; 571 this.source = source; 572 this.type = type; 573 if (level == IssueSeverity.NULL) 574 determineLevel(path); 575 if (type == null) 576 throw new Error("A type must be provided"); 577 } 578 579 public ValidationMessage(Source source, IssueType type, int line, int col, String path, String message, String html, IssueSeverity level) { 580 super(); 581 this.line = line; 582 this.col = col; 583 this.location = path; 584 if (message == null) 585 throw new Error("message is null"); 586 this.message = message; 587 this.html = html; 588 this.level = level; 589 this.source = source; 590 this.type = type; 591 if (level == IssueSeverity.NULL) 592 determineLevel(path); 593 if (type == null) 594 throw new Error("A type must be provided"); 595 } 596 597 private IssueSeverity determineLevel(String path) { 598 if (isGrandfathered(path)) 599 return IssueSeverity.WARNING; 600 else 601 return IssueSeverity.ERROR; 602 } 603 604 private boolean isGrandfathered(String path) { 605 if (path.startsWith("xds-documentmanifest.")) 606 return true; 607 if (path.startsWith("observation-device-metric-devicemetricobservation.")) 608 return true; 609 if (path.startsWith("medicationadministration-immunization-vaccine.")) 610 return true; 611 if (path.startsWith("elementdefinition-de-dataelement.")) 612 return true; 613 if (path.startsWith("dataelement-sdc-sdcelement.")) 614 return true; 615 if (path.startsWith("questionnaireresponse-sdc-structureddatacaptureanswers.")) 616 return true; 617 if (path.startsWith("valueset-sdc-structureddatacapturevalueset.")) 618 return true; 619 if (path.startsWith("dataelement-sdc-de-sdcelement.")) 620 return true; 621 if (path.startsWith("do-uslab-uslabdo.")) 622 return true; 623 if (path.startsWith(".")) 624 return true; 625 if (path.startsWith(".")) 626 return true; 627 if (path.startsWith(".")) 628 return true; 629 if (path.startsWith(".")) 630 return true; 631 632 return false; 633 } 634 635 public String getMessage() { 636 return message; 637 } 638 public ValidationMessage setMessage(String message) { 639 this.message = message; 640 return this; 641 } 642 643 public IssueSeverity getLevel() { 644 return level; 645 } 646 public ValidationMessage setLevel(IssueSeverity level) { 647 this.level = level; 648 return this; 649 } 650 651 public Source getSource() { 652 return source; 653 } 654 public ValidationMessage setSource(Source source) { 655 this.source = source; 656 return this; 657 } 658 659 public int getLine() { 660 return line; 661 } 662 663 public void setLine(int theLine) { 664 line = theLine; 665 } 666 667 public int getCol() { 668 return col; 669 } 670 671 public void setCol(int theCol) { 672 col = theCol; 673 } 674 675 public String getLocation() { 676 return location; 677 } 678 public ValidationMessage setLocation(String location) { 679 this.location = location; 680 return this; 681 } 682 683 public IssueType getType() { 684 return type; 685 } 686 687 public ValidationMessage setType(IssueType type) { 688 this.type = type; 689 return this; 690 } 691 692 public String summary() { 693 return level.toString()+" @ "+location+(line>= 0 && col >= 0 ? " (line "+Integer.toString(line)+", col"+Integer.toString(col)+"): " : ": ") +message +(source != null ? " (src = "+source+")" : ""); 694 } 695 696 697 public String toXML() { 698 return "<message source=\"" + source + "\" line=\"" + line + "\" col=\"" + col + "\" location=\"" + Utilities.escapeXml(location) + "\" type=\"" + type + "\" level=\"" + level + "\" display=\"" + Utilities.escapeXml(getDisplay()) + "\" ><plain>" + Utilities.escapeXml(message) + "</plain><html>" + html + "</html></message>"; 699 } 700 701 public String getHtml() { 702 return html == null ? Utilities.escapeXml(message) : html; 703 } 704 705 public String getDisplay() { 706 return level + ": " + (location==null || location.isEmpty() ? "" : (location + ": ")) + message; 707 } 708 709 /** 710 * Returns a representation of this ValidationMessage suitable for logging. The values of 711 * most of the internal fields are included, so this may not be suitable for display to 712 * an end user. 713 */ 714 @Override 715 public String toString() { 716 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 717 b.append("level", level); 718 b.append("type", type); 719 b.append("location", location); 720 b.append("message", message); 721 return b.build(); 722 } 723 724 @Override 725 public boolean equals(Object o) { 726 return (this.getMessage() != null && this.getMessage().equals(((ValidationMessage)o).getMessage())) && (this.getLocation() != null && this.getLocation().equals(((ValidationMessage)o).getLocation())); 727 } 728 729 @Override 730 public int compare(ValidationMessage x, ValidationMessage y) { 731 String sx = x.getLevel().getDisplay() + x.getType().getDisplay() + String.format("%06d", x.getLine()) + x.getMessage(); 732 String sy = y.getLevel().getDisplay() + y.getType().getDisplay() + String.format("%06d", y.getLine()) + y.getMessage(); 733 return sx.compareTo(sy); 734 } 735 736 @Override 737 public int compareTo(ValidationMessage y) { 738 return compare(this, y); 739 } 740 741 public String getLocationLink() { 742 return locationLink; 743 } 744 745 public ValidationMessage setLocationLink(String locationLink) { 746 this.locationLink = locationLink; 747 return this; 748 } 749 750 public String getTxLink() { 751 return txLink; 752 } 753 754 public ValidationMessage setTxLink(String txLink) { 755 this.txLink = txLink; 756 return this; 757 } 758 759 public void setHtml(String html) { 760 this.html = html; 761 } 762 763 public boolean isSlicingHint() { 764 return slicingHint; 765 } 766 767 public ValidationMessage setSlicingHint(boolean slicingHint) { 768 this.slicingHint = slicingHint; 769 return this; 770 } 771 772 public String getSliceHtml() { 773 return sliceHtml; 774 } 775 776 public ValidationMessage setSliceHtml(String sliceHtml, String[] text) { 777 this.sliceHtml = sliceHtml; 778 this.sliceText = text; 779 return this; 780 } 781 782 public String getMessageId() { 783 return messageId; 784 } 785 786 public ValidationMessage setMessageId(String messageId) { 787 this.messageId = messageId; 788 return this; 789 } 790 791 public boolean isSignpost() { 792 return signpost; 793 } 794 795 public ValidationMessage setSignpost(boolean signpost) { 796 this.signpost = signpost; 797 return this; 798 } 799 800 public boolean isCriticalSignpost() { 801 return criticalSignpost; 802 } 803 804 public ValidationMessage setCriticalSignpost(boolean criticalSignpost) { 805 this.criticalSignpost = criticalSignpost; 806 return this; 807 } 808 809 810}