Expression Manager building block functionality is exposed
via a set of Spring beans and Flex components. Because the services
are exposed as Spring beans, you can replace the services with your
own custom implementation.
Customizing the default Client-Side ExpressionEvaluator serviceIf you want to change the ExpressionEvaluator service,
but don’t want to replace it with a new custom implementation, you
can customize the default implementation. The default implementation
of the ExpressionEvaluator service requires an instance of Variable
Resolver and Function Mapper. These instances are used to retrieve
the values of variables and resolve function references when expressions
are evaluated. You can configure them using the following properties
of the default ExpressionEvaluator service: variableResolver:
The client-side variable resolver is a representation of the com.adobe.solutions.exm.runtime.IVariableResolver
interface. This interface is more complex than its server-side counterpart.
Apart from the standard API for returning the value of a variable,
it also has an API for setting the value of a variable used by Expression
Manager. This API is used for setting target variable values when
target variables are also passed along with expressions to the manager).
An implementation of the resolver interface also dispatches an event
(an instance of com.adobe.solutions.exm.runtime.VariableChangeEvent)
of type variableChangeEvent. The event is dispatched whenever
the value of any of the variables managed by the resolver changes. Expression
Manager uses this event for recomputing expressions which include
the changed variable). This event is expected to contain the fully qualified
name of the variable whose value changed, the old value, and the new
value.
Expression Manager provides a simple resolver implementation (com.adobe.solutions.exm.runtime.impl.SimpleVariableResolver),
backed by a dictionary, and uses fully qualified variable names
as keys in the dictionary. This implementation is likely unusable
for all but the most trivial of use-cases.
functionMapper: The client-side function mapper uses
the com.adobe.solutions.exm.runtime.IFunctionMapper interface. This
interface has the same contract as its server-side counterpart.
Given a function prefix and local-name, it returns a Function instance
which can be called by Expression Manager. The client-side expression
manager supports both remote and local functions. The function instance
returned by the mapper behaves differently depending on the type
of function: Remote functions: Given a prefix
of the form REMOTE_<svc> and a local-name. The mapper returns
a Function instance corresponding to the operation with the same
name as the local-name on the Flex remoting destination with ID
<svc>. The required remoting configuration is implemented
in the application by supplying a suitable services-config.xml during
compilation time.
Local functions: Given a prefix and local-name, the
mapper tries to resolve them to a method defined on an ActionScript
class by consulting an internal mapping. The application must ensure
that the resolved ActionScript class is available in the current
ApplicationDomain and has a no-argument constructor. This internal
mapping can be populated in one of the following ways (or a combination
of both):
The application can call addFunction() on
the SimpleFunctionMapper instance used by the expression manager
for adding entries to the internal mapping. The first parameter
of the method is the function reference as encountered inside expressions
(a string of the form "<prefix>:<local_name>"). The
second parameter is the ActionScript method to which the function
maps (a string of the form "<fully_qualified_ActionScript_class_name>:<method_name>").
The application can also have the SimpleFunctionMapper instance initialize
these mappings from the server. To do so, call the SimpleFunctionMapper
constructor with the initFromServer parameter = true. The server
invocation is asynchronous, and so the application must wait for the
SimpleFunctionMapper instance to dispatch an Event of
type serverInitializationSuccess before the instance
can be used. If server invocation fails, the SimpleFunctionMapper
instance dispatches an Event of type "serverInitializationError"
to notify the application. Also, server invocation involves loading
a Flex remoting destination with ID "lc.exm.functionService". The
application must ensure that the configuration for this destination
(and its channels) is configured by supplying a suitable services-config.xml
at compilation time.
Adding custom remote functionsYou can create a custom bundle to export your own remote
functions for use inside expressions. To create a custom bundle
to export your own remote functions, perform the following tasks: Ensure that the Expression Manager classes, specifically
the com.adobe.exm.expeval package, are imported in the bundle's
manifest.
Define an interface for the OSGi service containing methods
which are being exported for use by Expression Manager.
Declare methods on the interface and annotate them with the
@ServiceMethod annotation (com.adobe.exm.expeval.ServiceMethod).
Expression Manager ignores any unannotated methods.
The ServiceMethod
annotation has the following optional attributes which can also
be specified: enabled: Determines if this method
is enabled. Expression Manager ignores disabled methods. If unspecified,
the default value of this attribute is true.
familyId: Specifies the method’s family (group). If
empty, Expression Manager assumes that the method belongs to the
default family. There is no registry of families (except for the
default one) from which functions are chosen. Expression Manager
dynamically creates the registry by taking a union of all family
IDs specified by all the functions exported by the various bundles.
Ensure that the ID specified here is reasonably human-readable, since
it displays in the expression authoring user interface as well.
displayName: A human-readable name for the function.
This name is used for display purposes in the authoring user interface.
If empty, Expression Manager constructs a default name using the
function's prefix and local-name.
description: A verbose description for the function.
This description is used for display purposes in the authoring user
interface. If empty, Expression Manager constructs a default description
using the function's prefix and local-name.
The
parameters of the methods can also be optionally annotated using
the @ServiceMethodParameter annotation (com.adobe.exm.expeval.ServiceMethodParameter).
This annotation is only used for specifying human-readable names
and descriptions of method parameters for use in the authoring user
interface.
Ensure that the parameters and return-values of the interface
methods belong to one of the supported types. A list of supported
types can be found in Common JSP EL examples.
Define the implementation of the interface, configure it
as a Spring bean and export it as an OSGi service via BluePrint
with the following special properties: <bp:service interface="A" ref="<bean_id_of_AImpl> ">
<bp:service-properties>
<entry key="connectors.httpinvoker" value="true" />
<entry key="connectors.httpinvoker.alias" value="/<service_id> " />
<entry key="connectors.remoting" value="true" />
<entry key="connectors.remoting.id" value="<service_id>" />
<entry key="exm.service" value="true" />
</bp:service-properties>
</bp:service>
The exm.service=true entry
instructs Expression Manager the service contains remote functions
suitable for use in expressions. The <service_id> value
must be a valid Java identifier (alphanumeric/$/_ with no other
special characters). This value, prefixed with the REMOTE_ keyword, forms
the prefix which is used inside expressions. For example, an interface with
an annotated method bar() and the service ID in
the BluePrint service properties is foo, the method
can be referenced inside expressions using REMOTE_foo:bar().
Adding custom local functionsYou can create a custom bundle to export your own local
functions for use inside expressions. To create a custom bundle
to export your own local functions, perform the following tasks: Ensure that the Expression Manager classes, specifically
the com.adobe.exm.expeval package, are imported in the bundle's
manifest.
For each logical local function, ensure that a static method
is defined on a Java class and an equivalent normal method defined
on some ActionScript class. For example, for local function f, assume
that the Java implementation is com.foo.SomeJavaClass.fn() and the
ActionScript implementation is com.foo.SomeASClass.flexFn().
Package the Java class in the bundle which is exporting the
local function and ensure that it is marked as exported in the bundle's
manifest. Otherwise the Expression Manager bundle cannot load the
class. On the client-side, ensure that the ActionScript class is
available in the ApplicationDomain in which the Expression Manager
libraries are being used.
Annotate the Java implementation of the local function with
the @LocalFunction annotation (com.adobe.exm.expeval.LocalFunction).
Expression Manager ignores unannotated methods.
The LocalFunction
annotation has the following optional attributes which can also
be specified: FlexClassName: The fully qualified
name of the ActionScript class hosting the Flex implementation of
the local function.
FlexMethodName: The name of the ActionScript method
corresponding to the local function's Flex implementation.
enabled: Determines if this method is enabled. Expression
Manager ignores disabled methods.
familyId: Specifies the method’s family (group). If
empty, Expression Manager assumes that the method belongs to the
default family. There is no registry of families (except for the
default one) from which functions are chosen. Expression Manager
dynamically creates the registry by taking a union over the set
of all family IDs specified by all the functions exported by the
various bundles. Ensure that the ID they specify here is reasonably human-readable,
since it displays in the expression authoring user interface as
well.
displayName: A human-readable name for the function.
This name is used for display purposes in the authoring user interface.
If empty, Expression Manager constructs a default name using the
function's prefix and local-name.
description: A verbose description for the function.
This description is used for display purposes in the authoring user
interface. If empty, Expression Manager constructs a default description
using the function's prefix and local-name.
The
parameters of the methods can also be optionally annotated using
the @LocalFunctionParameter annotation (com.adobe.exm.expeval.LocalFunctionParameter).
This annotation is only used for specifying human-readable names
and descriptions of method parameters for use in the authoring user interface.
Ensure that the parameters and return-values of the interface
methods belong to one of the supported types. A list of supported
types can be found in Common JSP EL examples.
Define an empty bean of type com.adobe.exm.expeval.LocalFunctionProviderImpl
in the Spring context and assign it an ID.
Export the bean as an OSGi service with the following special
properties: <bp:service interface="com.adobe.exm.expeval.LocalFunctionProvider" ref="lfp_id ">
<bp:service-properties>
<entry key="exm.local.function.entry.<prefix> " value="<fully_qualified_name_of_Java_class_hosting_local_function> " />
[Repeat entries of the form "exm.local.function.entry.*" for other classes hosting local functions, if any]
</bp:service-properties>
</bp:service>
Ensure that the Java classes being specified as values for the exm.local.function.entry.* keys
are exported in the manifest of the host bundle, otherwise the Expression
Manager bundle cannot load them. The prefixes specified are used
as-is as function-prefixes inside expressions, and hence must be
valid Java identifiers. For example, if localFoo is
the prefix for the com.foo.SomeJavaClass class,
then you can see local function in expressions using the notation localFoo:fn().
The local-name in the expression is the same as the Java method
name.
Evaluating an expression with a custom functionThe following code example shows how to call an expression
containing a custom function:
HashMap<String, Serializable> variables = new HashMap<String, Serializable>();
variables.put("number1", 25);
variables.put("number2", 26);
EXPEvaluator expressionEvaluationService = null;
// Retrieve instance of expressionEvaluationService from spring // context as per example given in section 4.
Object result = expressionEvaluationService.evaluateExpression( "${fm1:add(number1, number2)}", variables);
When evaluating expressions, the function name would be prefixed
with the key (fm1). When calling an "add" function, the EL prefixes
with fm1, for example, "${fm1:add(number1, number2)}".
|
|
|