001package ca.uhn.fhir.validation; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2017 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import static org.apache.commons.lang3.StringUtils.isNotBlank; 024 025import java.util.Collections; 026import java.util.List; 027 028import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; 029 030import ca.uhn.fhir.context.FhirContext; 031import ca.uhn.fhir.rest.api.Constants; 032import ca.uhn.fhir.util.OperationOutcomeUtil; 033 034/** 035 * Encapsulates the results of validation 036 * 037 * @see ca.uhn.fhir.validation.FhirValidator 038 * @since 0.7 039 */ 040public class ValidationResult { 041 private final FhirContext myCtx; 042 private final boolean myIsSuccessful; 043 private final List<SingleValidationMessage> myMessages; 044 045 public ValidationResult(FhirContext theCtx, List<SingleValidationMessage> theMessages) { 046 boolean successful = true; 047 myCtx = theCtx; 048 myMessages = theMessages; 049 for (SingleValidationMessage next : myMessages) { 050 next.getSeverity(); 051 if (next.getSeverity() == null || next.getSeverity().ordinal() > ResultSeverityEnum.WARNING.ordinal()) { 052 successful = false; 053 } 054 } 055 myIsSuccessful = successful; 056 } 057 058 public List<SingleValidationMessage> getMessages() { 059 return Collections.unmodifiableList(myMessages); 060 } 061 062 /** 063 * Was the validation successful (in other words, do we have no issues that are at 064 * severity {@link ResultSeverityEnum#ERROR} or {@link ResultSeverityEnum#FATAL}. A validation 065 * is still considered successful if it only has issues at level {@link ResultSeverityEnum#WARNING} or 066 * lower. 067 * 068 * @return true if the validation was successful 069 */ 070 public boolean isSuccessful() { 071 return myIsSuccessful; 072 } 073 074 private String toDescription() { 075 StringBuilder b = new StringBuilder(100); 076 if (myMessages.size() > 0) { 077 if (myMessages.get(0).getSeverity() != null) { 078 b.append(myMessages.get(0).getSeverity().name()); 079 b.append(" - "); 080 } 081 b.append(myMessages.get(0).getMessage()); 082 b.append(" - "); 083 b.append(myMessages.get(0).getLocationString()); 084 } else { 085 b.append("No issues"); 086 } 087 return b.toString(); 088 } 089 090 /** 091 * @deprecated Use {@link #toOperationOutcome()} instead since this method returns a view. 092 * {@link #toOperationOutcome()} is identical to this method, but has a more suitable name so this method 093 * will be removed at some point. 094 */ 095 @Deprecated 096 public IBaseOperationOutcome getOperationOutcome() { 097 return toOperationOutcome(); 098 } 099 100 /** 101 * Create an OperationOutcome resource which contains all of the messages found as a result of this validation 102 */ 103 public IBaseOperationOutcome toOperationOutcome() { 104 IBaseOperationOutcome oo = (IBaseOperationOutcome) myCtx.getResourceDefinition("OperationOutcome").newInstance(); 105 populateOperationOutcome(oo); 106 return oo; 107 } 108 109 /** 110 * Populate an operation outcome with the results of the validation 111 */ 112 public void populateOperationOutcome(IBaseOperationOutcome theOperationOutcome) { 113 for (SingleValidationMessage next : myMessages) { 114 String location; 115 if (isNotBlank(next.getLocationString())) { 116 location = next.getLocationString(); 117 } else if (next.getLocationLine() != null || next.getLocationCol() != null) { 118 location = "Line[" + next.getLocationLine() + "] Col[" + next.getLocationCol() + "]"; 119 } else { 120 location = null; 121 } 122 String severity = next.getSeverity() != null ? next.getSeverity().getCode() : null; 123 OperationOutcomeUtil.addIssue(myCtx, theOperationOutcome, severity, next.getMessage(), location, Constants.OO_INFOSTATUS_PROCESSING); 124 } 125 126 if (myMessages.isEmpty()) { 127 String message = myCtx.getLocalizer().getMessage(ValidationResult.class, "noIssuesDetected"); 128 OperationOutcomeUtil.addIssue(myCtx, theOperationOutcome, "information", message, null, "informational"); 129 } 130 } 131 132 @Override 133 public String toString() { 134 return "ValidationResult{" + "messageCount=" + myMessages.size() + ", isSuccessful=" + myIsSuccessful + ", description='" + toDescription() + '\'' + '}'; 135 } 136}