View Javadoc
1   package ca.uhn.fhir.parser;
2   
3   import static org.apache.commons.lang3.StringUtils.isBlank;
4   
5   import ca.uhn.fhir.context.FhirContext;
6   import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
7   import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
8   
9   /*
10   * #%L
11   * HAPI FHIR - Core Library
12   * %%
13   * Copyright (C) 2014 - 2018 University Health Network
14   * %%
15   * Licensed under the Apache License, Version 2.0 (the "License");
16   * you may not use this file except in compliance with the License.
17   * You may obtain a copy of the License at
18   * 
19   * http://www.apache.org/licenses/LICENSE-2.0
20   * 
21   * Unless required by applicable law or agreed to in writing, software
22   * distributed under the License is distributed on an "AS IS" BASIS,
23   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24   * See the License for the specific language governing permissions and
25   * limitations under the License.
26   * #L%
27   */
28  
29  /**
30   * The default error handler, which logs issues but does not abort parsing, with only one exception:
31   * <p>
32   * The {@link #invalidValue(ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation, String, String)}
33   * method will throw a {@link DataFormatException} by default since ignoring this type of error
34   * can lead to data loss (since invalid values are silently ignored). See
35   * {@link #setErrorOnInvalidValue(boolean)} for information on this.
36   * </p>
37   * 
38   * @see IParser#setParserErrorHandler(IParserErrorHandler)
39   * @see FhirContext#setParserErrorHandler(IParserErrorHandler)
40   */
41  public class LenientErrorHandler implements IParserErrorHandler {
42  
43  	private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LenientErrorHandler.class);
44  	private static final StrictErrorHandler STRICT_ERROR_HANDLER = new StrictErrorHandler();
45  	private boolean myErrorOnInvalidValue = true;
46  	private boolean myLogErrors;
47  
48  	/**
49  	 * Constructor which configures this handler to log all errors
50  	 */
51  	public LenientErrorHandler() {
52  		myLogErrors = true;
53  	}
54  
55  	/**
56  	 * Constructor
57  	 * 
58  	 * @param theLogErrors
59  	 *           Should errors be logged?
60  	 * @since 1.2
61  	 */
62  	public LenientErrorHandler(boolean theLogErrors) {
63  		myLogErrors = theLogErrors;
64  	}
65  
66  	@Override
67  	public void containedResourceWithNoId(IParseLocation theLocation) {
68  		if (myLogErrors) {
69  			ourLog.warn("Resource has contained child resource with no ID");
70  		}
71  	}
72  
73  	@Override
74  	public void incorrectJsonType(IParseLocation theLocation, String theElementName, ValueType theExpected, ScalarType theExpectedScalarType, ValueType theFound, ScalarType theFoundScalarType) {
75  		if (myLogErrors) {
76  			if (ourLog.isWarnEnabled()) {
77  				String message = createIncorrectJsonTypeMessage(theElementName, theExpected, theExpectedScalarType, theFound, theFoundScalarType);
78  				ourLog.warn(message);
79  			}
80  		}
81  	}
82  
83  	@Override
84  	public void invalidValue(IParseLocation theLocation, String theValue, String theError) {
85  		if (isBlank(theValue) || myErrorOnInvalidValue == false) {
86  			if (myLogErrors) {
87  				ourLog.warn("Invalid attribute value \"{}\": {}", theValue, theError);
88  			}
89  		} else {
90  			STRICT_ERROR_HANDLER.invalidValue(theLocation, theValue, theError);
91  		}
92  	}
93  
94  	/**
95  	 * If set to <code>false</code> (default is <code>true</code>) invalid values will be logged. By
96  	 * default invalid attribute values cause this error handler to throw a {@link DataFormatException} (unlike
97  	 * other methods in this class which default to simply logging errors).
98  	 * <p>
99  	 * Note that empty values (e.g. <code>""</code>) will not lead to an error when this is set to
100 	 * <code>true</code>, only invalid values (e.g. a gender code of <code>foo</code>)
101 	 * </p>
102 	 * 
103 	 * @see #setErrorOnInvalidValue(boolean)
104 	 */
105 	public boolean isErrorOnInvalidValue() {
106 		return myErrorOnInvalidValue;
107 	}
108 
109 	@Override
110 	public void missingRequiredElement(IParseLocation theLocation, String theElementName) {
111 		if (myLogErrors) {
112 			ourLog.warn("Resource is missing required element: {}", theElementName);
113 		}
114 	}
115 
116 	/**
117 	 * If set to <code>false</code> (default is <code>true</code>) invalid values will be logged. By
118 	 * default invalid attribute values cause this error handler to throw a {@link DataFormatException} (unlike
119 	 * other methods in this class which default to simply logging errors).
120 	 * <p>
121 	 * Note that empty values (e.g. <code>""</code>) will not lead to an error when this is set to
122 	 * <code>true</code>, only invalid values (e.g. a gender code of <code>foo</code>)
123 	 * </p>
124 	 * 
125 	 * @return Returns a reference to <code>this</code> for easy method chaining
126 	 * @see #isErrorOnInvalidValue()
127 	 */
128 	public LenientErrorHandler setErrorOnInvalidValue(boolean theErrorOnInvalidValue) {
129 		myErrorOnInvalidValue = theErrorOnInvalidValue;
130 		return this;
131 	}
132 
133 	@Override
134 	public void unexpectedRepeatingElement(IParseLocation theLocation, String theElementName) {
135 		if (myLogErrors) {
136 			ourLog.warn("Multiple repetitions of non-repeatable element '{}' found while parsing", theElementName);
137 		}
138 	}
139 
140 	@Override
141 	public void unknownAttribute(IParseLocation theLocation, String theElementName) {
142 		if (myLogErrors) {
143 			ourLog.warn("Unknown attribute '{}' found while parsing", theElementName);
144 		}
145 	}
146 
147 	@Override
148 	public void unknownElement(IParseLocation theLocation, String theElementName) {
149 		if (myLogErrors) {
150 			ourLog.warn("Unknown element '{}' found while parsing", theElementName);
151 		}
152 	}
153 
154 	@Override
155 	public void unknownReference(IParseLocation theLocation, String theReference) {
156 		if (myLogErrors) {
157 			ourLog.warn("Resource has invalid reference: {}", theReference);
158 		}
159 	}
160 
161 	public static String createIncorrectJsonTypeMessage(String theElementName, ValueType theExpected, ScalarType theExpectedScalarType, ValueType theFound, ScalarType theFoundScalarType) {
162 		StringBuilder b = new StringBuilder();
163 		b.append("Found incorrect type for element ");
164 		b.append(theElementName);
165 		b.append(" - Expected ");
166 		b.append(theExpected.name());
167 		if (theExpectedScalarType != null) {
168 			b.append(" (");
169 			b.append(theExpectedScalarType.name());
170 			b.append(")");
171 		}
172 		b.append(" and found ");
173 		b.append(theFound.name());
174 		if (theFoundScalarType != null) {
175 			b.append(" (");
176 			b.append(theFoundScalarType.name());
177 			b.append(")");
178 		}
179 		String message = b.toString();
180 		return message;
181 	}
182 
183 }