package ca.uhn.fhir.narrative.template; import java.util.Collection; import java.util.List; import ca.uhn.fhir.narrative.template.nodes.AtomNode; /** * An abstract class the Filter and Tag classes extend. * <p/> * It houses some utility methods easily available for said * classes. */ public abstract class LValue { /** * Returns true iff a and b are equals, where (int) 1 is * equals to (double) 1.0 * * @param a * the first object to compare. * @param b * the second object to compare. * * @return true iff a and b are equals, where (int) 1 is * equals to (double) 1.0 */ public static boolean areEqual(Object a, Object b) { if (a == b) { return true; } if (a == null || b == null) { return false; } // TODO refactor the instance-ofs below if (a instanceof Number && b instanceof Number) { double delta = ((Number) a).doubleValue() - ((Number) b).doubleValue(); // To account for floating point rounding errors, return true if // the difference between double a and double b is very small. return Math.abs(delta) < 0.00000000001; } if (AtomNode.isEmpty(a) && (b instanceof CharSequence)) { return ((CharSequence)b).length() == 0; } if (AtomNode.isEmpty(b) && (a instanceof CharSequence)) { return ((CharSequence)a).length() == 0; } if (AtomNode.isEmpty(a) && (b instanceof Collection)) { return ((Collection)b).size() == 0; } if (AtomNode.isEmpty(b) && (a instanceof Collection)) { return ((Collection)a).size() == 0; } if (AtomNode.isEmpty(a) && (b.getClass().isArray())) { return ((Object[])b).length == 0; } if (AtomNode.isEmpty(b) && (a.getClass().isArray())) { return ((Object[])a).length == 0; } return a.equals(b); } /** * Returns this value as an array. If a value is already an array, * it is casted to a `Object[]`, if it's a `java.util.List`, it is * converted to an array and in all other cases, `value` is simply * returned as an `Object[]` with a single value in it. * * @param value * the value to convert/cast to an array. * * @return this value as an array. */ public Object[] asArray(Object value) { if(value == null) { return null; } if (value.getClass().isArray()) { return (Object[]) value; } if (value instanceof List) { return ((List) value).toArray(); } return new Object[]{value}; } /** * Convert `value` to a boolean. Note that only `nil` and `false` * are `false`, all other values are `true`. * * @param value * the value to convert. * * @return `value` as a boolean. */ public boolean asBoolean(Object value) { if (value == null) { return false; } if (value instanceof Boolean) { return (Boolean) value; } return true; } /** * Returns `value` as a Number. Strings will be coerced into * either a Long or Double. * * @param value * the value to cast to a Number. * * @return `value` as a Number. * * @throws NumberFormatException when `value` is a String which could * not be parsed as a Long or Double. */ public Number asNumber(Object value) throws NumberFormatException { if(value instanceof Number) { return (Number) value; } String str = String.valueOf(value); return str.matches("\\d+") ? Long.valueOf(str) : Double.valueOf(str); } /** * Returns `value` as a String. * * @param value * the value to convert to a String. * * @return `value` as a String. */ public String asString(Object value) { if (value == null) { return ""; } if (!this.isArray(value)) { return String.valueOf(value); } Object[] array = this.asArray(value); StringBuilder builder = new StringBuilder(); for (Object obj : array) { builder.append(this.asString(obj)); } return builder.toString(); } /** * Returns true iff `value` is an array or a java.util.List. * * @param value * the value to check. * * @return true iff `value` is an array or a java.util.List. */ public boolean isArray(Object value) { return value != null && (value.getClass().isArray() || value instanceof List); } /** * Returns true iff `value` is a whole number (Integer or Long). * * @param value * the value to check. * * @return true iff `value` is a whole number (Integer or Long). */ public boolean isInteger(Object value) { return value != null && (value instanceof Long || value instanceof Integer); } /** * Returns true iff `value` is a Number. * * @param value * the value to check. * * @return true iff `value` is a Number. */ public boolean isNumber(Object value) { if(value == null) { return false; } if(value instanceof Number) { return true; } // valid Long? if(String.valueOf(value).matches("\\d+")) { return true; } try { // valid Double? Double.parseDouble(String.valueOf(value)); } catch(Exception e) { return false; } return true; } /** * Returns true iff `value` is a String. * * @param value * the value to check. * * @return true iff `value` is a String. */ public boolean isString(Object value) { return value != null && value instanceof CharSequence; } }