001package ca.uhn.fhir.validation;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2016 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.server.interceptor.ExceptionHandlingInterceptor;
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                        b.append(myMessages.get(0).getMessage());
078                        b.append(" - ");
079                        b.append(myMessages.get(0).getLocationString());
080                } else {
081                        b.append("No issues");
082                }
083                return b.toString();
084        }
085
086        /**
087         * @deprecated Use {@link #toOperationOutcome()} instead since this method returns a view.
088         *             {@link #toOperationOutcome()} is identical to this method, but has a more suitable name so this method
089         *             will be removed at some point.
090         */
091        @Deprecated
092        public IBaseOperationOutcome getOperationOutcome() {
093                return toOperationOutcome();
094        }
095
096        /**
097         * Create an OperationOutcome resource which contains all of the messages found as a result of this validation
098         */
099        public IBaseOperationOutcome toOperationOutcome() {
100                IBaseOperationOutcome oo = (IBaseOperationOutcome) myCtx.getResourceDefinition("OperationOutcome").newInstance();
101                for (SingleValidationMessage next : myMessages) {
102                        String location;
103                        if (isNotBlank(next.getLocationString())) {
104                                location = next.getLocationString();
105                        } else if (next.getLocationLine() != null || next.getLocationCol() != null) {
106                                location = "Line[" + next.getLocationLine() + "] Col[" + next.getLocationCol() + "]";
107                        } else {
108                                location = null;
109                        }
110                        String severity = next.getSeverity() != null ? next.getSeverity().getCode() : null;
111                        OperationOutcomeUtil.addIssue(myCtx, oo, severity, next.getMessage(), location, ExceptionHandlingInterceptor.PROCESSING);
112                }
113
114                if (myMessages.isEmpty()) {
115                        String message = myCtx.getLocalizer().getMessage(ValidationResult.class, "noIssuesDetected");
116                        OperationOutcomeUtil.addIssue(myCtx, oo, "information", message, null, "informational");
117                }
118
119                return oo;
120        }
121
122        @Override
123        public String toString() {
124                return "ValidationResult{" + "messageCount=" + myMessages.size() + ", isSuccessful=" + myIsSuccessful + ", description='" + toDescription() + '\'' + '}';
125        }
126}