bea.com | products | dev2dev | support | askBEA
 Download Docs   Site Map   Glossary 
Search

Development Guide

 Previous Next Contents Index View as PDF  

Using the Expression Package

This topic illustrates how to use the services of the Expression package. The Expression package is part of the Personalization and Interaction Management features in WebLogic Portal. The Expression package allows you to externalize calculations, business policies, decision trees, and other operations from your Java code.

This section includes information on the following subjects:

 


What Is the Expression Package?

As previously mentioned, the Expression package allows you to externalize business logic or formulas from your Java code. Using the Expression package, any arithmetic, boolean, relational or conditional statement can be represented. You can use the Expression package to dynamically assemble and evaluate your own business logic.

An example of Expression package use is a rental car agency using it for calculating rental costs, which may change frequently. Rather than expressing the calculation using Java statements, the calculation can be externalized from the Java code into an XML document and interpreted at run time.

WebLogic Portal provides an Expression example. To see this example, take the following steps:

  1. Start the Personalization server, as follows:

    Start —> BEA WebLogic Platform 7.0 —> WebLogic Portal 7.0 —> Portal Examples —> Personalization Examples —> Launch Personalization Server

  2. After the Personalization server is running, start the Personalization Examples, as follows:

    Start —> BEA WebLogic Platform 7.0 —> WebLogic Portal 7.0 —> Portal Examples —> Personalization Examples —> Start Personalization Examples

    A browser window opens showing the Personalization Examples index, as shown in Figure  16-1.

    Figure 16-1 Personalization Examples Index


     

  3. If you are not logged in or have not created a user, click Please visit the User Login example first. A page opens where you can either log in or go to another page to create a user.

  4. After you have logged in or created a user, in the left column of the page, select Expressions —> Execute Expression. The Execute Expression Example page opens, as shown in Figure  16-8.

    Figure 16-2 Execute Expression Example


     

    This window shows a simple application of the Expression package, where the parameters are set using the drop-down lists.

  5. Click View Source in the left column. A new page opens showing the JSP source, as shown in Figure  16-3.

    Figure 16-3 JSP Source


     

    This page shows the JSP source (exec_expression.jsp) for the Expression Example. After the expression is executed (and a parameter is changed), the results are contained in the exec_expression_results.jsp. Both JSP files are located in the <BEA_HOME>\weblogic700\samples\portal\p13nDomain\beaApps\p13nApp\p13n directory.

    The next step provides information about how the expression works.

  6. On the Execute Expression Example page, click the How does it work? link. A a new browser window opens that describes the example, as shown in Figure  16-4.

    Figure 16-4 How Does It Work? Execute Expression


     

    This page describes how the Expression Example works. It also suggests an exercise to further your understanding of expressions.

  7. On the Execute Expression Example page, click the Preview Expression XML button. A page showing the XML appears, as shown in Figure  16-5.

    Figure 16-5 Preview Expression as XML


     

    This page shows the Expression Example XML before it is executed.

The next section discusses the differences between the Expressions package and the Rules Framework.

Using Rules or Expressions

One of the applications of the Rules Manager is to use business rules to match users and groups with appropriate content. The Rules Manager, like the Expressions package, is part of WebLogic Portal Personalization and Interaction Management.

The most important difference between the Expression package and the Rules Engine is that the Expression package uses named variables, while the Rules Engine does not. Additionally, the Rules Manager uses rule sets, where one rule can trigger another, that is, the rules can cascade.

In general, you use expressions when you want to bind variables to values (usually only one) and rules where you need pattern detection and want to evaluate all possible bindings to variables.

The Rule Engine has extremely powerful pattern matching and inferencing capabilities. However, these capabilities may come with a performance penalty. If you find yourself repeatedly executing a named rule, consider converting the rule to an expression. If you do not leverage the inferencing capabilities of the Rule Engine or rarely have more than one potential variable-value binding, then use expressions.

You should carefully evaluate the performance differences between using expressions, supplying an explicit binding between variables and values through a UnificationList or custom Unifier, and using the Rule Engine to explore all potential bindings.

Table  16-1 shows some examples of when to use rules and expressions.

