[ 
https://issues.apache.org/jira/browse/APEXMALHAR-1972?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15095872#comment-15095872
 ] 

Chinmay Kolhatkar edited comment on APEXMALHAR-1972 at 1/13/16 9:29 AM:
------------------------------------------------------------------------

h2. Objective
Purpose of ExpressionEvaluator is taking PojoUtils to a next level and getting 
closer to as quasi-Java Expression language.
The idea of ExpressionEvaluator is an attempt to have a quasi-Java expression 
language of DT/Apex Platform.

Expression evaluator is a library which evaluates a given quasi-Java expression 
and gives a return value after executing expression. 
The expression can be based in multiple POJOs,  multiple fields, nested POJOs 
or even a simple Java types.

This does not mean that PojoUtils can be replaced by ExpressionEvaluator. 
I would still say they will serve different purposes and if one wants to use a 
simple expression, PojoUtils is still the way.

h2. Prerequisites/Requirements
Expression Evaluator requires following libraries:
* Janino
* Apache commons.

h2. Functionality
Following functionality is expected to be provided by Expression Evaluator:
* Support quasi-Java Expression which defines a single line executable 
expression
* Support for quasi-Java expression based function code, which will be compiled 
on the fly and made available for execution.
* Should support accessing multiple fields from multiples input POJOs while 
addressing the conversion of private variables to public getter method for all 
levels.
* Should support nested field support
* quasi-Java expressions should support operands to be mentioned in following 
ways:
** ${input.fieldName} - Access fieldName via a object name.
** ${fieldName} - Accessing fieldName directly when a single object is 
registered for operation.
** ${input} - Accessing object variable directly
** ${input.fieldName.internalField} - Accessing nested fields
* There should be some predefined function provided to expression writer which 
one can directly use in expression for invoking certain functionality.
  These are simple String based, Date time based etc functions.
* On-need-basic one should be able to easily update Expression Evaluator to 
easily add new predefined functions to be made available for expression writer.
* User of ExpressionEvaluator should be able to add a custom method externally 
to be made available to in expression.
* Though operands are defined, placeholder for the operand in expression should 
be allowed to be overridden. By default, expression language should support 
bash type syntax for operand - {...}
* The library should not introduce any serialization related issues.

h2. quasi-Java Expression Language Examples
Given below are few examples using which expression language can be learn and 
adopted:

 || Expression || Task done by expression || Result of expression || 
 | {code} ${inp.field1} {code} | Access field1 from given POJO with placeholder 
“inp” | Will return value of field1 from given POJO | 
 | {code} ${inp.field1} + ${inp.field2} {code} | Perform addition | Will return 
addition of field1 & field2 from input POJO | 
 | {code} ${field1} + ${field2} {code} | Perform addition | Will return 
addition of field1 & field2 from input POJO. Will work with only single POJO 
input parameter. | 
 | {code} ${inp.field1} > 0 ? ${inp.field2} : ${inp.field3} {code} | JAVA 
ternary expression | Will return value of field2 from POJO if field1 is 
positive else field3 is returned | 
 | {code} ${inpA.field1} * ${inpA.field2} > 0 ? ${inpB.field1} : ${inpB.field2} 
{code} | JAVA ternary expression | Will return value of field1 from inpB if 
product of field1 & field2 from inpA is positive. Else return value of field2 
from inpB. | 
 | {code} (${inpA.field1} == ${inpA.field2}) && (${inpB.field1} == 
${inpB.field2}) {code} | Condition evaluation | Will return true if field1 & 
field2 from both inpA & inpB are same. | 
 | {code} equals(${inpA.field1}, ${inpB.field1}) {code} | Condition evaluation 
| Will return true if field1 from both inpA & inpB are same string. | 
 | {code} pow(${field1}, ${field1}) {code} | Exponent operation | Will return 
result of field1 to the power field2 from input POJO. | 

h2. Design of Expression Evaluator
h3. ExpressionEvaluator class
ExpressionEvaluator class takes input as expression in string format and 
expected return type and gives an instance of Expression Interface object which 
can be executed.
The class uses Janino to convert provided Java Expression to a compiled code 
and insert it to running JVM instance.
The class will be added to malhar-library in package 
com.datatorrent.lib.expressions.

h3. Expression interface
Expression interface is generic type interface which contains a single method 
called execute. _execute_ method executes compiled expression against variable 
number of Objects passed and returns the result of the expression. The return 
type of this method is generic and need to be passed on when 
ExpressionEvaluator compiles the expression.

h3. Public methods
* *ExpressionEvaluator constructor*
This is an empty constructor which constructs the ExpressionEvaluator class for 
the purpose of kryo serialization.

* *setInputObjectPlaceholders(String[] inputObjectPlaceholders, Class[] 
classTypes)*
Using this method library user can provide the mapping of object placeholder to 
its expected types. classType parameter refers the Class of input object 
referred as a placeholder in inputObjectPlaceholder parameter at the same index.
The object passed to execute method of Expression interface should be in same 
order as provided here.
For eg. 
{code:java}
setInputObjectPlaceholders(new String[]{"inpA", "inpB"}, new 
Class[]{TypeA.class, TypeB.class});
{code}          
Above call to the method registers 2 placeholders for objects called inpA & 
inpB of type TypeA & TypeB that might appear in expression provided for 
compilation. This means execute method will expected 2 Object parameters in the 
same order as their class types and placeholders when execution of compiled 
expression happens.

