Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Uses the concept of sessions to buckets in order to give a logical separation between different scopes. For example, "config" could be a bucket to store all data related to the configurations scope, and it will be represented as a folder in the local file system provider.

@Inject
protected BinaryDataService binaryDataService;

protected BinaryDataServiceSession session;


@PostConstruct
void init() {
  session = binaryDataService.newSession("config");
}


public void storeConfig(String key, InputStream inputStream) {
  session.store(key, inputStream);
}


public Optional<InputStream> findConfig(String key) {
  return session.find(key);
}

...

PropertyTypeDefaultDescription
initialCapacityInteger16The minimum size of the cache
maximumSizeLongThe maximum size of the cache. Can not be combined with a weigher
maximumWeightLongThe maximum weight to be allowed for an element in the cache (see Weigher section)
expireAfterWriteDurationThe time to wait to expire an element after its creation
expireAfterAccessDuration5mThe time to wait to expire an element after the last time it was accessed
recordStatsbooleantrueTo record statistics about hit rates and evictions (see Cache Statistics section)
testModebooleanfalseTo execute all cache operations in a single thread

...

If the cache statistics are enabled, they will be published as part of the application metrics:

  • cache.eviction.weight - the sum of weights of evicted entries
  • cache.evictions - the count of cache evictions
  • cache.size - the estimated number of entries in the cache
  • cache.gets - the number of times a cache-annotated method has returned an item (regardless if it was cached or not). This metric can be refined with the use of tags:
    • result:hit - the number of times cache lookup methods have returned a cached value
    • result:miss - the number of times cache lookup methods have returned an uncached value

...

PropertyTypeDefaultDescription
maxCountIntegerThe maximum number of elements before flushing. Triggers a Count flush
maxDataSizeLongThe maximum size of the collection elements before flushing. Triggers a Data Size flush
flushAfterDurationThe duration before flushing. Triggers a Scheduled flush
threadsInteger5The number of threads used to execute the flush event
flushTimeoutDuration10mThe timeout for the flush event

...

Function to determine the size of an element. Required to trigger a Data Size flush. For instance, a collection of integer elements can define its weigher as:

...

Consumer to be executed if the flush handler was successfully executed. For instance, a success handler for a collection of integer elements can be defined as:

...

BiConsumer to be executed if the flush handler failed. For instance, a failure handler for a collection of integer elements can be defined as:

...

Each collection will publish metrics about the duration of each flush event, its size, and the count of success/failures (see Metrics section).

This can be refined with the use of custom tags during the creation of the collection:

...

{
  "or": [
    {
      "equals": {
        "field": "fieldA",
        "value": "valueA"
      }
    }, {
      "equals": {
        "field": "fieldB",
        "value": "valueB"
      }
    }
  ]
}

EvalEx

EvalEx is a lightweight library capable of processing numeric, logical, conditional, String, array and structure-based expressions at runtime. It doesn’t need any external dependencies. Some minor functionalities such as support for hexadecimal and implicit multiplication are present. None of the functions are null safe due to the conversion of the parameters to EvaluationValue during processing.

Example of basic expression evaluation without variables or configuration.

var input = "5 * 2";
var expression = new Expression(input);
var rawResult = expression.evaluate();
int finalResult = rawResult.getNumberValue().intValue();

If the expression has variables, a Map with the value of said variables must be provided.

var input = "x * y";
Map<String, Object> variables = new HashMap<>();
variables.put("x", "5");
variables.put("y", "2");
var expression = new Expression(input);
var rawResult = expression.withValues(variables).evaluate();
int finalResult = rawResult.getNumberValue().intValue();

Exceptions

The library provides two new exceptions which must be handled. A ParseException is thrown, when the expression could not be parsed. An EvaluationException is thrown, when the expression could be parsed, but not evaluated. If possible, both exceptions report the following details:

  • Start Position of the error (character position, starting with 1).
  • End Position of the error (character position, starting with 1).
  • The Token string, usually the operator, function, variable or literal causing the error.
  • The error message.

Default Functions

Although the default operators and functions are not explicitly listed in the official documentation, they can be seen in the ExpressionConfiguration class.

