001package org.hl7.fhir.r5.utils;
002
003import java.util.List;
004
005/*
006  Copyright (c) 2011+, HL7, Inc.
007  All rights reserved.
008  
009  Redistribution and use in source and binary forms, with or without modification, 
010  are permitted provided that the following conditions are met:
011    
012   * Redistributions of source code must retain the above copyright notice, this 
013     list of conditions and the following disclaimer.
014   * Redistributions in binary form must reproduce the above copyright notice, 
015     this list of conditions and the following disclaimer in the documentation 
016     and/or other materials provided with the distribution.
017   * Neither the name of HL7 nor the names of its contributors may be used to 
018     endorse or promote products derived from this software without specific 
019     prior written permission.
020  
021  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
022  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
023  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
024  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
025  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
026  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
027  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
028  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
029  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
030  POSSIBILITY OF SUCH DAMAGE.
031  
032 */
033
034
035
036import org.hl7.fhir.r5.model.CodeableConcept;
037import org.hl7.fhir.r5.model.IntegerType;
038import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
039import org.hl7.fhir.r5.model.OperationOutcome;
040import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity;
041import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
042import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
043import org.hl7.fhir.r5.model.StringType;
044import org.hl7.fhir.r5.model.UrlType;
045import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
046import org.hl7.fhir.utilities.validation.ValidationMessage;
047import org.hl7.fhir.utilities.xhtml.NodeType;
048import org.hl7.fhir.utilities.xhtml.XhtmlNode;
049
050public class OperationOutcomeUtilities {
051
052
053  public static OperationOutcomeIssueComponent convertToIssue(ValidationMessage message, OperationOutcome op) {
054    OperationOutcomeIssueComponent issue = new OperationOutcome.OperationOutcomeIssueComponent();
055    issue.setUserData("source.vm", message);   
056    issue.setCode(convert(message.getType()));
057    
058    if (message.getLocation() != null) {
059      // message location has a fhirPath in it. We need to populate the expression
060      issue.addExpression(message.getLocation());
061    }
062    // pass through line/col if they're present
063    if (message.getLine() >= 0) {
064      issue.addExtension().setUrl(ToolingExtensions.EXT_ISSUE_LINE).setValue(new IntegerType(message.getLine()));
065    }
066    if (message.getCol() >= 0) {
067      issue.addExtension().setUrl(ToolingExtensions.EXT_ISSUE_COL).setValue(new IntegerType(message.getCol()));
068    }
069    issue.setSeverity(convert(message.getLevel()));
070    CodeableConcept c = new CodeableConcept();
071    c.setText(message.getMessage());
072    issue.setDetails(c);
073    if (message.getSource() != null) {
074      issue.getExtension().add(ToolingExtensions.makeIssueSource(message.getSource()));
075    }
076    if (message.getMessageId() != null) {
077      issue.getExtension().add(ToolingExtensions.makeIssueMessageId(message.getMessageId()));
078    }
079    issue.setUserData("source.msg", message);
080    return issue;
081  }
082
083  public static IssueSeverity convert(org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity level) {
084    switch (level) {
085    case FATAL : return IssueSeverity.FATAL;
086    case ERROR : return IssueSeverity.ERROR;
087    case WARNING : return IssueSeverity.WARNING;
088    case INFORMATION : return IssueSeverity.INFORMATION;
089   case NULL : return IssueSeverity.NULL;
090    }
091    return IssueSeverity.NULL;
092  }
093
094  public static org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity convert(IssueSeverity level) {
095    switch (level) {
096    case FATAL : return org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.FATAL;
097    case ERROR : return org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.ERROR;
098    case WARNING : return org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.WARNING;
099    case INFORMATION : return org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.INFORMATION;
100   case NULL : return org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.NULL;
101    }
102    return org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.NULL;
103  }
104
105  private static IssueType convert(org.hl7.fhir.utilities.validation.ValidationMessage.IssueType type) {
106    switch (type) {
107    case INVALID: return IssueType.INVALID; 
108    case STRUCTURE: return IssueType.STRUCTURE;
109    case REQUIRED: return IssueType.REQUIRED;
110    case VALUE: return IssueType.VALUE;
111    case INVARIANT: return IssueType.INVARIANT;
112    case SECURITY: return IssueType.SECURITY;
113    case LOGIN: return IssueType.LOGIN;
114    case UNKNOWN: return IssueType.UNKNOWN;
115    case EXPIRED: return IssueType.EXPIRED;
116    case FORBIDDEN: return IssueType.FORBIDDEN;
117    case SUPPRESSED: return IssueType.SUPPRESSED;
118    case PROCESSING: return IssueType.PROCESSING;
119    case NOTSUPPORTED: return IssueType.NOTSUPPORTED;
120    case DUPLICATE: return IssueType.DUPLICATE;
121    case NOTFOUND: return IssueType.NOTFOUND;
122    case TOOLONG: return IssueType.TOOLONG;
123    case CODEINVALID: return IssueType.CODEINVALID;
124    case EXTENSION: return IssueType.EXTENSION;
125    case TOOCOSTLY: return IssueType.TOOCOSTLY;
126    case BUSINESSRULE: return IssueType.BUSINESSRULE;
127    case CONFLICT: return IssueType.CONFLICT;
128    case INCOMPLETE: return IssueType.INCOMPLETE;
129    case TRANSIENT: return IssueType.TRANSIENT;
130    case LOCKERROR: return IssueType.LOCKERROR;
131    case NOSTORE: return IssueType.NOSTORE;
132    case EXCEPTION: return IssueType.EXCEPTION;
133    case TIMEOUT: return IssueType.TIMEOUT;
134    case THROTTLED: return IssueType.THROTTLED;
135    case INFORMATIONAL: return IssueType.INFORMATIONAL;
136          case NULL: return IssueType.NULL;
137    case DELETED: return IssueType.DELETED;
138    case MULTIPLEMATCHES: return IssueType.MULTIPLEMATCHES;
139    default:
140      return IssueType.NULL;
141    }
142  }
143
144  public static OperationOutcome createOutcome(List<ValidationMessage> messages) {
145    OperationOutcome res = new OperationOutcome();
146    for (ValidationMessage vm : messages) {
147      res.addIssue(convertToIssue(vm, res));
148    }
149    return res;
150  }
151  
152
153  public static OperationOutcomeIssueComponent convertToIssueSimple(ValidationMessage message, OperationOutcome op) {
154    OperationOutcomeIssueComponent issue = new OperationOutcome.OperationOutcomeIssueComponent();
155    issue.setUserData("source.vm", message);   
156    issue.setCode(convert(message.getType()));
157    
158    if (message.getLocation() != null) {
159      // message location has a fhirPath in it. We need to populate the expression
160      issue.addExpression(message.getLocation());
161    }
162    if (message.getLine() >= 0 && message.getCol() >= 0) {
163      issue.setDiagnostics("["+message.getLine()+","+message.getCol()+"]");
164    }
165    issue.setSeverity(convert(message.getLevel()));
166    CodeableConcept c = new CodeableConcept();
167    c.setText(message.getMessage());
168    issue.setDetails(c);
169    if (message.sliceText != null) {
170      issue.addExtension(ToolingExtensions.EXT_ISSUE_SLICE_INFO, new StringType(CommaSeparatedStringBuilder.join("; ", message.sliceText)));
171    }
172    if (message.getServer() != null) {
173      issue.addExtension(ToolingExtensions.EXT_ISSUE_SERVER, new UrlType(message.getServer()));
174    }
175    return issue;
176  }
177
178  public static OperationOutcome createOutcomeSimple(List<ValidationMessage> messages) {
179    OperationOutcome res = new OperationOutcome();
180    for (ValidationMessage vm : messages) {
181      res.addIssue(convertToIssueSimple(vm, res));
182    }
183    return res;
184  }
185
186  public static OperationOutcome outcomeFromTextError(String text) {
187    OperationOutcome oo = new OperationOutcome();
188    oo.getText().setStatus(NarrativeStatus.GENERATED);
189    oo.getText().setDiv(new XhtmlNode(NodeType.Element, "div"));
190    oo.getText().getDiv().tx(text);
191    OperationOutcomeIssueComponent issue = oo.addIssue();
192    issue.setSeverity(IssueSeverity.ERROR);
193    issue.setCode(IssueType.EXCEPTION);
194    issue.getDetails().setText(text);
195    return oo;
196  }
197
198}