* *createExecutableExpression(String expression, Class<?> returnType)*
This is the main method in ExpressionEvalator class which compiles the given 
string expression and generates a Interface of type Expression having a execute 
method which return object of type returnType.
Internally, the expression is parsed as be Expression Lauguage constructs and 
converted into a compiled Java code which gets injected into running JVM. This 
method uses Janino library.

* *createExecutableFunction(String expression, Class<?> returnType)* 
This method is similar to createExecutableExpression expect the expression can 
contain a complete method’s content.
This means the expression can have all types of constructs which can be 
provided in a Java method.

* *addImports(String importPackage)*
This method adds any given package to the default list of default imports.The 
import that are added here can be directly used inside Expression.

* *overrideImports(String[] importPackages)*
This method overrides the list of default imports currently set for expression 
evaluation. Except java.lang will remain there.

* *registerCustomMethod(String qualifiedFunc)*
This method can add a public static custom function to be made available while 
expression evaluation. 
The parameter passed to the function should be qualified function name i.e. it 
should be prepended with classname as well.

For eg. 
Lets say there is a class which has public static function:
{code:java}
package com.package.name.something;
public class Example
{
  public static compute(<params>)
  {
    <operations>
  }
}
{code}

Calling _registerCustomMethod("com.package.name.something.Example.compute")_ 
will add compute method to be directly 
available in Expression Language.

h2. Predefined functions in Expression language
By default all the public static methods in following classes can be invoked 
i.e. called in in Expression.

h3. From other libraries
# java.lang.Math.*
# org.apache.commons.lang3.StringUtils.*
# org.apache.commons.lang3.StringEscapeUtils.*
# org.apache.commons.lang3.time.DurationFormatUtils.*
# org.apache.commons.lang3.time.DateFormatUtils.*
# org.apache.commons.lang3.time.DateUtils.*

h3. Custom ones
# com.datatorrent.lib.expressions.ConversionUtils.*
# com.datatorrent.lib.expressions.StringUtils.*
# com.datatorrent.lib.expressions.DateTimeUtils.*



was (Author: chinmay):
h2. Objective
Purpose of ExpressionEvaluator is taking PojoUtils to a next level and getting 
closer to as quasi-Java Expression language.
The idea of ExpressionEvaluator is an attempt to have a quasi-Java expression 
language of DT/Apex Platform.

Expression evaluator is a library which evaluates a given quasi-Java expression 
and gives a return value after executing expression. 
The expression can be based in multiple POJOs,  multiple fields, nested POJOs 
or even a simple Java types.

This does not mean that PojoUtils can be replaced by ExpressionEvaluator. 
I would still say they will serve different purposes and if one wants to use a 
simple expression, PojoUtils is still the way.

h2. Prerequisites/Requirements
Expression Evaluator requires following libraries:
* Janino
* Apache commons.

h2. Functionality
Following functionality is expected to be provided by Expression Evaluator:
* Support quasi-Java Expression which defines a single line executable 
expression
* Support for quasi-Java expression based function code, which will be compiled 
on the fly and made available for execution.
* Should support accessing multiple fields from multiples input POJOs while 
addressing the conversion of private variables to public getter method for all 
levels.
* Should support nested field support
* quasi-Java expressions should support operands to be mentioned in following 
ways:
** ${input.fieldName} - Access fieldName via a object name.
** ${fieldName} - Accessing fieldName directly when a single object is 
registered for operation.
** ${input} - Accessing object variable directly
** ${input.fieldName.internalField} - Accessing nested fields
* There should be some predefined function provided to expression writer which 
one can directly use in expression for invoking certain functionality.
  These are simple String based, Date time based etc functions.
* On-need-basic one should be able to easily update Expression Evaluator to 
easily add new predefined functions to be made available for expression writer.
* User of ExpressionEvaluator should be able to add a custom method externally 
to be made available to in expression.
* Though operands are defined, placeholder for the operand in expression should 
be allowed to be overridden. By default, expression language should support 
bash type syntax for operand - {...}
* The library should not introduce any serialization related issues.

h2. quasi-Java Expression Language Examples
Given below are few examples using which expression language can be learn and 
adopted:

 || Expression || Task done by expression || Result of expression || 
 | {code} ${inp.field1} {code} | Access field1 from given POJO with placeholder 
“inp” | Will return value of field1 from given POJO | 
 | {code} ${inp.field1} + ${inp.field2} {code} | Perform addition | Will return 
addition of field1 & field2 from input POJO | 
 | {code} ${field1} + ${field2} {code} | Perform addition | Will return 
addition of field1 & field2 from input POJO. Will work with only single POJO 
input parameter. | 
 | {code} ${inp.field1} > 0 ? ${inp.field2} : ${inp.field3} {code} | JAVA 