Table 16-1 Expressions vs. Rules

Feature

Expressions

Rules

Externalize business logic from Java code

Yes

Yes

Rapid deployment of business logic independent of application code

Yes

Yes

Non programmers can assemble business logic using JSP or Swing GUI

Yes

Yes

Inferencing capability

No

Yes
One rule firing can cause another rule to be fired.

Explicit binding of value to variables

Yes

No
Values are bound to variables using class type. All possible bindings are automatically tested.

Long-lived persistence of business logic

Yes

Yes
Business logic is persisted as XML documents. The XML Schema can provide independence from the Java code.

Business logic can be passed between processes

Yes

Yes
XML documents defining business logic can be serialized or passed between Web Services.

XML Parsing cache

No

Yes
RulesManager implements a TTL cache for ruleset documents.

Expressions cache and optimization

Yes

Yes
The Rule Engine uses the Expression package internally, and hence leverages many of its underlying optimizations.


 

To see an example of rules, take the following steps:

  1. In the Personalization Examples window, select Rule —> Rules Manager. The Rules Manager Example appears, as shown in Figure  16-6.

    Figure 16-6 Rules Manager Example


     

    This page shows an example of rules. This example demonstrates that the action of one rule will cause the condition of another rule to become satisfied. This ability is not present in the Expression package.

  2. For more explanation, click the How does it work? link. The explanation appears, as shown in Figure  16-7.

    Figure 16-7 How Does It Work? Rules Manager


     

Expression Package Classes

The Expression package allows users to dynamically assemble and execute XML-based expressions. The package defines a set of Java classes that represent various types of expression operators, and contains services for evaluating expressions consisting of instances of these operators.

The Expression package includes a base Expression class, a Variable class, and the following operator classes for operating on Expressions and Variables:

The Expression package also includes the following services for operating on expressions:

Unlike an expression written directly in Java and executed from within a Java program, the Expression package allows you to dynamically assemble and modify expressions from within your Java programs. An expression may be modified any number of times both before and after evaluation. When you assemble expressions using the Expression package you can also take advantage the advanced features of the Expression package, such as expression caching, validation, and optimization.

The Expression package serves as the foundation of the BEA Rules Engine. The Rules Engine leverages the package in order to represent and evaluate rule condition and action expressions. Likewise, you can use the Expression package to dynamically assemble and evaluate your own business logic.

The Package Structure for the Expression Package

The Expression package interfaces and abstract classes can be found in the following package: com.bea.p13n.expression

The Expression package operators are organized in the following packages:

Basic language operators—com.bea.p13n.expression.operators

Logical operators—com.bea.p13n.expression.operators.logical

String operators—com.bea.p13n.expression.operators.string

Mathematical operators—com.bea.p13n.expression.operators.math

Comparative operators—com.bea.p13n.expression.operators.comparative

Collection operators—com.bea.p13n.expression.operators.collection


 

The Expression package related classes are packaged in the p13n_util.jar archive.

 


Assembling and Managing Expressions

Before you can begin using expressions, you must first learn how to programmatically assemble them using the various operator classes provided in the Expression package.

An expression is represented as a tree, where each node is another expression itself or a plain Java object. Expression trees are assembled in a bottom-up manner; a child expression or Java object is first created, and then added to a parent expression.

Figure  16-8 illustrates the steps required to build an expression tree.

Maintaining Parent-child Relationships

Each of the operator classes defined in the Expression package extends a common base class that contains the necessary logic for maintaining parent-child relationships; therefore, you do not have to worry about maintaining these relationships while assembling expressions. However, it is possible to modify the structure of an expression after it has been created.

Table  16-2 shows the operators provided in the Expression interface for adding, modifying, or removing subexpressions in an expression.

Table 16-2 Methods for Building an Expression Tree

Java Method

Description

addSubExpression

Adds a child (can be a subexpression) to an expression object.

removeSubExpression

Removes an object (can be a subexpression) of the expression object.

setSubExpression

Replaces existing object (of an expression) by the given object (can be a subexpression).

getSubExpression

Can be used to access the children of an expression object.

getParent