FunctionDescriptionExample
ABSReturns the absolute value of a valueABS(-7) = 7
CEILINGRounds a number towards positive infinityCEILING(1.1) = 2
FACTReturns the factorial of a numberFACT(5) = 120
FLOORRounds a number towards negative infinityFLOOR(1.9) = 1
IFConditional operation where if the first parameter is true, the second one is executed. If not, the third parameter is executedIF(TRUE, 5+1, 6+2) = 8
LOGPerforms the logarithm with base e on a valueLOG(5) = 1.609
LOG10Performs the logarithm with base 10 on a valueLOG10(5) = 0.698
MAXReturns the highest value from all the parameters providedMAX(5, 55, 6, 102) = 102
MINReturns the lowest value from all the parameters providedMIN(5, 55, 6, 102) = 5
NOTNegates a boolean expressionNOT(True) = false
RANDOMReturns random number between 0 and 1RANDOM() = 0.1613...
ROUNDRounds a decimal number to a specified scaleROUND(0.5652,2) = 0.57
SUMReturns the sum of the parametersSUM(0.5, 3, 1) = 4.5
SQRTReturns the square root of the value providedSQRT(4) = 2
ACOSReturns the arc-cosine in degreesACOS(1) = 0
ACOSHReturns the hyperbolic arc-cosine in degreesACOSH(1.5) = 0.96
ACOSRReturns the arc-cosine in radiansACOSR(0.5) = 1.04
ACOTReturns the arc-co-tangent in degreesACOT(1) = 45
ACOTHReturns the hyperbolic arc-co-tangent in degreesACOTH(1.003) = 3.141
ACOTRReturns the arc-co-tangent in radiansACOTR(1) = 0.785
ASINReturns the arc-sine in degreesASIN(1) = 90
ASINHReturns the hyperbolic arc-sine in degreesASINH(6.76) = 2.61
ASINRReturns the arc-sine in radiansASINR(1) = 1.57
ATANReturns the arc-tangent in degreesATAN(1) = 45
ATAN2Returns the angle of arc-tangent2 in degreesATAN2(1, 0) = 90
ATAN2RReturns the angle of arc-tangent2 in radiansATAN2R(1, 0) = 1.57
ATANHReturns the hyperbolic arc-tangent in degreesATANH(0.5) = 0.54
ATANRReturns the arc-tangent in radiansATANR(1) = 0.78
COSReturns the cosine in degreesCOS(180) = -1
COSHReturns the hyperbolic cosine in degreesCOSH(PI) = 11.591
COSRReturns the cosine in radiansCOSR(PI) = -1
COTReturns the co-tangent in degreesCOT(45) = 1
COTHReturns the hyperbolic co-tangent in degreesCOTH(PI) = 1.003
COTRReturns the co-tangent in radiansCOTR(0.785) = 1
CSCReturns the co-secant in degreesCSC(270) = -1
CSCHReturns the hyperbolic co-secant in degreesCSCH(3*PI/2) = 0.017
CSCRReturns the co-secant in radiansCSCR(3*PI/2) = -1
DEGConverts an angle from radians to degreesDEG(0.785) = 45
RADConverts an angle from degrees to radiansRAD(45) = 0.785
SINReturns the sine in degreesSIN(150) = 0.5
SINHReturns the hyperbolic sine in degreesSINH(2.61) = 6.762
SINRReturns the sine in radiansSINR(2.61) = 0.5
SECReturns the secant in degreesSEC(120) = -2
SECHReturns the hyperbolic secant in degreesSECH(2.09) = 0.243
SECRReturns the secant in radiansSECR(2.09) = -2
TANReturns the tangent in degreesTAN(360) = 0
TANHReturns the hyperbolic tangent in degreesTANH(2*PI) = 1
TANRReturns the tangent in radiansTANR(2*PI) = 0
STR_CONTAINSReturns true if string contains substring or false if not (case sensitive)STR_CONTAINS("Hoy es", "Hoy") = true
STR_LOWERConverts all the characters of a string to upper caseSTR_LOWER("HOY ES") = hoy es
STR_UPPERConverts all the characters of a string to upper caseSTR_UPPER("hoy es") = HOY ES

Expression Configuration

The expression evaluation can be configured to enable and disable specific features.

