All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.imsweb.validation.ValidatorContextFunctions Maven / Gradle / Ivy

/*
 * Copyright (C) 2004 Information Management Services, Inc.
 */
package com.imsweb.validation;

import java.lang.reflect.Method;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import groovy.lang.Binding;

import com.imsweb.validation.internal.ExtraPropertyEntityHandlerDto;
import com.imsweb.validation.shared.ContextFunctionDocAnnotation;
import com.imsweb.validation.shared.ContextFunctionDocDto;
import com.imsweb.validation.shared.ValidatorLookup;

/**
 * Helper methods made available to the edits.
 * 

* These functions need to be initialized before executing any edits in the framework. This class only provides basic methods; * there are more advanced implementations that extends this class and can be provided in the initialize() method. *

* To initialize the framework with these basic method, call the following:

* ValidatorContextFunctions.initialize(new ValidatorContextFunction()) * As of version 1.5, the functions are lazily initialized with the default implementation; so if you don't need a special implementation, * there is no need to initialize this class anymore. *

* To add your own methods to the context of the edits, create a class that extends this one, add the methods, and call the following:

* ValidatorContextFunctions.initialize(new MyValidatorContextFunction()) */ public class ValidatorContextFunctions { // unique private instance private static ValidatorContextFunctions _INSTANCE; /** * Initializes this class with the passed instance. *

* If it was already initialized with another instance, the previous one will be overridden with the new one. Use the * isInitialized() methods if you don't want this behavior. *

* Created on Feb 11, 2008 by depryf * @param instance a ValidatorContextFunctions instance */ public static synchronized void initialize(ValidatorContextFunctions instance) { _INSTANCE = instance; } /** * Returns true if this class has already been initialized, false otherwise. *

* Created on Mar 6, 2008 by depryf * @return true if this class has already been initialized, false otherwise */ public static synchronized boolean isInitialized() { return _INSTANCE != null; } /** * Gets current instance of the ValidatorContextFunctions *

* Created on Feb 11, 2008 by depryf * @return a ValidatorContextFunctions */ public static synchronized ValidatorContextFunctions getInstance() { if (_INSTANCE == null) _INSTANCE = new ValidatorContextFunctions(); return _INSTANCE; } /** * Returns documentation about any methods available in the context of the edits execution. *

* Created on Mar 3, 2010 by depryf * @return a list of ValidatorContextFunctionDto */ public static synchronized List getMethodsDocumentation() { if (_INSTANCE == null) throw new RuntimeException("Validation Context Functions have not been initialized!"); List dtos = new ArrayList<>(); for (Method m : _INSTANCE.getClass().getMethods()) { ContextFunctionDocAnnotation annotation = m.getAnnotation(ContextFunctionDocAnnotation.class); if (annotation != null) { ContextFunctionDocDto dto = new ContextFunctionDocDto(); dto.setMethodName(m.getName()); if (!StringUtils.isEmpty(annotation.param1())) dto.getParams().add(annotation.param1()); if (!StringUtils.isEmpty(annotation.param2())) dto.getParams().add(annotation.param2()); if (!StringUtils.isEmpty(annotation.param3())) dto.getParams().add(annotation.param3()); if (!StringUtils.isEmpty(annotation.param4())) dto.getParams().add(annotation.param4()); if (!StringUtils.isEmpty(annotation.param5())) dto.getParams().add(annotation.param5()); if (!StringUtils.isEmpty(annotation.param6())) dto.getParams().add(annotation.param6()); if (!StringUtils.isEmpty(annotation.param7())) dto.getParams().add(annotation.param7()); if (!StringUtils.isEmpty(annotation.param8())) dto.getParams().add(annotation.param8()); if (!StringUtils.isEmpty(annotation.param9())) dto.getParams().add(annotation.param9()); if (!StringUtils.isEmpty(annotation.param10())) dto.getParams().add(annotation.param10()); if (!StringUtils.isEmpty(annotation.paramName1())) dto.getParamNames().add(annotation.paramName1()); if (!StringUtils.isEmpty(annotation.paramName2())) dto.getParamNames().add(annotation.paramName2()); if (!StringUtils.isEmpty(annotation.paramName3())) dto.getParamNames().add(annotation.paramName3()); if (!StringUtils.isEmpty(annotation.paramName4())) dto.getParamNames().add(annotation.paramName4()); if (!StringUtils.isEmpty(annotation.paramName5())) dto.getParamNames().add(annotation.paramName5()); if (!StringUtils.isEmpty(annotation.paramName6())) dto.getParamNames().add(annotation.paramName6()); if (!StringUtils.isEmpty(annotation.paramName7())) dto.getParamNames().add(annotation.paramName7()); if (!StringUtils.isEmpty(annotation.paramName8())) dto.getParamNames().add(annotation.paramName8()); if (!StringUtils.isEmpty(annotation.paramName9())) dto.getParamNames().add(annotation.paramName9()); if (!StringUtils.isEmpty(annotation.paramName10())) dto.getParamNames().add(annotation.paramName10()); dto.setDescription(annotation.desc()); dto.setExample(annotation.example()); dtos.add(dto); } } return dtos; } /** * Forces the given entity (corresponding to the given collection name) to report the given properties when the edit fails. *

* There can be any number of properties. But if none are provided, then the properties gathered statically from the edit text will be used instead. *

* Created on Apr 21, 2010 by depryf * @param binding groovy binding (cannot be null) * @param entity entity on which the properties need to be reported (cannot be null) * @param properties properties to report; if none are provided, the failures will be reported for all the static properties */ @SuppressWarnings("unchecked") @ContextFunctionDocAnnotation(paramName1 = "binding", param1 = "Groovy binding (always called 'binding')", paramName2 = "entity", param2 = "entity to force the failure on; what entity means is application-dependent", paramName3 = "properties", param3 = "optional properties (with alias prefix) to report the failure on; if none are provided, the failure will be reported for all properties used in the edit", desc = "Forces a failure on the provided entity, this can be useful in situations where an edits iterates over sub-entities and a failure needs to be reported on some of those sub-entities.", example = "Functions.forceFailureOnEntity(binding, line)\nFunctions.forceFailureOnEntity(binding, line, 'line.nameLast')\nFunctions.forceFailureOnEntity(binding, line, 'line.nameLast', 'line.nameFirst')") public void forceFailureOnEntity(Binding binding, Object entity, String... properties) { if (binding == null || entity == null) return; Set forcedEntities = (Set)binding.getVariable(ValidationEngine.VALIDATOR_FORCE_FAILURE_ENTITY_KEY); if (forcedEntities == null) { forcedEntities = new HashSet<>(); binding.setVariable(ValidationEngine.VALIDATOR_FORCE_FAILURE_ENTITY_KEY, forcedEntities); } forcedEntities.add(new ExtraPropertyEntityHandlerDto(entity, properties)); } /** * Forces the given properties to be reported if the edit fails. *

* Created on Apr 27, 2010 by depryf * @param binding groovy binding (cannot be null) * @param properties properties to report (with alias prefix); if null or empty then the function does nothing */ @SuppressWarnings("unchecked") @ContextFunctionDocAnnotation(paramName1 = "binding", param1 = "Groovy binding (always called 'binding')", paramName2 = "properties", param2 = "properties (with alias prefix) to report the failure on; if none are provided, this function does nothing", desc = "Forces the provided properties to be reported when a failure happens; the properties will be reported on the current entity being validated (what entity means is application-dependent).", example = "Functions.forceFailureOnProperty(binding, 'line.nameLast')\nFunctions.forceFailureOnProperty(binding, 'line.nameLast', 'line.nameFirst')") public void forceFailureOnProperty(Binding binding, String... properties) { if (properties == null || properties.length == 0) return; Set forcedProperties = (Set)binding.getVariable(ValidationEngine.VALIDATOR_FORCE_FAILURE_PROPERTY_KEY); if (forcedProperties == null) { forcedProperties = new HashSet<>(); binding.setVariable(ValidationEngine.VALIDATOR_FORCE_FAILURE_PROPERTY_KEY, forcedProperties); } forcedProperties.addAll(Arrays.asList(properties)); } /** * Forces the given properties to be ignored if the edit fails. *

* Created on Apr 27, 2010 by depryf * @param binding groovy binding (cannot be null) * @param properties properties to ignore (with alias prefix); if null or empty then the function does nothing */ @SuppressWarnings("unchecked") @ContextFunctionDocAnnotation(paramName1 = "binding", param1 = "Groovy binding (always called 'binding')", paramName2 = "properties", param2 = "properties (with alias prefix) to ignore; if none are provided, this function does nothing", desc = "Ignores the provided properties when reporting a failure for the edit.", example = "Functions.ignoreFailureOnProperty(binding, 'line.nameLast')\nFunctions.ignoreFailureOnProperty(binding, 'line.nameLast', 'line.nameFirst')") public void ignoreFailureOnProperty(Binding binding, String... properties) { if (properties == null || properties.length == 0) return; Set ignoredProperties = (Set)binding.getVariable(ValidationEngine.VALIDATOR_IGNORE_FAILURE_PROPERTY_KEY); if (ignoredProperties == null) { ignoredProperties = new HashSet<>(); binding.setVariable(ValidationEngine.VALIDATOR_IGNORE_FAILURE_PROPERTY_KEY, ignoredProperties); } ignoredProperties.addAll(Arrays.asList(properties)); } /** * Gets the value defined in the context of the passed validator ID, under the passed key *

* Created on Nov 12, 2007 by depryf * @param validatorId validator ID * @param contextKey context key * @return an object, possibly null * @throws ValidationException */ @ContextFunctionDocAnnotation(paramName1 = "validatorId", param1 = "validator ID", paramName2 = "contextKey", param2 = "context key", desc = "Returns the value of the requested context key, throws an exception if the context is not found.", example = "Functions.getContext('seer', 'Birthplace_Table')") public Object getContext(String validatorId, String contextKey) throws ValidationException { if (validatorId == null) throw new ValidationException("Group is required when accessing a context entry."); if (contextKey == null) throw new ValidationException("Context key is required when accessing a context entry."); Object context = ValidationEngine.getContext(contextKey, validatorId); if (context == null) throw new ValidationException("Unknown context key '" + contextKey + "' from group '" + validatorId + "'"); return context; } /** * Returns the ValidatorLookup corresponding to the passed ID, throws an exception if such a lookup doesn't exist. *

* Created on Dec 20, 2007 by depryf * @param id lookup ID * @return a ValidatorLookup, never null * @throws ValidationException */ @ContextFunctionDocAnnotation(paramName1 = "id", param1 = "Lookup ID", desc = "Returns the lookup corresponding to the requested ID.\n\n" + "The returned object is a ValidatorLookup on which the following methods are available:\n" + " String getId()\n" + " String getByKey(String key)\n" + " String getByKeyWithCase(String key)\n" + " Set getAllByKey(String key)\n" + " Set getAllByKeyWithCase(String key)\n" + " Set getAllKeys()\n" + " String getByValue(String value)\n" + " String getByValueWithCase(String value)\n" + " Set getAllByValue(String value)\n" + " Set getAllByValueWithCase(String value)\n" + " Set getAllValues()\n" + " boolean containsKey(Object key)\n" + " boolean containsKeyWithCase(Object key)\n" + " boolean containsValue(Object value)\n" + " boolean containsValueWithCase(Object value)\n" + " boolean containsPair(String key, String value)\n" + " boolean containsPairWithCase(String key, String value)\n", example = "Functions.fetchLookup('lookup_id').containsKey(value)") public ValidatorLookup fetchLookup(String id) throws ValidationException { if (id == null) throw new ValidationException("Unable to load lookup "); ValidatorLookup lookup = ValidatorServices.getInstance().getLookupById(id); if (lookup == null) throw new ValidationException("Unable to load lookup '" + id + "'"); return lookup; } /** * Returns the value corresponding to the passed ID from our configuration files. Returns null if such an ID doesn't exist. *

* Created on Dec 20, 2007 by depryf * @param id configuration variable ID * @return corresponding value, null if it doesn't exist * @throws ValidationException */ @ContextFunctionDocAnnotation(paramName1 = "id", param1 = "Configuration variable ID", desc = "Returns the value of the requested configuration variable.", example = "Functions.fetchConfVariable('id')") public Object fetchConfVariable(String id) throws ValidationException { if (id == null) throw new ValidationException("Unable to fetch configuration variable for null value"); return ValidatorServices.getInstance().getConfVariable(id); } /** * Utility method that attempts to convert the supplied object to an Integer. *

* Created on Dec 27, 2007 by depryf * @param value value * @return corresponding Integer value, or null if the conversion fails */ @ContextFunctionDocAnnotation(paramName1 = "value", param1 = "value to convert to an Integer", desc = "Converts the passed value to an Integer, returns null if it can't be converted.", example = "Functions.asInt(record.ageAtDx)\nFunctions.asInt(25)\nFunctions.asInt('25')\nFunctions.asInt('whatever') would return null") public Integer asInt(Object value) { Integer result = null; if (value != null) { if (value instanceof Integer) result = (Integer)value; else if (value instanceof Number) result = ((Number)value).intValue(); else { String str = value instanceof String ? (String)value : value.toString(); if (NumberUtils.isDigits(str)) result = Integer.valueOf(str); } } return result; } /** * Checks that the passed value is between low and high; both inclusive. *

* Created on Dec 27, 2007 by depryf * @param value value to check * @param low low limit to check against * @param high high limit to check against * @return true if value is between low and high, false otherwise */ @ContextFunctionDocAnnotation(paramName1 = "value", param1 = "value to compare", paramName2 = "low", param2 = "low limit", paramName3 = "high", param3 = "high limit", desc = "returns true if the value is between the low and hight limit (inclusive), false it is not or cannot be determined", example = "Functions.between(2, 1, 3) -> true\nFunctions.between('B', 'A', 'C') -> true") public boolean between(Object value, Object low, Object high) { if (value == null || low == null || high == null) return false; if (value instanceof String) { String val = (String)value; String l = low.toString(); String h = high.toString(); // special case, if the three params are numeric string, compare them as numeric, not strings if (NumberUtils.isDigits(val) && NumberUtils.isDigits(l) && NumberUtils.isDigits(h)) { long lVal = Long.parseLong(val); long lLow = Long.parseLong(l); long lHigh = Long.parseLong(h); return lVal >= lLow && lVal <= lHigh; } else return val.compareTo(l) >= 0 && val.compareTo(h) <= 0; } if (value instanceof Number && low instanceof Number && high instanceof Number) { double val = ((Number)value).doubleValue(); double l = ((Number)low).doubleValue(); double h = ((Number)high).doubleValue(); return val >= l && val <= h; } return false; } /** * Returns the current day *

* Created on Dec 27, 2007 by depryf * @return current day */ @ContextFunctionDocAnnotation(desc = "Returns the current day as an integer.", example = "Functions.getCurrentDay()") public int getCurrentDay() { return LocalDate.now().getDayOfMonth(); } /** * Returns the current month *

* Created on Dec 27, 2007 by depryf * @return current month */ @ContextFunctionDocAnnotation(desc = "Returns the current month as an integer.", example = "Functions.getCurrentMonth()") public int getCurrentMonth() { return LocalDate.now().getMonthValue(); } /** * Returns the current year *

* Created on Dec 27, 2007 by depryf * @return current year */ @ContextFunctionDocAnnotation(desc = "Returns the current year as an integer.", example = "Functions.getCurrentYear()") public int getCurrentYear() { return LocalDate.now().getYear(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy