Creating and manipulating objects

From FlexRule Wiki
Jump to: navigation, search

Introduction

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

Defining and instantiating

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

for example in the following sample rule we have defined three parameters.

  1. <Procedure name="Sample1" enabled="true">
  2.  
  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>
  11.  
  12. </Procedure>

Please note 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 in a moment.

Complex and Custom types

In a complex type, the rule must create an instance (if not created yet) and then can 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 the Constructor calls the default constructor on the type to instantiate it. However there might be some types that you may need to use other overloads of constructors. To doing that you need to pass some input values to the constructor arguments. In these cases you can use 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 scenario you require 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

In 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>
  6.  
  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 to its properties to read or set new values. You can use Var commands to access its properties, set values parameter or set 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 in 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 simple, lets try to set a simple string value like "Arash" to our defined variable named name.

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

And then lets try to set the firstNameLength to be set to the length of firstName.

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

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>
  6.  
  7.   <Var name="firstName" value='"Arash"' />
  8.   <Var name="firstNameLength" value="firstName.Length" />
  9. </Procedure>

Let's assume we have setup 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>
  6.  
  7.   <Var name="firstName" value='"Arash"' />
  8.   <Var name="firstNameLength" value="firstName.Length" />
  9.  
  10.   <New name="person">
  11.     <Constructor />
  12.   </New>
  13.  
  14.   <Var name="person" value="person.FirstName = firstName" />
  15. </Procedure>

Invoke methods

To invoke a method on an instantiated object you can use

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

CallMethod

This command not only allows you to invoke a method of an object, also it let you to stores the return 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 in our example Person type has a method call GetHistory that lists all the driving fines of the person. And the rule simply checks if a person has any fines in last 2 months.

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

Please note that we have assumed you already had defined fineList as a parameter in your logic`s declaration section.

Using expressions

Method call invokation is supported also in expression level. 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)" />

Example

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

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>
  8.  
  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... and start using 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 Using command and then it can be used with a registered name.

Info2.pngThe members can be either 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>
  6.  
  7.   <Var value="now = DateTime.Now" />
  8. </Procedure>
Note pinned.png You can use 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