Can be used to access the parent expression of an expression object.


 

For more information about the Expression interface, see the Javadoc.

Managing the Expression Cache

The expression interface also includes methods to manage the caching of results. The result of evaluating an expression may be cached in each expression object. When the cache is enabled for an expression, trying to evaluate the same expression a second time will return the cached value.

Note: By default, caching is turned off. You may want to keep the cache turned off for some operators, such as MethodCall.

Table  16-3 shows the methods provided in the Expression interface to manage the caching of results.

Table 16-3 Methods to Manage Caching of Results

Java Method

Description

setCacheEnabled

Can be used to enable or disable the cache for an expression.

isCacheEnabled

Can be used to check if the cache is enabled for an expression.

isCached

Can be used to check if a result is currently cached for an expression.

getCachedValue

Can be used to get the current cached result of evaluating the expression.


 

For more information about the Expression interface, see the Javadoc.

 


Working with Expressions

After you have assembled an expression, you are ready to work with it using the various Expression package services. These services allow you to prepare an assembled expression for evaluation, validate that the expression is well-formed, optimize its structure, and finally, evaluate the expression.

The following information is presented in this section:

The Expression Factory

The ExpressionFactory provides methods to create the various Expression package services and data structures used by these services.

For example, the following method will create an instance of the Validator service:

ExpressionFactory.createValidator(null);

For more detail on how to construct the various Expression package services, see the Javadoc.

Expression Package Services

The Expression package offers services which can be used on any expression that is built using the operators in the Expression package.

Unification Service

The Unifier is used to unify variables (assign values to variables) present in an expression. The Unifier uses a data structure known as a UnificationList that stores the variable name and the corresponding value of the variable. Like the Unifier, the UnificationList instances are created via the ExpressionFactory. The Unifier gets the value from the list for a particular variable using the variable name as a key to search the UnificationList, and binds the retrieved value to the variable.

For more information about the Unifier interface and the ExpressionFactory class, see the Javadoc.

Optimization Service

The Optimizer is used to optimize an expression. The default optimization algorithm used by the Optimizer is shown below.

For more information about the Optimizer interface and the ExpressionFactory class, see the Javadoc.

Validation Service

The Validator is used to validate an expression. The default validation algorithm used by the Validator is as follows:

For each operand of an operator:

The Validator can be used in a stateless or stateful mode. In stateless mode, any expression evaluations necessary to perform validation will be executed in stateless mode.

For more information about stateless and stateful evaluation modes, see the Evaluation Service section below.

For more information about the Validator interface and the ExpressionFactory class, see the Javadoc.

Evaluation Service

The Evaluator is used to evaluate an expression. An expression can be evaluated in stateful or stateless mode:

Stateful mode

In this mode, the value of each variable that appears in the expression is determined by retrieving the value set within the variable.

In other words, stateful mode relies upon the expression having been previously unified by a Unifier.

When an expression is evaluated in stateful mode and results caching is turned on, the results of evaluation will be cached within the expression.

Stateless mode

In this mode, the value of each variable that appears in the expression is determined by looking up a value that is bound to the name of the variable in an external data structure.

In other words, the evaluation process does not rely upon state associated with the expression, and as such, does not require the expression to be unified before evaluation.

The data structure that contains the name-value mappings for variables is known as a UnificationList and is associated with the Evaluator. Like the Evaluator, the UnificationList instances can be created using the ExpressionFactory.

A side effect of stateless mode is that expression evaluation cannot take advantage of results caching.

You can use of stateful mode in a situation where an expression need only be evaluated within a single thread of execution. In the case of multithreaded evaluation of a single expression, you must use stateless mode.

Note: If an expression does not contain variables, then there is no difference between the two evaluation modes.

For more information about the Evaluator interface and the ExpressionFactory class, see the Javadoc.

Execution Service

The Executor aggregates the Unification Service, Validation Service and Evaluation Service. The execute method on an Executor takes a Unifier, a Validator and an Evaluator to execute a cycle of unification-validation-evaluation operations.

The algorithm used by the Executor is shown below:

Unification