FeatureDescriptionDefaults
allowOverwriteConstantsAllows variables to have the name of a constantTrue
arraysAllowedAllows array index functionsTrue
dataAccessorSupplierThe Data Accessor is responsible for storing and retrieving variable values. You can define your own data access interface, by defining a class that implements the DataAccessorInterfaceMapBasedDataAccessor
decimalPlacesRoundingSpecifies the amount of decimal places to round to in each operation or functionDisabled
defaultConstantsSpecifies the default constants that can be used in every expressionExpressionConfiguration.StandardConstants
functionDictionaryThe function dictionary is used to look up the functions that are used in an expression. You can define your own function directory, by defining a class that implements the FunctionDictionaryIfcMapBasedFunctionDictionary
implicitMultiplicationAllowedAllows for automatic multiplication without operatorsTrue
mathContextSpecifies the precision and rounding methodPrecision: 68, Mode: HALF-EVEN
operatorDictionaryThe operator dictionary is used to look up the functions that are used in an expression. You can define your own operator directory, by defining a class that implements the OperatorDictionaryIfcMapBasedOperatorDictionary
powerOfPrecedenceAllows changes to the operation precedenceLower precedence
stripTrailingZerosAllows the trailing decimal zeros in a number result to be strippedTrue
structuresAllowedSpecifies if the structure separator (‘.’) operator is allowedTrue

Custom Functions

Personalized functions can be added with the expression configuration. For this process a new class that extends AbstractFunction. In this class @FunctionParameter tags must be added to class. These will signify the parameters needed to use the function. Lastly, an override to the evaluate method is needed to implement the custom function's logic. This functions can be called recursively.

This class is an example of a basic custom function which adds 5 to the parameter provided.

@FunctionParameter(name = "value")
public class AddFiveFunction extends AbstractFunction {

  @Override
  public EvaluationValue evaluate(Expression expression, Token functionToken, EvaluationValue... parameterValues) throws EvaluationException {
    EvaluationValue value = parameterValues[0];
    return new EvaluationValue(value.getNumberValue().doubleValue()+5.0);
  }
}

The function is then added to the evaluated expression via an ExpressionConfiguration object at evaluation time.

ExpressionConfiguration configuration = ExpressionConfiguration.
  defaultConfiguration().withAdditionalFunctions(
  Map.entry("ADDFIVE", new AddFiveFunction()));
var input = "ADDFIVE(5)";
var expression = new Expression(input, configuration);
var rawResult = expression.evaluate();
int finalResult = rawResult.getNumberValue().intValue();

Custom Operators

Much like functions, custom operators can be added. To do this, a new class that extends AbstractOperator is needed. A tag must be added to specify if the operator must be used as prefix, postfix or infix. The tag also specifies the precedence using a value for comparison. The value of the other operators can be seen in the OperatorIfc for reference. If no value is specified, the operator will have the highest precedence.

This class is an example of a basic custom function which adds 5 to the parameter provided.

@PrefixOperator(precedence = 1)
public class TimesThreeOperator extends AbstractOperator {

  @Override
  public EvaluationValue evaluate(Expression expression, Token operatorToken, EvaluationValue... operands) throws EvaluationException {
    return new EvaluationValue(operands[0].getNumberValue().intValue()*3);
  }
}

The operator is then added to the evaluated expression via an ExpressionConfiguration object at evaluation time.

ExpressionConfiguration configuration = ExpressionConfiguration.
  defaultConfiguration().withAdditionalOperators(
  Map.entry("@", new TimesThreeOperator()));
var input = "@3";
Expression expression = new Expression(input, configuration);
return expression.evaluate();

EvalEx Utils

The EvalExUtils class contains methods made to facilitate the processes that may use the Expression Language evaluator.

Array Converters

When an array is evaluated all of its contents are converted to an EvaluationValue object. This renders the resulting array useless if not processed. To simplify this, 4 array converters were included to convert an EvaluationValue array to an Integer, String, Boolean or plain Object array.

Added Functions

System Function

SystemFunction gets a System property or Environment Variable value given it's key. The System property has precedence. If no System property or Environment variable is found, an EvaluationException is thrown with the message "No such system parameter or environment variable". It is used with the SYSTEM tag. E.g. SYSTEM(java.runtime.version) = 17.0.6+10 (result may vary).

Encrypt and Decrypt Functions

