001package org.hl7.fhir.dstu2016may.validation; 002 003/* 004Copyright (c) 2011+, HL7, Inc 005All rights reserved. 006 007Redistribution and use in source and binary forms, with or without modification, 008are 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 019THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028POSSIBILITY OF SUCH DAMAGE. 029 030*/ 031 032import java.text.MessageFormat; 033import java.util.List; 034 035import org.apache.commons.lang3.StringUtils; 036import org.hl7.fhir.utilities.validation.ValidationMessage; 037import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; 038import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 039import org.hl7.fhir.utilities.validation.ValidationMessage.Source; 040 041public class BaseValidator { 042 043 protected ValidationMessage.Source source; 044 045 /** 046 * Test a rule and add a {@link IssueSeverity#FATAL} validation message if the validation fails 047 * 048 * @param thePass 049 * Set this parameter to <code>false</code> if the validation does not pass 050 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 051 */ 052 protected boolean fail(List<ValidationMessage> errors, ValidationMessage.IssueType type, int line, int col, String path, boolean thePass, String msg) { 053 if (!thePass) { 054 errors.add(new ValidationMessage(source, type, line, col, path, msg, ValidationMessage.IssueSeverity.FATAL)); 055 } 056 return thePass; 057 } 058 059 /** 060 * Test a rule and add a {@link IssueSeverity#FATAL} validation message if the validation fails 061 * 062 * @param thePass 063 * Set this parameter to <code>false</code> if the validation does not pass 064 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 065 */ 066 protected boolean fail(List<ValidationMessage> errors, ValidationMessage.IssueType type, List<String> pathParts, boolean thePass, String msg) { 067 if (!thePass) { 068 String path = toPath(pathParts); 069 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, ValidationMessage.IssueSeverity.FATAL)); 070 } 071 return thePass; 072 } 073 074 /** 075 * Test a rule and add a {@link IssueSeverity#FATAL} validation message if the validation fails 076 * 077 * @param thePass 078 * Set this parameter to <code>false</code> if the validation does not pass 079 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 080 */ 081 protected boolean fail(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { 082 if (!thePass) { 083 String path = toPath(pathParts); 084 errors.add(new ValidationMessage(source, type, -1, -1, path, formatMessage(theMessage, theMessageArguments), IssueSeverity.FATAL)); 085 } 086 return thePass; 087 } 088 089 /** 090 * Test a rule and add a {@link IssueSeverity#FATAL} validation message if the validation fails 091 * 092 * @param thePass 093 * Set this parameter to <code>false</code> if the validation does not pass 094 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 095 */ 096 protected boolean fail(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { 097 if (!thePass) { 098 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.FATAL)); 099 } 100 return thePass; 101 } 102 103 104 private String formatMessage(String theMessage, Object... theMessageArguments) { 105 String message; 106 if (theMessageArguments != null && theMessageArguments.length > 0) { 107 message = MessageFormat.format(theMessage, theMessageArguments); 108 } else { 109 message = theMessage; 110 } 111 return message; 112 } 113 114 protected boolean grammarWord(String w) { 115 return w.equals("and") || w.equals("or") || w.equals("a") || w.equals("the") || w.equals("for") || w.equals("this") || w.equals("that") || w.equals("of"); 116 } 117 118 /** 119 * Test a rule and add a {@link IssueSeverity#INFORMATION} validation message if the validation fails 120 * 121 * @param thePass 122 * Set this parameter to <code>false</code> if the validation does not pass 123 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 124 */ 125 protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg) { 126 if (!thePass) { 127 errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.INFORMATION)); 128 } 129 return thePass; 130 } 131 132 /** 133 * Test a rule and add a {@link IssueSeverity#INFORMATION} validation message if the validation fails 134 * 135 * @param thePass 136 * Set this parameter to <code>false</code> if the validation does not pass 137 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 138 */ 139 protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { 140 if (!thePass) { 141 String message = formatMessage(theMessage, theMessageArguments); 142 errors.add(new ValidationMessage(source, type, line, col, path, message, IssueSeverity.INFORMATION)); 143 } 144 return thePass; 145 } 146 147 /** 148 * Test a rule and add a {@link IssueSeverity#INFORMATION} validation message if the validation fails 149 * 150 * @param thePass 151 * Set this parameter to <code>false</code> if the validation does not pass 152 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 153 */ 154 protected boolean hint(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { 155 if (!thePass) { 156 String path = toPath(pathParts); 157 String message = formatMessage(theMessage, theMessageArguments); 158 errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.INFORMATION)); 159 } 160 return thePass; 161 } 162 163 /** 164 * Test a rule and add a {@link IssueSeverity#INFORMATION} validation message if the validation fails 165 * 166 * @param thePass 167 * Set this parameter to <code>false</code> if the validation does not pass 168 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 169 */ 170 protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { 171 if (!thePass) { 172 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.INFORMATION)); 173 } 174 return thePass; 175 } 176 177 /** 178 * Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails 179 * 180 * @param thePass 181 * Set this parameter to <code>false</code> if the validation does not pass 182 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 183 */ 184 protected boolean rule(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { 185 if (!thePass) { 186 String message = formatMessage(theMessage, theMessageArguments); 187 errors.add(new ValidationMessage(source, type, line, col, path, message, IssueSeverity.ERROR)); 188 } 189 return thePass; 190 } 191 192 /** 193 * Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails 194 * 195 * @param thePass 196 * Set this parameter to <code>false</code> if the validation does not pass 197 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 198 */ 199 protected boolean rule(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String msg) { 200 if (!thePass) { 201 String path = toPath(pathParts); 202 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.ERROR)); 203 } 204 return thePass; 205 } 206 207 /** 208 * Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails 209 * 210 * @param thePass 211 * Set this parameter to <code>false</code> if the validation does not pass 212 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 213 */ 214 protected boolean rule(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { 215 if (!thePass) { 216 String path = toPath(pathParts); 217 String message = formatMessage(theMessage, theMessageArguments); 218 errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.ERROR)); 219 } 220 return thePass; 221 } 222 223 /** 224 * Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails 225 * 226 * @param thePass 227 * Set this parameter to <code>false</code> if the validation does not pass 228 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 229 */ 230 protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { 231 if (!thePass) { 232 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.ERROR)); 233 } 234 return thePass; 235 } 236 237 static public boolean rule(List<ValidationMessage> errors, Source source, IssueType type, String path, boolean thePass, String msg) { 238 if (!thePass) { 239 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.ERROR)); 240 } 241 return thePass; 242 } 243 244 /** 245 * Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails 246 * 247 * @param thePass 248 * Set this parameter to <code>false</code> if the validation does not pass 249 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 250 */ 251 protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) { 252 if (!thePass) { 253 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.ERROR)); 254 } 255 return thePass; 256 } 257 258 protected String splitByCamelCase(String s) { 259 StringBuilder b = new StringBuilder(); 260 for (int i = 0; i < s.length(); i++) { 261 char c = s.charAt(i); 262 if (Character.isUpperCase(c) && !(i == 0 || Character.isUpperCase(s.charAt(i-1)))) 263 b.append(' '); 264 b.append(c); 265 } 266 return b.toString(); 267 } 268 269 protected String stripPunctuation(String s, boolean numbers) { 270 StringBuilder b = new StringBuilder(); 271 for (char c : s.toCharArray()) { 272 int t = Character.getType(c); 273 if (t == Character.UPPERCASE_LETTER || t == Character.LOWERCASE_LETTER || t == Character.TITLECASE_LETTER || t == Character.MODIFIER_LETTER || t == Character.OTHER_LETTER || (t == Character.DECIMAL_DIGIT_NUMBER && numbers) || (t == Character.LETTER_NUMBER && numbers) || c == ' ') 274 b.append(c); 275 } 276 return b.toString(); 277 } 278 279 private String toPath(List<String> pathParts) { 280 if (pathParts == null || pathParts.isEmpty()) { 281 return ""; 282 } 283 return "//" + StringUtils.join(pathParts, '/'); 284 } 285 286 /** 287 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 288 * 289 * @param thePass 290 * Set this parameter to <code>false</code> if the validation does not pass 291 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 292 */ 293 protected boolean warning(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { 294 if (!thePass) { 295 msg = formatMessage(msg, theMessageArguments); 296 errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.WARNING)); 297 } 298 return thePass; 299 300 } 301 302 /** 303 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 304 * 305 * @param thePass 306 * Set this parameter to <code>false</code> if the validation does not pass 307 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 308 */ 309 protected boolean warning(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { 310 if (!thePass) { 311 String path = toPath(pathParts); 312 String message = formatMessage(theMessage, theMessageArguments); 313 errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.WARNING)); 314 } 315 return thePass; 316 } 317 318 /** 319 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 320 * 321 * @param thePass 322 * Set this parameter to <code>false</code> if the validation does not pass 323 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 324 */ 325 protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { 326 if (!thePass) { 327 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.WARNING)); 328 } 329 return thePass; 330 } 331 332 /** 333 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 334 * 335 * @param thePass 336 * Set this parameter to <code>false</code> if the validation does not pass 337 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 338 */ 339 protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) { 340 if (!thePass) { 341 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.WARNING)); 342 } 343 return thePass; 344 } 345 346 /** 347 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 348 * 349 * @param thePass 350 * Set this parameter to <code>false</code> if the validation does not pass 351 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 352 */ 353 protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) { 354 if (!thePass) { 355 msg = formatMessage(msg, theMessageArguments); 356 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.WARNING)); 357 } 358 return thePass; 359 } 360 361 //--------- 362 /** 363 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 364 * 365 * @param thePass 366 * Set this parameter to <code>false</code> if the validation does not pass 367 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 368 */ 369 protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { 370 if (!thePass) { 371 msg = formatMessage(msg, theMessageArguments); 372 errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.INFORMATION)); 373 } 374 return thePass; 375 376 } 377 378 /** 379 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 380 * 381 * @param thePass 382 * Set this parameter to <code>false</code> if the validation does not pass 383 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 384 */ 385 protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { 386 if (!thePass) { 387 String path = toPath(pathParts); 388 String message = formatMessage(theMessage, theMessageArguments); 389 errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.INFORMATION)); 390 } 391 return thePass; 392 } 393 394 /** 395 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 396 * 397 * @param thePass 398 * Set this parameter to <code>false</code> if the validation does not pass 399 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 400 */ 401 protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { 402 if (!thePass) { 403 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.INFORMATION)); 404 } 405 return thePass; 406 } 407 408 /** 409 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 410 * 411 * @param thePass 412 * Set this parameter to <code>false</code> if the validation does not pass 413 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 414 */ 415 protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) { 416 if (!thePass) { 417 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.INFORMATION)); 418 } 419 return thePass; 420 } 421 422 /** 423 * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails 424 * 425 * @param thePass 426 * Set this parameter to <code>false</code> if the validation does not pass 427 * @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation) 428 */ 429 protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) { 430 if (!thePass) { 431 msg = formatMessage(msg, theMessageArguments); 432 errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.INFORMATION)); 433 } 434 return thePass; 435 } 436 437}