package se.cambio.cds.util; import org.apache.log4j.Logger; import org.openehr.rm.datatypes.basic.DataValue; import org.openehr.rm.datatypes.quantity.*; import org.openehr.rm.datatypes.quantity.datetime.DvDateTime; import org.openehr.rm.datatypes.quantity.datetime.DvDuration; import org.openehr.rm.datatypes.quantity.datetime.DvTemporal; import org.openehr.rm.datatypes.text.CodePhrase; import org.openehr.rm.datatypes.text.DvCodedText; import org.openehr.rm.datatypes.text.DvText; import org.openehr.rm.support.measurement.SimpleMeasurementService; import se.cambio.cds.gdl.model.expression.*; import se.cambio.cds.model.facade.execution.vo.PredicateGeneratedElementInstance; import se.cambio.cds.model.instance.ElementInstance; import se.cambio.openehr.controller.session.OpenEHRSessionManager; import se.cambio.openehr.util.ExceptionHandler; import se.cambio.openehr.util.OpenEHRDataValues; import se.cambio.openehr.util.exceptions.InternalErrorException; import se.cambio.openehr.util.misc.DataValueGenerator; import java.math.BigDecimal; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class DVUtil { public static DataValue createDV(ElementInstance elementInstance, String rmName, String attributeName, Object value) throws InternalErrorException{ DataValue dv = elementInstance.getDataValue(); if(dv==null){ dv = DataValueGenerator.getDummyDV(rmName); } return DataValueGenerator.createDV(dv, attributeName, value); } //Compares to DataValues ignoring language dependent labels (DvCodedText & DvOrdinal) public static boolean equalDVs(DataValue dv1, DataValue dv2){ if (dv1 instanceof DvCodedText && dv2 instanceof DvCodedText){ DvCodedText dvCodedText1 = (DvCodedText) dv1; DvCodedText dvCodedText2 = (DvCodedText) dv2; return dvCodedText1.getDefiningCode().equals(dvCodedText2.getDefiningCode()) && dvCodedText2.getTerminologyId().equals(dvCodedText2.getTerminologyId()); }else if (dv1 instanceof DvOrdinal && dv2 instanceof DvOrdinal){ DvOrdinal dvOrdinal1 = (DvOrdinal) dv1; DvOrdinal dvOrdinal2 = (DvOrdinal) dv2; return dvOrdinal1.getValue() == dvOrdinal2.getValue() && equalDVs(dvOrdinal1.getSymbol(), dvOrdinal2.getSymbol()); }else if (dv1 instanceof DvQuantity && dv2 instanceof DvQuantity){ DvQuantity dvQuantity1 = (DvQuantity) dv1; DvQuantity dvQuantity2 = (DvQuantity) dv2; int precision = Math.max(dvQuantity1.getPrecision(), dvQuantity2.getPrecision()); double magnitude1 = round(dvQuantity1.getMagnitude(), precision); double magnitude2 = round(dvQuantity2.getMagnitude(), precision); return SimpleMeasurementService.getInstance().compare(dvQuantity1.getUnits(), magnitude1, dvQuantity2.getUnits(), magnitude2) == 0; }else if (dv1 instanceof DvProportion && dv2 instanceof DvProportion){ DvProportion dvProportion1 = (DvProportion) dv1; DvProportion dvProportion2 = (DvProportion) dv2; return (dvProportion1.getNumerator()/dvProportion1.getDenominator()) == (dvProportion2.getNumerator()/dvProportion2.getDenominator()); }else if (dv1 instanceof DvTemporal && dv2 instanceof DvTemporal){ DvTemporal dvTemporal1 = (DvTemporal)dv1; DvTemporal dvTemporal2 = (DvTemporal)dv2; return dvTemporal1.getDateTime().getMillis() == dvTemporal2.getDateTime().getMillis(); }else{ if (dv1==null && dv2==null){ return true; }else{ if (dv1!=null){ return dv1.equals(dv2); }else{ return false; } } } } //Used by the drools engine public static boolean equalDV(boolean inPredicate, ElementInstance ei, DataValue dv2, boolean negated) { if (ei instanceof PredicateGeneratedElementInstance){ return inPredicate; }else{ boolean result = DVUtil.equalDVs(ei.getDataValue(), dv2); if (negated){ return !result; }else{ return result; } } } public static boolean nullValueEquals(DvCodedText nullFlavour, Object o) { if (o instanceof DvCodedText){ if (nullFlavour!=null){ return DVUtil.equalDVs(nullFlavour, (DataValue)o); }else{ return false; } }else{ return false; } } public static boolean isSubClassOf(boolean inPredicate, ElementInstance ei, Map<ElementInstance, Map<String, Boolean>> bindingsMap, DataValue... dataValues) { return isSubClassOfCached(inPredicate, ei, bindingsMap, false, dataValues); } public static boolean isSubClassOfCached(boolean inPredicate, ElementInstance ei, Map<ElementInstance, Map<String, Boolean>> bindingsMap, boolean negation, DataValue... dataValues) { Map<String, Boolean> bindingMapByElementInstance = bindingsMap.get(ei); if (bindingMapByElementInstance==null){ bindingMapByElementInstance = new HashMap<String, Boolean>(); bindingsMap.put(ei, bindingMapByElementInstance); } String dataValueKey = getDataValuesKey(dataValues); Boolean isSubClass = bindingMapByElementInstance.get(dataValueKey); if (isSubClass==null){ if (!negation){ isSubClass = isSubClassOf(inPredicate, ei, dataValues); }else{ isSubClass = isNotSubClassOf(inPredicate, ei, dataValues); } bindingMapByElementInstance.put(dataValueKey, isSubClass); } return isSubClass; } private static String getDataValuesKey(DataValue[] dataValues){ StringBuffer sb = new StringBuffer(); for(DataValue dataValue: dataValues){ sb.append(dataValue.serialise()); } return sb.toString(); } public static boolean isSubClassOf(boolean inPredicate, ElementInstance ei, DataValue... dataValues) { if (!inPredicate && ei instanceof PredicateGeneratedElementInstance){ return false; }else{ CodePhrase a = getCodePhrase(ei.getDataValue()); Set<CodePhrase> codePhrases = new HashSet<CodePhrase>(); for (int i = 0; i < dataValues.length; i++) { codePhrases.add(getCodePhrase(dataValues[i])); } if (a!=null && !codePhrases.isEmpty()){ try { boolean result= OpenEHRSessionManager.getTerminologyFacadeDelegate().isSubclassOf(a, codePhrases); return result; } catch (InternalErrorException e) { ExceptionHandler.handle(e); return false; } }else{ return false; } } } private static CodePhrase getCodePhrase(DataValue dv){ if (dv instanceof DvCodedText){ return ((DvCodedText)dv).getDefiningCode(); }else if (dv instanceof DvOrdinal){ return ((DvOrdinal)dv).getSymbol().getDefiningCode(); }else if (dv instanceof DvText){ try{ DataValue dvAux = DataValue.parseValue(OpenEHRDataValues.DV_CODED_TEXT+","+((DvText)dv).getValue()); if (dvAux instanceof DvCodedText){ return ((DvCodedText)dvAux).getDefiningCode(); }else{ return null; } }catch(Exception e){ Logger.getLogger(DVUtil.class).warn("Unable to get CodePhrase from text '"+dv.toString()+"'"); return null; } }else{ return null; } } public static boolean isNotSubClassOf(boolean inPredicate, ElementInstance ei, Map<ElementInstance, Map<String, Boolean>> bindingsMap, DataValue... dataValues) { return isSubClassOfCached(inPredicate, ei, bindingsMap, true, dataValues); } public static boolean isNotSubClassOf(boolean inPredicate, ElementInstance ei, DataValue... dataValues){ if (ei instanceof PredicateGeneratedElementInstance){ return true; }else{ //TODO Remove, exceptions should be handled CodePhrase a = getCodePhrase(ei.getDataValue()); Set<CodePhrase> codePhrases = new HashSet<CodePhrase>(); for (int i = 0; i < dataValues.length; i++) { codePhrases.add(getCodePhrase(dataValues[i])); } if (a!=null && !codePhrases.isEmpty()){ try { return !OpenEHRSessionManager.getTerminologyFacadeDelegate().isSubclassOf(a, codePhrases); } catch (InternalErrorException e) { ExceptionHandler.handle(e); return false; } }else{ return false; } } } @SuppressWarnings({ "rawtypes", "unchecked" }) public static int compareDVs(DataValue dv1, DataValue dv2){ if (dv1 instanceof DvText){ return dv1.equals(dv2)?0:-1; }else{ if (dv1 instanceof Comparable<?>){ return ((Comparable)dv1).compareTo(dv2); }else{ return -1; } } } public static boolean compatibleComparison(DataValue dv1, DataValue dv2){ if (dv1 instanceof DvQuantity){ if (dv2 instanceof DvQuantity){ String unit1 = ((DvQuantity)dv1).getUnits(); String unit2 = ((DvQuantity)dv2).getUnits(); boolean compatible = false; try{ compatible = SimpleMeasurementService.getInstance().unitsComparable(unit1, unit2); }catch(IllegalArgumentException e){ Logger.getLogger(DVUtil.class).warn("Illegal argument comparing unit '"+unit1+"' with '"+unit2+"'"); return false; } if (!compatible){ Logger.getLogger(DVUtil.class).warn("Comparing two elements with incompatible units '"+unit1+"'!='"+unit2+"'"); } return compatible; }else{ return false; } }else if (dv1 instanceof DvCount && dv2 instanceof DvCount){ return true; }else if (dv1 instanceof DvTemporal<?> && dv2 instanceof DvTemporal<?>){ return true; }else if (dv1 instanceof DvDuration && dv2 instanceof DvDuration){ return true; }else if (dv1 instanceof DvProportion && dv2 instanceof DvProportion){ return true; }else if (dv1 instanceof DvOrdinal && dv2 instanceof DvOrdinal){ return true; } else { return false; //Comparison of DVText always incompatible (not for equals/unequals) } } public static double round(double unroundedDouble, int precision){ BigDecimal bd = new BigDecimal(unroundedDouble); bd = bd.setScale(precision,BigDecimal.ROUND_HALF_UP); return bd.doubleValue(); } public static ConstantExpression convertToExpression(DataValue dv){ String dataValueStr = dv.serialise(); dataValueStr = dataValueStr.substring(dataValueStr.indexOf(",")+1); if (dv instanceof DvCodedText){ DvCodedText dvCT = (DvCodedText)dv; return new CodedTextConstant(dvCT.getValue(), dvCT.getDefiningCode()); }else if (dv instanceof DvOrdinal){ DvOrdinal dvOrdinal = (DvOrdinal)dv; return new OrdinalConstant(dvOrdinal); }else if (dv instanceof DvText){ return new StringConstant(dataValueStr); }else if (dv instanceof DvDateTime) { return new DateTimeConstant(getDateTimeStrWithoutMillisAndTimezone(dataValueStr)); }else if (dv instanceof DvQuantity) { return new QuantityConstant((DvQuantity)dv); }else{ return new ConstantExpression(dataValueStr); } } public static boolean checkMaxMin(DataValue predicateDV, DataValue dv, String opSymbol) throws InternalErrorException{ if (predicateDV instanceof DvOrdered && dv instanceof DvOrdered){ int comp = ((DvOrdered) predicateDV).compareTo((DvOrdered)dv); if (OperatorKind.MAX.getSymbol().equals(opSymbol)){ return comp<0; }else if (OperatorKind.MIN.getSymbol().equals(opSymbol)){ return comp>0; }else{ throw new InternalErrorException(new Exception("Operator for predicate '"+opSymbol+"' is not valid.")); } }else{ return false; } } private static String getDateTimeStrWithoutMillisAndTimezone(String dateTimeDVStr){ //Ignore millis if found if (dateTimeDVStr.indexOf(".")>0){ return dateTimeDVStr.substring(0,dateTimeDVStr.indexOf(".")); }else if (dateTimeDVStr.indexOf("+")>0){ return dateTimeDVStr.substring(0,dateTimeDVStr.indexOf("+")); }else if (dateTimeDVStr.indexOf("-")>0){ return dateTimeDVStr.substring(0,dateTimeDVStr.indexOf("-")); }else{ return dateTimeDVStr; } } public static boolean areDomainsCompatible(String domain1, String domain2){ if (domain1==null){ return true; }else{ if (domain2==null){ return true; }else{ return domain1.equals(domain2); } } } } /* * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the 'License'); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an 'AS IS' basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * * The Initial Developers of the Original Code are Iago Corbal and Rong Chen. * Portions created by the Initial Developer are Copyright (C) 2012-2013 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Software distributed under the License is distributed on an 'AS IS' basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * ***** END LICENSE BLOCK ***** */