001/******************************************************************************* 002 * Crown Copyright (c) 2006 - 2014, Copyright (c) 2006 - 2014 Kestral Computing P/L. 003 * All rights reserved. This program and the accompanying materials 004 * are made available under the terms of the Eclipse Public License v1.0 005 * which accompanies this distribution, and is available at 006 * http://www.eclipse.org/legal/epl-v10.html 007 * 008 * Contributors: 009 * Kestral Computing P/L - initial implementation 010 *******************************************************************************/ 011 012package org.hl7.fhir.utilities.ucum; 013 014import java.util.ArrayList; 015import java.util.List; 016 017import org.hl7.fhir.utilities.ucum.special.Registry; 018 019 020public class UcumValidator { 021 022 private UcumModel model; 023 private List<String> result; 024 private Registry handlers; 025 026 public UcumValidator(UcumModel model, Registry handlers) { 027 super(); 028 this.model = model; 029 this.handlers = handlers; 030 } 031 032 public List<String> validate() { 033 result = new ArrayList<String>(); 034 checkCodes(); 035 checkUnits(); 036 return result; 037 } 038 039 private void checkCodes() { 040 for (Unit unit : model.getBaseUnits()) { 041 checkUnitCode(unit.getCode(), true); 042 } 043 for (Unit unit : model.getDefinedUnits()) { 044 checkUnitCode(unit.getCode(), true); 045 } 046 } 047 048 private void checkUnits() { 049 for (DefinedUnit unit : model.getDefinedUnits()) { 050 if (!unit.isSpecial()) 051 checkUnitCode(unit.getValue().getUnit(), false); 052 else if (!handlers.exists(unit.getCode())) 053 result.add("No Handler for "+unit.getCode().toString()); 054 } 055 } 056 057 private void checkUnitCode(String code, boolean primary) { 058 try { 059 Term term = new ExpressionParser(model).parse(code); 060 String c = new ExpressionComposer().compose(term); 061 if (!c.equals(code)) 062 result.add("Round trip failed: "+code+" -> "+c); 063 new Converter(model, handlers).convert(term); 064 } catch (Exception e) { 065 result.add(code+": "+e.getMessage()); 066 } 067 if (primary) 068 try { 069 // there can't be any codes that have digits in them that aren't inside [] 070 boolean inBrack = false; 071 boolean nonDigits = false; 072 for (int i = 0; i < code.length(); i++) { 073 char ch = code.charAt(i); 074 if (ch == '[') 075 if (inBrack) 076 throw new Exception("nested ["); 077 else 078 inBrack = true; 079 if (ch == ']') 080 if (!inBrack) 081 throw new Exception("] without ["); 082 else 083 inBrack = false; 084 nonDigits = nonDigits || !(ch >= '0' && ch <= '9'); 085 if (ch >= '0' && ch <= '9' && !inBrack && nonDigits) { 086 throw new Exception("code "+code+" is ambiguous because it has digits outside []"); 087 } 088 } 089 } catch (Exception e) { 090 result.add(e.getMessage()); 091 } 092 093 } 094 095}