{"id":50411897,"url":"https://github.com/americanexpress/unify-simple-decision-table","last_synced_at":"2026-05-31T04:02:40.813Z","repository":{"id":359416903,"uuid":"1089802813","full_name":"americanexpress/unify-simple-decision-table","owner":"americanexpress","description":"Simple and easy to use Java implementation of a decision table","archived":false,"fork":false,"pushed_at":"2026-05-21T19:13:55.000Z","size":179,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T04:19:33.730Z","etag":null,"topics":["decision-tables","excel","java","json","rules-engine","workflow"],"latest_commit_sha":null,"homepage":"https://github.com/americanexpress/unify-simple-decision-table","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/americanexpress.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-04T20:45:28.000Z","updated_at":"2026-05-21T19:11:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/americanexpress/unify-simple-decision-table","commit_stats":null,"previous_names":["americanexpress/unify-simple-decision-table"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/americanexpress/unify-simple-decision-table","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/americanexpress%2Funify-simple-decision-table","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/americanexpress%2Funify-simple-decision-table/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/americanexpress%2Funify-simple-decision-table/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/americanexpress%2Funify-simple-decision-table/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/americanexpress","download_url":"https://codeload.github.com/americanexpress/unify-simple-decision-table/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/americanexpress%2Funify-simple-decision-table/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33718446,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decision-tables","excel","java","json","rules-engine","workflow"],"created_at":"2026-05-31T04:02:37.985Z","updated_at":"2026-05-31T04:02:40.794Z","avatar_url":"https://github.com/americanexpress.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## unify-simple-decision-table\n\n---\n\nUnify Simple Decision Table is a simple and easy to use, Java based implementation of a decision table. Don't let its\nsimple and easy to use nature fool you - it is just about as powerful as can be - but thankfully no more!\n\nIt provides the following high level functionality:\n\n1. Passing of input data as a map of key value pairs.\n2. \"First match\" and \"All Matches\" match policies.\n3. \"Return None\" and \"Return Default\" no match policies.\n4. Strict and lenient row validation policies.\n5. Multiple data types and evaluation operators.\n6. Return contents of multiple columns for one or more matched rows.\n7. Call external Java methods for evaluation or return values.\n8. Specify JEXL expressions for return values.\n9. Raise matched row events for analytics and client specific actions.\n10. Pass in any arbitrary input Java object to be used by external Java method for evaluation or return.\n\nThis decision table implementation uses sequential rule evaluation. In other words, it evaluates the input data\nagainst the rule rows defined, one at a time, starting from the top. Hence, it is recommended for users\nto keep the size of a decision table manageable for performance reasons. We recommend not going beyond a few hundred\nrows and a few tens of columns - this also helps in comprehension and keeps things nice, simple and scalable.\n\nDecision tables can be Excel based or JSON based. We recommend JSON based decision tables as they can be stored\nas source code and changes tracked. On the other hand, Excel based decision tables are easier to work with\nfor a non-technical person but the main disadvantage is that you cannot track\nchanges using a diff tool. One way of working could be to start out with Excel based decision table\nand convert the same to JSON based once it has been set up and tested. Of course, once you get comfortable with JSON based tables,\nyou could work with them directly. We provide a utility to convert an Excel decision table into a\nJSON decision table.\n\nAnd while you are here, may we invite you to check out a couple of other related offerings which could be of interest:\n\n***Unify-jdocs - a new way of working with JSON documents***\n\nhttps://github.com/americanexpress/unify-jdocs\n\nThis decision table implementation relies on unify-jdocs for all JSON reading and writing requirements.\n\n***Unify-flowret - A lightweight Java based orchestration engine***\n\nhttps://github.com/americanexpress/unify-flowret\n\nIf you like what you see, we would very much appreciate a like - it keeps us motivated knowing that our\nwork is appreciated and helping people in the community.\n\n### Getting the package\n\nUnify-simple-decision-table is available as a jar file in Maven central with the following Maven coordinates:\n\n```pom\n\u003cgroupId\u003ecom.americanexpress.unify.simple_decision_table\u003c/groupId\u003e\n\u003cartifactId\u003eunify-simple-decision-table\u003c/artifactId\u003e\n\u003cversion\u003e2.0.1\u003c/version\u003e\n```\n\n---\n\n### Version 2.x.x release alert\n\nVersion 2.x.x is an upgrade that contains the following:\n\n1. Bumped JDocs dependency which requires a breaking change and hence moving up to 2.x.x\n1. Throw an exception if JDocs library is not initialized\n2. Refactored package names to avoid potential conflicts with other libraries\n3. Added a stand-alone method to validate a decision table\n4. Added a new method to create a decision table from a JSON string\n6. Added a new operator MATCHES_REGEX\n7. Added a method to get the name of the decision table\n8. Added a methid to get the name of the system\n9. Updated test cases\n10. Added time expiry cache utility classes\n\nFor migrating to 2.x.x, the only breaking change is the requirement to have the JDocument class initialized before initializing\nthe decision table. This can be done by calling the method `JDocument.init` like below:\n\n`JDocument.init(new Initializer());`\n\nNote that the above initializes JDocument (unify-jdocs or JDocs) with default initialization and configuration values which\nshould be sufficient for using the decision table. However, it may happen that the application wants to use or uses\nJDocs independently and may already have its own initialization and configuration for JDocs. In this case, we only need\nto ensure that the Jdocs initialization occurs before the decision table initialization in the application. Please refer to the\nJDocs link above to get to know more about initializing and configuring JDocs.\n\n---\n\n### Prerequisites\n\nUnify-simple-decision-table works with Java 8 and later.\n\nMake sure that log4j configuration file is found in the class path. A sample file is provided in the test resources folder.\n\n### Quick start\n\n```java\n// initialize the decision table\nDecisionTable.init(\"my_app\", null);\n\n// create a decision table from a JSON file from the resources folder\nDecisionTable dt = DecisionTable.fromJson(\"/com/americanexpress/unify/decision_table/DTTest1.json\");\n\n// create a map of input values to pass into the decision table. The first value specifies the column name in the decision\n// table and the second value specifies the input value for that column. Note that it is the client's responsibility to ensure\n// that the data passed in matches the data type definition for the column        \nMap\u003cString, String\u003e values = new HashMap\u003c\u003e();\nvalues.put(\"score\", \"100\");\nvalues.put(\"yob\", \"1974\");\nvalues.put(\"code\", \"4GG\");\n\n// evaluate the input values against the decision table\nList\u003cMatchedRow\u003e list = dt.evaluate(values);\n\n// read the contents of the return rows(s)\nSystem.out.println(list.get(0).get(\"function\").getString());\nSystem.out.println(list.get(0).get(\"name\").getString());\nSystem.out.println(list.get(0).get(\"value\").getInteger());\n\n```\n\nAnd that is all there is to it.\n\n### Initializing decision tables\n\nA decision table can be initialized by using a `Configurator` object. The configurator can be initialized in a fluent\nmanner and can be passed to the static `init` method of `DecisionTable`.\n\n```java\npublic static void init(String systemName, Configuration conf);\n```\n\nThe parameter `systemName` is an arbitrary application name passed in by clients. Think of it as the application name\nin which the decision table implementation runs. This name is also returned to clients as part of the decision event\nnotification via the `eventHandler`.\n\nThe `Configuration` is the configuration object to use for initialization.\n\nThe following options can be set using the `Configuration` object.\n\n```java\npublic Configuration setEventHandler(EventHandler eventHandler)\npublic Configuration setAllowedClasses(List\u003cClass\u003c?\u003e\u003e allowedClasses)\npublic Configuration setDefaultRowValidationPolicy(RowValidationPolicy defaultRowValidationPolicy)\n```\n\nThe `eventHandler` object is a client provided Java object which implements the `EventHandler` interface. The decision\ntable delivers events to this object and this could be used to generate analytics for decision table usage.\n\nThe `allowedClasses` object is a list of classes that are allowed to be used in JEXL scripts across all decision tables.\nMore details are provided in the section on JEXL expressions later.\n\nThe `defaultRowValidationPolicy` object specifies the row validation policy to use while loading the decision table.\nThis policy is used if there is no row validation policy defined explicitly in the decision table. Please refer to the section\n'Row Validation Policy' in the breakdown of decision table below.\n\nBelow is an example of how we can use the configurator to initialize the decision table. Note that we need to do this\nonce at the start of the application.\n\n```Java\nConfiguration conf = new Configuration()\n        .setEventHandler(new TestHandler())\n        .setAllowedClasses(Arrays.asList(Integer.class)\n        .setDefaultRowValidationPolicy(RowValidationPolicy.STRICT);\nDecisionTable.init(\"Test\", conf);\n```\n\nNote that the `Configuration` object uses default values to initialize the decision table if any option is not specified. The default values are below:\n\n* NULL for event handler\n* NULL for allowedClasses\n* STRICT for default row validation policy\n\n### Creating an Excel based decision table\n\nTo create an Excel decision table, you can start with the provided template and copy it under a different name.\nThe template is provided in the main resources folder as `DecisionTableTemplateV1.xlsx`.\nPlease do not change the text / position of certain yellow highlighted cells as these are markers for the\nparser program to read the decision table contents correctly. Note that the column names, number of columns and the\ncolumn types are all sample values in the file and can be changed as per requirement.\nYou can add / delete rows and columns as long as:\n\n1. The first column marker is always in cell B5\n2. The last column marker is always in row 5 and after the first column marker\n3. The first row marker is always in cell A9\n4. The default row marker is always in column A and after the first row marker\n\nOnce you have created an Excel decision table, you could store in as a file in your `resources` folder. A couple of\ntest files are provided - `DTTest1.xlxs` and `DTTest2.xlxs` in the test `resources` folder.\n\nExcel based decision tables are loaded using the method `fromExcel` as below:\n\n```java\nDecisionTable dt = DecisionTable.fromExcel(\"/com/americanexpress/unify/decision_table/DTTest1.xlsx\");\n```\n\n### Creating a JSON based decision table\n\nTo create a JSON based decision table, one needs to adhere to the structure of a JSON decision table definition. The same is\nprovided in the main `resources` folder under the name `decision_table.json`.\n\nJSON based decision tables are loaded using the method `fromJson`. They can either be loaded from a file in the resources\nfolder or by providing the decision table definition as a JSON string.\n\nDecision tables loaded are assigned a name at the time of loading. This name is used internally to store decision\ntables in a cache for fast access. Only decision tables loaded from the resources folder are stored in the cache. Decision\ntables loaded from JSON strings are not. It is left to the clients to cache decision tables loaded from JSON strings\nshould they want it.\n\nShould clients require to explicitly unload a decision table from the internal cache, they can call the below method:\n\n```java\npublic static void unload(String decisionTableName)\n```\n\n#### Loading a JSON decision table using a file from the `resources` folder\n\nIn the snippet below, `DTTest1.json` is a file stored in the `resouces` folder in the path `/com/americanexpress/unify/decision_table`.\n```java\nDecisionTable dt = DecisionTable.fromJson(\"/com/americanexpress/unify/decision_table/DTTest1.json\");\n```\n\nIn the above scenario, the decision table name is set to the resource file path i.e. `/com/americanexpress/unify/decision_table/DTTest1.json`\n\n#### Loading a JSON decision table from a JSON string\n\nIn this scenario, it is left to the clients to read the decision table definition as a JSON string and provide a decision table name. Note\nthat such decision tables are not cached. It is also left to the clients to make sure that the decision table names do not\nclash. As a side note, decision table names are used when sending decision table events for analytics.\n\n```java\nString s = \"{...}\"; // string containing the decision table definition as a JSON string \nDecisionTable dt = DecisionTable.fromJsonString(\"my_decision_table_name\", s);\n```\n\nNote that the static method `fromJson(String, String)` is deprecated in favor of the above.\n\nOnce the decision table is loaded, further steps to work with the decision table in Java code remain the same irrespective\nof whether it was loaded from an Excel or from JSON file / string.\n\nJSON based decision tables can also be validated using the following method:\n\n```java\npublic static void validate(String json)\n```\n\nNote that the static method `validate(String, String)` is deprecated in favor of the above.\n\n### Break-down of a decision table\n\nBelow is a sample JSON based decision table which we will use to explain the various constituents:\n\n```json\n{\n  \"decision_table\": {\n    \"version\": \"1\",\n    \"match_policy\": \"first_match\",\n    \"no_match_policy\": \"return_default\",\n    \"row_validation_policy\": \"strict\",\n    \"cols\": [\n      {\n        \"name\": \"code\",\n        \"type\": \"evaluate\",\n        \"data_type\": \"string\"\n      },\n      {\n        \"name\": \"score\",\n        \"type\": \"evaluate\",\n        \"data_type\": \"integer\"\n      },\n      {\n        \"name\": \"value\",\n        \"type\": \"return\",\n        \"data_type\": \"string\"\n      },\n      {\n        \"name\": \"new_score\",\n        \"type\": \"return\",\n        \"data_type\": \"integer\"\n      }\n    ],\n    \"rows\": [\n      {\n        \"cols\": [\n          {\n            \"name\": \"code\",\n            \"value\": \"IN 4GG, 5FF, 7HH, U55\"\n          },\n          {\n            \"name\": \"score\",\n            \"value\": \"= 5\"\n          },\n          {\n            \"name\": \"value\",\n            \"value\": \"value_1\"\n          },\n          {\n            \"name\": \"new_score\",\n            \"value\": \"10\"\n          }\n        ]\n      },\n      {\n        \"cols\": [\n           {\n              \"name\": \"code\",\n              \"value\": \"IN 8HD, C56\"\n           },\n           {\n              \"name\": \"score\",\n              \"value\": \"\"\n           },\n           {\n              \"name\": \"value\",\n              \"value\": \"value_2\"\n           },\n           {\n              \"name\": \"new_score\",\n              \"value\": \"20\"\n           }\n        ]\n      },\n      {\n        \"cols\": [\n          {\n            \"name\": \"code\",\n            \"value\": \"= DSS\"\n          },\n          {\n            \"name\": \"score\",\n            \"value\": null\n          },\n          {\n            \"name\": \"value\",\n            \"value\": \"value_3\"\n          },\n          {\n            \"name\": \"new_score\",\n            \"value\": \"30\"\n          }\n        ]\n      }\n    ],\n    \"default_row\": [\n      {\n        \"name\": \"value\",\n        \"value\": \"default\"\n      },\n      {\n        \"name\": \"new_score\",\n        \"value\": null\n      }\n    ]\n  }\n}\n```\n\nThe corresponding Excel based decision table looks like below:\n\n![sample_excel_decision_table](sample_excel_decision_table.png)\n\n#### Version number\n\nSpecifies the version number of the decision table implementation and is found in the JSON path $.decision_table.version.\nIt is hard coded to 1 at present.\n\n#### Match Policy\n\nSpecifies the match policy for the decision table. This field can take on the following values:\n1. `first_match` - evaluation returns when the first match is found.\n2. `all_matches` - the input is evaluated against all rows and all matching rows are returned.\n\nThis field is defined in the JSON path $.decision_table.match_policy.\n\nThis field is case-insensitive.\n\n#### No Match Policy\n\nSpecifies the behaviour when no matches are found. This field can take on the following values:\n\n1. `return_default` - the contents of the return columns of the default row are returned.\n2. `return_none` - no rows are returned.\n\nThis field is defined in the JSON path $.decision_table.no_match_policy.\n\nThis field is case-insensitive.\n\n#### Row Validation Policy\n\nThis defines the validation policy for each row while loading a decision table. It can take on the following values:\n\n1. `strict` - all rows need to have all evaluation columns defined.\n2. `lenient` - rows can skip evaluate columns if they are to be ignored.\n\nNote that the row validation policy is only applicable to JSON decision tables. Excel decision tables always follow the strict\nvalidation policy as there is no scope to not specify a value (even if empty) for any evaluation column for any row.\n\nThis field is defined in the JSON path $.decision_table.row_validation_policy.\n\nIf this field is not defined, the default row validation policy set during initialization of the decision table is used.\n\nThis field is case-insensitive.\n\n#### Defining decision table columns\n\nThe decision table column definition consists of an array of columns in the path $.decision_table.cols. Each element\nin this array defines either an evaluate or a return column type. You can define the evaluate and return column\ntypes in any order, but for better understanding, we recommend to first define all evaluate columns and then all return columns.\n\n#### Column types\n\nDecision table can have the following two types of columns:\n\n1. `evaluate` columns - these are the evaluation columns. The input values passed into the decision table consists of\n   an input value for each such column. The input values are evaluated against the criteria specified in the cell for the column.\n2. `return` columns - these are the columns whose values are returned in case the evaluation columns are matched.\n\nThis field is case-insensitive.\n\n#### Column data types\n\nEach column has a data type. The following are the data types which can be assigned to each column.\n\n```java\npublic enum DataType {\n   STRING,\n   INTEGER,\n   LONG,\n   BOOLEAN,\n   DOUBLE,\n   BIGDECIMAL\n}\n```\n\nThis field is case-insensitive.\n\n#### Defining decision table rows\n\nIn a decision table, there could be multiple rows that contain the evaluation criteria against which the input values\nare evaluated. These rows are defined in the array $.decision_table.rows. Each element of this array consists\nof an array of columns (which correspond to the evaluate and return columns). Each element in the columns array is used to specify\nthe column name and the evaluation criteria or the return value.\n\n#### Operator types\n\nThe operator type must be specified as the starting value in an evaluation cell. For example, if we need to compare the\npassed in string value to \"America\", we will need to specify the following criteria in the evaluation cell:\n\n`= America`\n\nNote above that the first space after the operator is mandatory and is not part of the data.\n\nThe following operator types can be specified in the evaluation criteria for each column in the evaluation rows:\n\n```text\n  \u003e=\n  \u003e\n  =\n  \u003c\n  \u003c=\n  \u003c\u003e\n  IN\n  NOT_IN\n  ANY_CONTAINED_IN\n  NOT_ANY_CONTAINED_IN\n  ALL_CONTAINED_IN\n  NOT_ALL_CONTAINED_IN\n  CONTAINS_ALL\n  NOT_CONTAINS_ALL\n  ALL_EQUAL\n  MATCHES_REGEX\n```\nWe refer to the values that are passed into the decision table at run time (dynamically) by the program as input values.\nThe values against which the input values are evaluated i.e. the values specified in the cells of the evaluation\ncells in the decision table are referred to as evaluation values.\n\nWhile interpreting operators, the inputs values are always on the left hand side (LHS) and the evaluation values are\nalways on the right hand side (RHS). For example, if A is the input value and B is the evaluation value, then LT (\u003c)\noperator can be written as:\n\nA \u003c B meaning \"is A less than B?\"\n\nWe will use the above notation to explain the operators below.\n\n#### \\\u003e=, \u003e, =, \u003c, \u003c=, \u003c\u003e operators\n\nThese operators take in only one input value and specify only one evaluation value. The meaning of the operators is\nself-explanatory.\n\n#### IN operator\n\nThis operator takes in a single input value and evaluates against multiple evaluation values. The multiple evaluation\nvalues are comma separated. For example:\n\nA IN A, B, C -\u003e will match\n\nD IN A, B, C -\u003e will NOT match\n\nAny spaces after and before the comma are ignored i.e. the evaluation values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table.\n\n#### NOT_IN operator\n\nThis is the opposite of IN operator. This will return a match if the input value is not found in the evaluation values.\n\nD NOT_IN A, B, C -\u003e will match\n\nA NOT_IN A, B, C -\u003e will NOT match\n\nAny spaces after and before the comma are ignored i.e. the evaluation values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table.\n\n#### ANY_CONTAINED_IN operator\n\nThis operator takes in multiple comma separated input values and evaluates against multiple comma separated evaluation\nvalues.\n\nInput Values ANY_CONTAINED_IN evaluation values - this is to be read as \"is any input value contained in evaluation\nvalues?\"\n\nIt returns a match if any of the input values are found in the evaluation values. For example:\n\nA, B ANY_CONTAINED_IN A, C, D -\u003e will match as A is found\n\nA, C ANY_CONTAINED_IN A, C, D -\u003e will match as A and C are found but it is sufficient for only one to be found\n\nB ANY_CONTAINED_IN A, C, D -\u003e will NOT match as none found\n\nB, E ANY_CONTAINED_IN A, C, D -\u003e will NOT match as none found\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### NOT_ANY_CONTAINED_IN operator\n\nThis operator is the opposite of ANY_CONTAINED_IN operator. It means \"is any input value not contained in evaluation\nvalues?\". Examples below:\n\nA, B NOT_ANY_CONTAINED_IN A, C, D -\u003e will match as B is not found in evaluation values\n\nB NOT_ANY_CONTAINED_IN A, C, D -\u003e will match as B is not found\n\nB, E NOT_ANY_CONTAINED_IN A, C, D -\u003e will match as B is not found. The fact that E is also not found is irrelevant\n\nA, C NOT_ANY_CONTAINED_IN A, C, D -\u003e will NOT match as both A and C are found\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### ALL_CONTAINED_IN operator\n\nThis operator takes in multiple comma separated input values and evaluates against multiple comma separated evaluation\nvalues.\n\nInput Values ALL_CONTAINED_IN evaluation values - this is to be read as\n\"are all input values contained in evaluation values?\"\n\nIt returns a match if all the input values are found in the evaluation values. For example:\n\nA, B ALL_CONTAINED_IN A, B, C, D -\u003e will match as A and B are found in evaluation values\n\nA, B, A, B, A, B, C ALL_CONTAINED_IN A, B, C, D -\u003e will match as all found\n\nA, E ALL_CONTAINED_IN A, B, C, D -\u003e will NOT match as E not found\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### NOT_ALL_CONTAINED_IN operator\n\nThis operator takes in multiple comma separated input values and evaluates against multiple comma separated evaluation\nvalues. This operator is the opposite of ALL_CONTAINED_IN operator.\n\nInput Values NOT_ALL_CONTAINED_IN evaluation values - this is to be read as\n\"is none of the input values contained in evaluation values?\"\n\nIt returns a match if none of the input values are found in the evaluation values. For example:\n\nE, F NOT_ALL_CONTAINED_IN A, B, C, D -\u003e will match as E and F both are not found in evaluation values\n\nE, F, E, E, F NOT_ALL_CONTAINED_IN A, B, C, D -\u003e will match as all E and all F are not found in evaluation values\n\nA, B NOT_ALL_CONTAINED_IN A, B, C, D -\u003e will NOT match as A and B are found in evaluation values\n\nA, E NOT_ALL_CONTAINED_IN A, B, C, D -\u003e will NOT match as A is found\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### CONTAINS_ALL operator\n\nThis operator takes in multiple comma separated input values and evaluates against multiple comma separated evaluation\nvalues.\n\nInput Values CONTAINS_ALL evaluation values - this is to be read as\n\"are all the evaluation values present in the input values?\"\n\nIt returns a match if all the evaluation values are found in the input values. For example:\n\nA, B, C, D CONTAINS_ALL A, B -\u003e will match as both A and B are found in input values\n\nA, B, C, D CONTAINS_ALL A, A, A, B, B, C -\u003e will match as all are found in input values\n\nA, B, C, D CONTAINS_ALL A, E -\u003e will NOT match as E is not found in input values\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### NOT_CONTAINS_ALL operator\n\nThis operator takes in multiple comma separated input values and evaluates against multiple comma separated evaluation\nvalues. This operator is the opposite of CONTAINS_ALL operator.\n\nThis operator is similar to NOT_ALL_CONTAINED_IN operator except that the input and evaluation values are switched.\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### ALL_EQUAL operator\n\nThis operator takes in multiple comma separated input values and evaluates against multiple comma separated evaluation\nvalues.\n\nInput Values ALL_EQUAL evaluation values - this is to be read as\n\"are all the input values present in the evaluation values and vice versa?\"\n\nIt returns a match if all input values are present in the evaluation values and vice versa. The order of value on either\nside is not important. Values can also repeat on both sides. For example:\n\nB, A ALL_EQUAL A, B -\u003e will match\n\nB, A, B, A ALL_EQUAL A, B -\u003e will match\n\nB, C ALL_EQUAL A, B -\u003e will NOT match as C is not present in evaluation values\n\nA, B ALL_EQUAL C, B -\u003e will NOT match as C is not present in input values\n\nAny spaces after and before the comma are ignored i.e. the values are trimmed.\n\nEvaluation values are deduplicated at the time of loading the decision table. Input values are deduplicated before evaluation.\n\n#### MATCHES_REGEX operator\n\nThis operator evaluates the input value against a regex specified. Returns true if matched, else false.\n\n### A note on NULL and empty values\n\nPlease note the following while specifying values in evaluation or return cells:\n\n***For Excel based decision tables:***\n\nFor Excel based decision tables, for an evaluation or a return cell, one can ony specify an empty cell and there\nis no way to define a NULL value.\n\nAn empty evaluation cell is used to specify a don't care condition i.e. ignore evaluation of this cell.\n\nFor return cells, if we leave the value as blank in the Excel cell, to clients, it will be returned as NULL for non String\ndata types and as empty for String data types.\n\n***For JSON based decision tables:***\n\nFor JSON based decision tables, it is possible to either specify NULL or an empty string as the value in an evaluation cell\nor a return cell.\n\nFor evaluation cells, NULL and empty values are treated the same i.e. the evaluation for the cell will be ignored.\n\nFor return cells, NULL and empty both are returned as NULL for all non String data types and as empty for all String data types.\nThe rationale for this is that for non String data types, an empty value has no meaning -\nfor example, an empty value is not a valid integer, hence a NULL value is returned. For a String data type,\nwe could have returned NULL or empty as the case may be, but we decided to return empty to ease usage while checking return values and\nto have the same behaviour as in an Excel based decision table.\n\n### Validations during decision table loading\n\nDecision tables are validated for correctness when they are loaded (either from JSON or from Excel).\n\nThe following conditions are always validated while loading decision tables:\n\n1. No duplicate column names should exist\n2. All `rule_id` and `comments` columns must be of String type\n3. All values across rows for `rule_id` column must be unique\n\nFor JSON based decision tables, additionally, the following conditions are also validated:\n\n1. For decision tables that have `return_default` no match policy, a default row must be defined\n2. For decision tables that have `return_none` no match policy, a default row must not be defined\n3. Default row, if present, must contain only return columns\n\n### Other features\n\n#### Passing additional data to the decision table\n\nSometimes, there may be a need to have access to some additional data while evaluating the passed in values. The clients\ncan pass any Java object as additional input in the `evaluate` method. The `evaluate` method takes on the following signatures:\n\n```java\npublic List\u003cMatchedRow\u003e evaluate(Map\u003cString, String\u003e values);\npublic List\u003cMatchedRow\u003e evaluate(Map\u003cString, String\u003e values, Object input);\n```\n\nThe access to this Java object is only available to the external Java method specified in evaluation or in return\ncells (explained in the next section).\n\n#### Invoking Java code from within decision table\n\nIt is possible to specify a method of a class to be executed as the RHS when evaluating the passed in value or\nwhile returning a value for a return column. To use this feature, enter the value of an evaluation or a return cell as \"#fully\nqualified method path\" and define your class to implement this method. Make sure that this class is found\nin the classpath. Additionally, the method must have the following signature:\n\n`\nObject method_name(Map\u003cString, String\u003e input, Object additionalInput)\n`\n\nFor example, create a class `TestInvokable` and an execute method in the class and enter\n\"#com.americanexpress.unify.base.decision_table.TestInvokable.execute\" in the evaluation / return cell. If the row is matched, then\nthe class `TestInvokable` will be instantiated and `execute` method called on the object of this class.\nThe execute method will receive the map of input values passed to the decision table as well as a custom input object\npassed by the client.\n\nPlease refer to the method `testInvokable` in the file `DecisionTableTest` in the test folder for a sample.\n\n#### Invoking JEXL script from within decision table\n\nIt is possible to invoke a JEXL script for returning a value from the return columns. To invoke a script,\nspecify the script in the return cell value starting with ?. Each input key is automatically\nfed into the JEXL context as a JEXL variable. Note that since we pass all input values as strings, it is left to the client\nto convert to appropriate types in the script.\n\nIf the script contains any reference to a Java object, then the class for that Java object needs to be explicitly\ndefined upfront while initializing the decision table as part of the `Configuration` object. This is to ensure\nthat no arbitrary code execution can take place and that code execution is restricted to the set of Java classes pre-defined\nby the application (while initializing the decision table).\n\nFor example, we could have a JEXL script as below. In this script, the Java class Long would need to be defined while\ninitializing the decision table. Also note the use of #pragma while using Java classes in the script. More information on\nhow to create scripts can be looked up in JEXL documentation.\n\n```jexl\n\"value\": \"?#pragma jexl.namespace.Long java.lang.Long; var i = Long:parseLong(yob); return (i + 20);\"\n```\n\nPlease refer to the tests `testJexl`, `testJexl1` and `testJexl2` in the file `DecisionTableTest` for the usage of this\nfeature.\n\nDecision tables are loaded when they are accessed and have an idle time associated with them. The idle time is the\nduration of time for which the decision\ntable has not been accessed. On idle time expiry, the decision tables are off loaded from system memory. They are\nautomatically loaded\nagain when invoked. This helps to conserve system resources.\n\n#### Converting an Excel decision table to JSON\n\nAn existing Excel decision table can be converted to a JSON decision table by using the class `ExcelToJson`.\n\nUse the below method to look for Excel decision table files across all folders and its sub folder and convert them to\nJSON in one go.\n\n```java\npublic static List\u003cString\u003e createJsonFiles(String baseDirPath,String filePattern)\n```\n\nThis method takes in a root folder as the first parameter (for example `c:/folder` without a trailing slash)\nand the suffix pattern for Excel files as the second parameter (for example `.xlsx') and traverses\nrecursively through the folder to look for Excel files to convert. Note RECURSIVELY. The JSON file is created in the\nsame location\nwith the Excel file suffix replaced by .json as the suffix. Existing files will be replaced.\n\nUse the below method to convert a single Excel decision table file to JSON.\n\n```java\npublic static void createJsonFile(String filePath)\n```\n\nThis method takes in the complete file path of the Excel file to be converted (for example `c:/folder/1.xlsx').\nThe JSON file is created in the same location with the Excel file suffix replaced by .json as the suffix. Existing files\nwill be replaced.\n\n#### Converting a JSON decision table to Excel\n\nDecision tables that contain a high number of columns / rows can be difficult to visualize in JSON format. It is\nquite helpful if we could view these decision tables in Excel for the purpose of analysis. We can do this by using\nthe class `JsonToExcel`.\n\nUse the below method to look for JSON decision table files across all folders and its sub folder and convert them to\nExcel in one go.\n\n```java\npublic static List\u003cString\u003e createExcelFiles(String baseDirPath, String filePattern)\n```\n\nThis method takes in a root folder as the first parameter (for example `c:/folder` without a trailing slash)\nand the suffix pattern for JSON files as the second parameter (for example `.json') and traverses\nrecursively through the folder to look for JSON files to convert. Note RECURSIVELY. The Excel file is created in the\nsame location\nwith the JSON file suffix replaced by .xlsx as the suffix. Existing files will be replaced.\n\nUse the below method to convert a single JSON decision table file to Excel.\n\n```java\n  public static void createExcelFile(String filePath)\n```\n\nThis method takes in the complete file path of the JSON file to be converted (for example `c:/folder/1.json').\nThe Excel file is created in the same location with the JSON file suffix replaced by .xlsx as the suffix. Existing files\nwill be replaced.\n\n#### Rules Loaded Event\n\nThis event is emitted when the decision table is loaded for the first time. A sample is given below:\n\n```json\n{\n  \"decision_table_event\": {\n    \"system_name\": \"Test\",\n    \"event_name\": \"RULES_LOADED\",\n    \"table_name\": \"/com/americanexpress/unify/decision_table/name.json\",\n    \"table_size\": 2,\n    \"rules\": [\n      {\n        \"rule_id\": \"rule_1\",\n        \"comments\": \"\"\n      },\n      {\n        \"rule_id\": \"rule_2\",\n        \"comments\": \"\"\n      }\n    ]\n  }\n}\n```\n\nIn the above, table size specifies the number of rows in the table including the default row if present.\n\nThe `rules` array specifies, for each row, the values of the columns that have `rule_id` and `comments` type.\n\nIf there are no columns with these column types, the 1 index based row number is used as value for `rule_id` and\nempty for `comments`.\n\n#### Match Fired Event\n\nThis event is emitted for all matches encountered when the decision table is evaluated. A sample is given below:\n\n```json\n{\n  \"decision_table_event\": {\n    \"system_name\": \"Test\",\n    \"event_name\": \"MATCH_FIRED\",\n    \"table_name\": \"/com/americanexpress/unify/decision_table/name.json\",\n    \"table_size\": 2,\n    \"input\": [\n      {\n        \"col_name\": \"code\",\n        \"col_type\": \"STRING\",\n        \"value\": \"4GG\"\n      },\n      {\n        \"col_name\": \"score\",\n        \"col_type\": \"LONG\",\n        \"value\": \"90\"\n      },\n      {\n        \"col_name\": \"yob\",\n        \"col_type\": \"INTEGER\",\n        \"value\": \"2014\"\n      }\n    ],\n    \"result\": [\n      {\n        \"rule_id\": \"rule_default\",\n        \"comments\": \"\",\n        \"row_num\": 1,\n        \"values\": [\n          {\n            \"col_name\": \"function\",\n            \"col_type\": \"STRING\",\n            \"value\": \"foo4\"\n          },\n          {\n            \"col_name\": \"name\",\n            \"col_type\": \"STRING\",\n            \"value\": \"\"\n          },\n          {\n            \"col_name\": \"value\",\n            \"col_type\": \"INTEGER\",\n            \"value\": \"4\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nIn the above, table size specifies the number of rows in the table including the default row if present.\n\nThe `input` array specifies the input to the decision table.\n\nThe `result` array specifies the details of the row(s) matched. For decision tables that have the no match policy\nof return none, for a no match, this block is omitted.\n\nIn the `result` array, the following are the fields output:\n\n`rule_id` - specifies the rule id value for the row. If rule id for the row is not specified, 1 index based row number is returned.\n\n`comments` - specifies the comments value for the row.\n\n`row_num` - specifes the 1 index based row number of the matched row.\n\n`values` - an array that specifies the values of the return columns of the matched row.\n\nWhile capturing events in the application, it would be worth pointing out, that in heavily used systems, the number\nof events generated could be quite high. To address this, the application may need to create an implementation where either:\n\n1) a bounded queue is used to store events awaiting processing - in which case, events arriving at a time when the queue is full\n   could be ignored\n2) or an unbounded queue is used to hold events - which introduces the risk of JVM going out of memory if the load is high and events\n   are not being processed fast enough\n3) or a bounded blocking queue is used if the application is OK to wait till space is available in the queue\n\n### What next?\n\nGo through the unit test cases in the source code. Unit test cases are available in the location `src/test`\n\nProvide us feedback. We would love to hear from you.\n\n### Author:\n\nDeepak Arora, GitHub: @deepakarora3, Twitter: @DeepakAroraHi\n\n## Contributing\n\nWe welcome Your interest in the American Express Open Source Community on Github. Any Contributor to any Open Source\nProject managed by the American Express Open Source Community must accept and sign an Agreement indicating agreement to\nthe terms below. Except for the rights granted in this Agreement to American Express and to recipients of software\ndistributed by American Express, You reserve all right, title, and interest, if any, in and to Your Contributions.\nPlease\n[fill out the Agreement](https://cla-assistant.io/americanexpress/unify-simple-decision-table).\n\n## License\n\nAny contributions made under this project will be governed by the\n[Apache License 2.0](./LICENSE.txt).\n\n## Code of Conduct\n\nThis project adheres to the [American Express Community Guidelines](./CODE_OF_CONDUCT.md). By participating, you are\nexpected to honor these guidelines.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famericanexpress%2Funify-simple-decision-table","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famericanexpress%2Funify-simple-decision-table","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famericanexpress%2Funify-simple-decision-table/lists"}