Note: The Unifier should be null in the case where the expression passed to the Executor is already unified, or the expression is to be evaluated in stateless mode.

Validation

Evaluation

Note: If the Evaluator passed is stateless, then the Unifier should be null.

For more information about the Executor interface and the ExpressionFactory class, see the Javadoc.

Code Examples

This section contains examples that illustrate how to construct expressions programmatically and use the Expression package services.

This section contains the following four code examples:

Stateful Evaluation of a Simple Expression

A logical expression is constructed and executed in stateful mode. The expression does not contain any variables.

Listing 16-1 Example

The source code for creating and executing the expression is shown below:

Expression expression = new LogicalAnd(Boolean.TRUE, Boolean.FALSE); 
// Prepare for creating an executor by creating a stateful
// evaluator. Since the expression does not contain variables,
// we are not using a validator or a unifier in this example,
// so we will not create them.
// null is passed for the environment Map.
Evaluator evaluator = ExpressionFactory.createEvaluator(null); 
// null is passed for the environment Map.
Executor executor = ExpressionFactory.createExecutor(null);
// Execute the above expression by passing null for both the unifier
// and validator parameters.
Object result = executor.execute(expression, null, null, evaluator);
// The result should be Boolean.FALSE.

Stateful Evaluation of an Expression Containing Variables

An expression containing variables is constructed and evaluated in stateful mode.

Listing 16-2 Example

The source code for creating and executing the expression in stateful mode is shown below.

// Create a variable that can store an object of type Boolean
// and whose name is "?booleanVariable".
Variable booleanVariable = new Variable("?booleanVariable", Boolean.class);
// Now, we will use the variable that we created in the above step.
Expression expression = new LogicalAnd(Boolean.TRUE, booleanVariable); 
// Next, we'll unify the expression by binding any variables
// present in the expression. In the above case, there is one
// variable in the expression so the variable needs to be assigned a
// value. This is shown below.
// Create a UnificationList to store the variable name and value as
// key-value pairs.
UnificationList unificationList = ExpressionFactory.createUnificationList(null);
UnificationList.addObject("?booleanVariable", Boolean.FALSE);
// Create a unifier.
Unifier unifier = ExpressionFactory.createUnifier(null, unificationList);
// Prepare for creating an executor by creating a stateful
// evaluator. We are not using a validator in this example,
// so we will not create one.
// null is passed for the environment Map.
Evaluator evaluator = ExpressionFactory.createEvaluator(null); 
// null is passed for environment Map.
Executor executor = ExpressionFactory.createExecutor(null);
// Execute the above expression by passing a unifier and a null
// validator.
Object result = executor.execute(expression, unifier, null, evaluator);
// The result should be Boolean.FALSE.

Note: The expression can be unified before calling the execute method by calling the unify method on the Unifier. Once the expression is unified there is no need to pass a unifier to the execute method of the executor.

Stateless Validation and Evaluation of an Expression
Containing Variables

An expression containing variables is constructed and evaluated in stateless mode. The Validator service is also used to validate the expression.

Listing 16-3 Example

The source code for creating and executing the expression in stateless mode is shown below.

// Create a variable that can store an object of type Boolean
// and whose name is "?booleanVariable".
Variable booleanVariable = new Variable("?booleanVariable", Boolean.class);
// Now we will use the variable that we created in the above step.
Expression expression = new LogicalAnd(Boolean.TRUE, booleanVariable); 
// Next, we'll unify the expression by binding any variables
// present in the expression. In the above case there is one
// variable in the expression, so the variable needs to be assigned
// a value. This is shown below.
// Create a UnificationList to store the variable name and value as
// key-value pairs.
UnificationList unificationList = ExpressionFactory.createUnificationList(null);
UnificationList.addObject("?booleanVariable", Boolean.FALSE); 
// Prepare for creating an executor by creating a stateless
// evaluator. We are not using a unifier in this example,
// so we will not create one.
// Creating a stateless evaluator by passing null for the
// environment Map and the UnificationList.
Evaluator evaluator = ExpressionFactory.createEvaluator(null, unificationList); 
// Creating a stateless validator.
Validator validator = ExpressionFactory.createValidator(null, evaluator);
// Creating an executor.
Executor executor = ExpressionFactory.createExecutor(null);
// Execute the above expression by passing null for the unifier and
// a non-null validator.
Object result = executor.execute(expression, null, validator, evaluator)
// The result should be Boolean.FALSE.
// After calling execute method, the given expression will not be
// modified by any services that were used above.
// The stateless execution mode is useful if an expression is shared
// between multiple threads.

