apex-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Chinmay Kolhatkar (JIRA)" <j...@apache.org>
Subject [jira] [Comment Edited] (APEXMALHAR-1972) Create Expression Evaluator Support quasi-Java Expression Language
Date Wed, 13 Jan 2016 16:54:39 GMT

    [ 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 4:54 PM:
------------------------------------------------------------------------

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.
* All the java operators should be supported.

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.
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.*



> 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)

Mime
View raw message