EncryptFunction encrypts the given content using the encryption method in CryptoUtils. It is used with the ENCRYPT tag. E.g. ENCRYPT("Test") = (Encrypted string for "Test"). DecryptFunction decrypts an encrypted content using the decryption method in CryptoUtils. It is used with the DECRYPT tag. E.g. DECRYPT(Encrypted string for "Test") = Test.

Regex Match Function

RegexMatchFunction returns a boolean specifying if a string matches a given pattern. It is used with the REGEX_MATCH tag. E.g. REGEX_MATCH("This is a Test", ".t") = true.

Ends With and Starts with Functions

EndsWithFunction verifies with a boolean if a string ends with a given substring. It is used with the STR_ENDSWITH tag. E.g. STR_ENDSWITH("This is a test","test") = true. StartsWithFunction verifies with a boolean if a string starts with a given substring. These functions are case-sensitive. It is used with the STR_STARTSWITH tag. E.g. STR_STARTSWITH("This is a test","This") = true.

Is Empty and Is Blank Functions

IsBlankFuction verifies with a boolean if a string is blank. It is used with the tag STR_ISBLANK tag. E.g. STR_ISBLANK(" ") = true. IsEmptyFunction verifies with a boolean if a string is empty. It is used with the tag STR_ISEMPTY tag. E.g. STR_ISEMPTY("") = true.

Split Function

SplitFunction splits a given string by a given token. The resulting array contains EvaluationValue objects, therefore the substrings must be converted back to strings. It is used with the STR_SPLIT tag. E.g. STR_SPLIT("This is a Test", "") = {"This", "is", "a", "test"}.

Concat Function

ConcatFunction concatenates any given set of strings. It is used with the STR_CONCAT tag. E.g. STR_CONCAT("This", "is", "a", "test") = "This is a Test".

Array Join Function

ArrayJoinFunction concatenates two given arrays of the same type into one array. It is used with the ARR_JOIN tag. The resulting array will be an Object[], therefore it must be processed with the arrayFactoryProcessor. E.g. JOIN(list1, list2) = (1, 2, 3, 4, 5, 6) with list1 = (1, 2, 3) and list2 = (4, 5, 6) being variables.

Array Contains Function

ArrayContainsFunction verifies if an array contains a given value. It is used with the ARR_CONTAINS tag. E.g. ARR_CONTAINS(array, 1) = true, with array = (1, 2, 3) being a variable.

Get By Index Function

GetByIndexFunction provides the value in the given index. It is used with the ARR_GET tag. E.g. ARR_GET(array, 0) = "This", with array = ("This", "is", "a", "test") being a variable.

Array Is Empty Function

ArrayIsEmptyFunction provides a boolean specifying if an array is Empty. It is used with the ARR_ISEMPTY tag. E.g. ARR_ISEMPTY(array) = true, with array = () being a variable.

Array Size Function

ArraySizeFunction provides the value in the given index. It is used with the ARR_SIZE tag. E.g. SIZE(array) = 3, with array = (1, 2, 3) being a variable.

HTTP Base Client

The HTTP Base Client is an abstraction of the OkHttpClient. It provides features such as retry handlers (see Retries) and automated paginated requests.

...

PropertyTypeDefaultDescription
bodybyte[]The body of the message.
queueStringThe queue this message was sent to or delivered from.
typeMessage.MessageTypeThe type of the message. Can be DIRECT or BROADCAST. See Message Types.
propertiesMap<String,String>Map of message properties.

...

ParameterTypeDescription
queueStringName of the queue to register the Consumer to.
consumerPropertiesConsumerPropertiesA ConsumerProperties instance for the consumer.
messageTypeMessage.MessageTypeThe type of message this consumer is supposed to listen to. Can be Message.MessageType.DIRECT or Message.MessageType.BROADCAST. See Message Types.
onMessageDeliveryPredicate<Message>The function to execute when a message is received. Returns true if the message is successfully consumed, false otherwise.

...

ParameterTypeDescription
messageMessageThe Message to send.
successHandlerConsumer<Message>A consumer function to execute when the message is succesfully sent.
failureHandlerBiConsumer<Message, Exception>A biconsumer function to execute when there is an error sending the message and the retries have been exhausted.

...

ParameterTypeDescription
messageMessageThe Message to send.

Providers

RabbitMQ

...