Creating and manipulating objects

From FlexRule Wiki
Jump to: navigation, search


In a procedural rule, you can instantiate an object and access its member. You may access the object member if you want to:

  • Read or set a property value
  • Invoke a method on the object
Note pinned.pngIn this article we used Procedure logic, but the same principal applies to all the other types of logic (i.e., Flow, DecisionTable, Validation, etc.

Defining and instantiating

The first step in creating an object is to define a parameter that can be use to access the newly instantiated object. To define a parameter, we simply use the Declaration section and use the Define command.

For example, in the following sample rule we have defined three parameters:

  1. <Procedure name="Sample1" enabled="true">
  3.   <Declaration>
  4.     <Define name="time" direction="out" />
  5.     <Define name="item" direction="out" />
  6.     <Define name="discount" direction="out" />
  7.     <Define name="hasPassedvalidation" direction="out" />
  8.     <Define name="firstName" direction="out" />
  9.     <Define name="firstNameLength" direction="out" />
  10.   </Declaration>
  12. </Procedure>

Please note that the defined parameters do not need to specify types.

Primitive types

Primitive types do not need instantiation. For example, a string can be assigned to the parameters just by using Var command. We will describe this later.

Complex and Custom types

In a complex type, the rule must create an instance (if not created yet) and then reference the parameter to access the members. To create an instance, you can use

  1. New command
  2. Var and use of new or newOf functions.
Usine New Command

Let's say we want to create a DateTime and assign it to our defined parameter named time.

  1. <New name="time" type="System.DateTime">
  2.   <Constructor />
  3. </New>

Of with no Constructor when no parameter is required.

  1. <New name="time" type="System.DateTime"/>

Note that the Constructor calls the default constructor on the type to instantiate it. However, there might be some types in which you may need to use other overloads of constructors. To do that you need to pass some input values to the constructor arguments. In such cases you can use the Param command.

  1. <New name="start">
  2.   <Constructor>
  3.     <Param value="10i"/>
  4.     <Param value="30i"/>
  5.     <Param value="0i"/>
  6.   </Constructor>
  7. </New>
Custom types

In some scenarios you need to create a specific type (your application`s types) that is located in an your assembly. Then you have to specify the type information in the New command.

  1. <New name="item" 
  2.      assembly="SampleApplication.Library.dll" type="Entities.Person">
  3.   <Constructor>
  4.     <Param value='"Arash"'/>
  5.   </Constructor>
  6. </New>

Or if you have setup the typeId information in the execution context, you can only specify the typeId.

  1. <New name="item" 
  2.      typeId="Person">
  3.   <Constructor>
  4.     <Param value='"Arash"'/>
  5.   </Constructor>
  6. </New>

To setup the typeId you have to use the following code to register type identifiers before executing the procedural engine.

  1. byte[] procedure=... // loading the rule content here.
  2. var engine = RuntimeEngine.FromXml(procedure);
  3. engine.OnRunning = (e)=> e.ExecutorSetup.TypeIdRegistry.Register("Person", typeof(Officer));
Using expressions

At the expression level, new and newOf are functions that create new instances of a type. These functions are part of the standard expression languages and are explained here. You can evaluate the expressions in Procedural and Validation logic using Var commands.

  1. <Procedure name="new date time sample>
  2. 	<Declaration>
  3. 		<Define name="obj" direction="out" />
  4. 		<Using path="System.DateTime" />
  5. 	</Declaration>
  7. 	<Var value="obj = new(DateTime, 1977, 3, 1)"/>
  8. </Procedure>

Read and write properties

When an object exists: either by instantiating using the methods we described here or by being passed by application, then in your logic you can access its properties to read or set new values. You can use Var commands to access its properties, set a values parameter or set a value to an object`s property. All Var commands must have a name setting. The name would refer to the name of a defined parameter in the rule based on the current Scope scope. If the scope is not defined, it refers to the root declaration section of the rule.

Please note you can use this command in Validation and Decision logic as well

To start with a simple example, let's try to set a string value like "Arash" to our defined variable named name.

  1. <Var name="firstName" value='"Arash"' />

Now let's try to set the firstNameLength to be set to the length of firstName.

  1. <Var name="firstNameLength" value="firstName.Length" />

Then let's see what we have modelled as the rule so far:

  1. <Procedure name="Sample1" enabled="true">
  2.    <Declaration>
  3.     <Define name="firstName" direction="out" />
  4.     <Define name="firstNameLength" direction="out" />
  5.   </Declaration>
  7.   <Var name="firstName" value='"Arash"' />
  8.   <Var name="firstNameLength" value="firstName.Length" />
  9. </Procedure>

Let's assume we have set up the type identifier as Person and we have instantiated it. This Person type has a property named FirstName and we want to set the property of the instantiated object. To access the internal properties of an object to be set, you can use path setting of the Var command.

  1. <Var name="person" path="FirstName" value="firstName" />

Or the other alternative for this is using assignment operator

  1. <Var value="person.FirstName = firstName" />

Let's put everything together now:

  1. <Procedure name="Sample1" enabled="true">
  2.   <Declaration>
  3.     <Define name="firstName" direction="out" />
  4.     <Define name="firstNameLength" direction="out" />
  5.   </Declaration>
  7.   <Var name="firstName" value='"Arash"' />
  8.   <Var name="firstNameLength" value="firstName.Length" />
  10.   <New name="person">
  11.     <Constructor />
  12.   </New>
  14.   <Var name="person" value="person.FirstName = firstName" />
  15. </Procedure>

Invoke methods

To invoke a method on an instantiated object you can use the following:

  1. CallMethod command
  2. Var command and method invoke expression


This command not only allows you to invoke a method of an object, it also let's you store the returned value of the execution to a defined parameter in your rule.

Please note you can use this command in Validation and Decision logic as well.

Let's say that in our example, the Person type has a method call GetHistory that lists all the driving fines of the person. The rule then simply checks if a person has any fines in last two months.

  1. <CallMethod method="person.GetHistory" return="fineList">
  2.   <!-- last two months fine retrieval-->
  3.   <Param value="2i"/>
  4. </CallMethod>

Please note that we assume you already defined fineList as a parameter in your logic's declaration section.

Using expressions

Method call invokation is supported also in expression level. The Var command evaluates an expression, so when the expression is calling a method, the evaluation results invoking the method.

  1. <Var value="fineList = person.GetHistory(2i)" />


The logic for this example is to discover whether a person has had any fines recently, and allows the application to retrieve the list of fines from the execution context. We do not ask the application to define the meaning of recently by passing the number of months to be retrieved. It is up to the rule abstraction to define what recently means.

Now let's put everything together:

  1. <Procedure name="IsRecentlyFined" enabled="true">
  2.   <Declaration>
  3.     <Define name="personId" direction="in" />
  4.     <!-- application can read the following two values from context -->
  5.     <Define name="fineList" direction="out" />
  6.     <Define name="hasAnyFines" direction="out" />
  7.   </Declaration>
  9.   <Var value="person = new (Person, personId)" />
  10.   <Var value="fineList = person.GetHistory(2i)" />
  11.   <Var value="hasAnyFines = fineList.Count gt 0"/>
  12. </Procedure>

Custom code

There are multiple ways of using custom code as part of your logic execution:

  1. Static Members: You can register your type and assembly using Using command in any logic (i.e., Flow, Procedural, Decision Table, etc.) and start using the members of the type.
  2. Custom Function: Define your methods in your custom code as a function and use them as FlexRule functions.

Static Members

To access static members (Properties and Methods) of a Type, the type must be registered with the Using command. Then it can be used with a registered name.

Info2.pngThe members can be either a static property or method.
  1. <Procedure name="Now" enabled="true">
  2.   <Declaration>
  3.     <Define name="now" direction="out" />
  4.     <Using path="System.DateTime" />
  5.   </Declaration>
  7.   <Var value="now = DateTime.Now" />
  8. </Procedure>
Note pinned.png You can use the assembly parameter on the Using to reference your own assembly.

Custom Functions

This allows you to extend FlexRule's functions list and use your custom code as a normal function as part of the execution.

More details