ternary expression | Will return value of field2 from POJO if field1 is 
positive else field3 is returned | 
 | {code} ${inpA.field1} * ${inpA.field2} > 0 ? ${inpB.field1} : ${inpB.field2} 
{code} | JAVA ternary expression | Will return value of field1 from inpB if 
product of field1 & field2 from inpA is positive. Else return value of field2 
from inpB. | 
 | {code} (${inpA.field1} == ${inpA.field2}) && (${inpB.field1} == 
${inpB.field2}) {code} | Condition evaluation | Will return true if field1 & 
field2 from both inpA & inpB are same. | 
 | {code} equals(${inpA.field1}, ${inpB.field1}) {code} | Condition evaluation 
| Will return true if field1 from both inpA & inpB are same string. | 
 | {code} pow(${field1}, ${field1}) {code} | Exponent operation | Will return 
result of field1 to the power field2 from input POJO. | 

h2. Design of Expression Evaluator
h3. ExpressionEvaluator class
ExpressionEvaluator class takes input as expression in string format and 
expected return type and gives an instance of Expression Interface object which 
can be executed.
The class uses Janino to convert provided Java Expression to a compiled code 
and insert it to running JVM instance.

h3. Expression interface
Expression interface is generic type interface which contains a single method 
called execute. _execute_ method executes compiled expression against variable 
number of Objects passed and returns the result of the expression. The return 
type of this method is generic and need to be passed on when 
ExpressionEvaluator compiles the expression.

h3. Public methods
* *ExpressionEvaluator constructor*
This is an empty constructor which constructs the ExpressionEvaluator class for 
the purpose of kryo serialization.

* *setInputObjectPlaceholders(String[] inputObjectPlaceholders, Class[] 
classTypes)*
Using this method library user can provide the mapping of object placeholder to 
its expected types. classType parameter refers the Class of input object 
referred as a placeholder in inputObjectPlaceholder parameter at the same index.
The object passed to execute method of Expression interface should be in same 
order as provided here.
For eg. 
{code:java}
setInputObjectPlaceholders(new String[]{"inpA", "inpB"}, new 
Class[]{TypeA.class, TypeB.class});
{code}          
Above call to the method registers 2 placeholders for objects called inpA & 
inpB of type TypeA & TypeB that might appear in expression provided for 
compilation. This means execute method will expected 2 Object parameters in the 
same order as their class types and placeholders when execution of compiled 
expression happens.

* *createExecutableExpression(String expression, Class<?> returnType)*
This is the main method in ExpressionEvalator class which compiles the given 
string expression and generates a Interface of type Expression having a execute 
method which return object of type returnType.
Internally, the expression is parsed as be Expression Lauguage constructs and 
converted into a compiled Java code which gets injected into running JVM. This 
method uses Janino library.

* *createExecutableFunction(String expression, Class<?> returnType)* 
This method is similar to createExecutableExpression expect the expression can 
contain a complete method’s content.
This means the expression can have all types of constructs which can be 
provided in a Java method.

* *addImports(String importPackage)*
This method adds any given package to the default list of default imports.The 
import that are added here can be directly used inside Expression.

* *overrideImports(String[] importPackages)*
This method overrides the list of default imports currently set for expression 
evaluation. Except java.lang will remain there.

* *registerCustomMethod(String qualifiedFunc)*
This method can add a public static custom function to be made available while 
expression evaluation. 
The parameter passed to the function should be qualified function name i.e. it 
should be prepended with classname as well.

For eg. 
Lets say there is a class which has public static function:
{code:java}
package com.package.name.something;
public class Example
{
  public static compute(<params>)
  {
    <operations>
  }
}
{code}

Calling _registerCustomMethod("com.package.name.something.Example.compute")_ 
will add compute method to be directly 
available in Expression Language.

h2. Predefined functions in Expression language
By default all the public static methods in following classes can be invoked 
i.e. called in in Expression.

h3. From other libraries
# java.lang.Math.*
# org.apache.commons.lang3.StringUtils.*
# org.apache.commons.lang3.StringEscapeUtils.*
# org.apache.commons.lang3.time.DurationFormatUtils.*
# org.apache.commons.lang3.time.DateFormatUtils.*
# org.apache.commons.lang3.time.DateUtils.*

h3. Custom ones
# com.datatorrent.lib.expressions.ConversionUtils.*
# com.datatorrent.lib.expressions.StringUtils.*
# com.datatorrent.lib.expressions.DateTimeUtils.*


> Create Expression Evaluator Support quasi-Java Expression Language
> ------------------------------------------------------------------
>
>                 Key: APEXMALHAR-1972
>                 URL: https://issues.apache.org/jira/browse/APEXMALHAR-1972
>             Project: Apache Apex Malhar
>          Issue Type: New Feature
>          Components: utilities
>            Reporter: Chinmay Kolhatkar
>            Assignee: Chinmay Kolhatkar
>
> Create Expression Evaluator utility which will have support for quasi-Java 
> expression language.
> Usecases, Design, etc need to be added as a comment.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to