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.fhir.ucum; 013 014import java.util.ArrayList; 015import java.util.List; 016 017import org.fhir.ucum.special.Registry; 018 019 020 021public class UcumValidator { 022 023 private UcumModel model; 024 private List<String> result; 025 private Registry handlers; 026 027 public UcumValidator(UcumModel model, Registry handlers) { 028 super(); 029 this.model = model; 030 this.handlers = handlers; 031 } 032 033 public List<String> validate() { 034 result = new ArrayList<String>(); 035 checkCodes(); 036 checkUnits(); 037 return result; 038 } 039 040 private void checkCodes() { 041 for (Unit unit : model.getBaseUnits()) { 042 checkUnitCode(unit.getCode(), true); 043 } 044 for (Unit unit : model.getDefinedUnits()) { 045 checkUnitCode(unit.getCode(), true); 046 } 047 } 048 049 private void checkUnits() { 050 for (DefinedUnit unit : model.getDefinedUnits()) { 051 if (!unit.isSpecial()) 052 checkUnitCode(unit.getValue().getUnit(), false); 053 else if (!handlers.exists(unit.getCode())) 054 result.add("No Handler for "+unit.getCode().toString()); 055 } 056 } 057 058 private void checkUnitCode(String code, boolean primary) { 059 try { 060 Term term = new ExpressionParser(model).parse(code); 061 String c = new ExpressionComposer().compose(term); 062 if (!c.equals(code)) 063 result.add("Round trip failed: "+code+" -> "+c); 064 new Converter(model, handlers).convert(term); 065 } catch (Exception e) { 066 result.add(code+": "+e.getMessage()); 067 } 068 if (primary) 069 try { 070 // there can't be any codes that have digits in them that aren't inside [] 071 boolean inBrack = false; 072 boolean nonDigits = false; 073 for (int i = 0; i < code.length(); i++) { 074 char ch = code.charAt(i); 075 if (ch == '[') 076 if (inBrack) 077 throw new Exception("nested ["); 078 else 079 inBrack = true; 080 if (ch == ']') 081 if (!inBrack) 082 throw new Exception("] without ["); 083 else 084 inBrack = false; 085 nonDigits = nonDigits || !(ch >= '0' && ch <= '9'); 086 if (ch >= '0' && ch <= '9' && !inBrack && nonDigits) { 087 throw new Exception("code "+code+" is ambiguous because it has digits outside []"); 088 } 089 } 090 } catch (Exception e) { 091 result.add(e.getMessage()); 092 } 093 094 } 095 096}