Stateful Validation and Evaluation of an Expression
Containing Variables

An expression containing variables is constructed and evaluated in stateful mode. The Validator service is also used to validate the expression.

Listing 16-4 Example

The source code for creating and executing the expression in a stateful mode is shown below.

// Create a variable that can store an object of type Boolean
// and whose name is "?booleanVariable".
Variable booleanVariable = new Variable("?booleanVariable", Boolean.class);
// Now we will use the variable that we created in the above step.
Expression expression = new LogicalAnd(Boolean.TRUE, booleanVariable); 
// Next, we'll unify the expression by binding any variables
// present in the expression. In the above case, there is one
// variable in the expression, so the variable needs to be assigned
// a value. This is shown below.
// Create a UnificationList to store the variable name and value
// as key-value pairs.
UnificationList unificationList = ExpressionFactory.createUnificationList(null);
UnificationList.addObject("?booleanVariable", Boolean.FALSE);
// Create a unifier.
Unifier unifier = ExpressionFactory.createUnifier(null, unificationList);
// Prepare for creating an executor by creating a stateful
// evaluator and validator.
// null is passed for the environment Map.
Evaluator evaluator = ExpressionFactory.createEvaluator(null); 
// null is passed for the environment Map.
// Creating a validator.
Validator validator = ExpressionFactory.createValidator(null);
// Creating an executor.
Executor executor = ExpressionFactory.createExecutor(null);
// Execute the above expression by passing a unifier and a non-null
// validator.
Object result = executor.execute(expression, unifier, validator, evaluator);
// The result should be Boolean.FALSE.

Note: The expression can be unified before calling the execute method by calling the unify method on the Unifier. Once the expression is unified there is no need to pass a unifier to the execute method of the Executor. The validation service can be used directly by calling the validate method. The validate method throws an InvalidExpressionException if the given expression is invalid.

 


Configuring the Expression Package

The expression.properties file contains configuration settings for the Expression package and should be modified with care.

This file is archived in p13n_util.jar under the package com.bea.p13n.expression.

##
# Expression Comparator null handling
#
# If the following property is set to true the Expression
# Comparator will return false as the result of comparing
# any non-null value to a null, regardless of the
# comparison being performed.
#
# Defaults to true.
##
expression.comparator.nullcheck=true
##
# Expression Comparator equality epsilon.
#
# The following property determines the epsilon value for
# numeric equality comparisons.
#
# Defaults to 0.
##
expression.comparator.epsilon=0.00001
##
# Expression Introspector Method Array Caching
#
# If the following property is set to true the Expression
# Introspector will cache the array of Methods implemented by a
# Java Class.
#
# Defaults to true. 
##
expression.introspector.method.array.cache=true
##
# Expression Introspector Method Caching
#
# If the following property is set to true the Expression
# Introspector will cache Methods by signature.
#
# Defaults to true.
##
expression.introspector.method.cache=true
##
# Expression Parser Node Support Classes
#
# This property supports a comma-delimited list of classes
# extending the base AST NodeSupport class. Such classes
# provide node creation support for expression-schema namespaces
# required for constructing the intermediate AST representing a
# given Expression instance.
#
# All NodeSupport subclasses must co-exist peacefully with the
# required CoreNodeSupport instance.
##
parser.node.support.list=\ 
com.bea.p13n.expression.internal.parser.expression.ExpressionNodeSupport
##
# Expression Parser Transform Visitor Class
#
# This property specifies the ExpressionTranformVisitor or
# subclass to be used for intermediate AST-to-Expression
# transformations.
#
##
parser.transform=\
com.bea.p13n.expression.internal.parser.expression.ExpressionTransformVisitor

 

Back to Top Previous Next