Thursday, 12 July 2018

Chain of Command D365

1) Chain of commands:

It is the new extension possible in AX7. We are able to add pre and post functionality to extensible methods in a much easier and readable manner than the previously used event handlers. We are now able to access protected methods and variables directly in extened clas with out problems.


Create two classes, one is the base class of the other and add a method we want to extend called ‘testMe’. Add infolog calls inside the method to track the execution :
class COCBaseClass
{
void new(){}
protected void testMe()
{
info("base class call");
}
public void runTest()
{
    this.testMe();
}
}

class COCChildClass extends COCBaseClassclass
{
protected void testMe()
{
    info("child class before super");
    super();
    info("child class after super");
}
}
Create a new model, add reference for the class model we created above, and add an extension class for our child class.
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt_Extension
{
protected void testMe()
{
    info("Extension 1 before next call");
    next testMe()
    info("Extension 1 after next call");
}
}
"next” keyword to the call which will wrap our extension code around the extended method. This next keyword separates the pre and post parts of our extension and mandatory to be called inside the chain of command method

Capture1

The advantage of chain of command is you can share the same method variables in the pre and post (before/after next() call) or share the same tts block inside your COC method. COC also supports return value and parameter modification of the extended method in a much more readable manner. Extending a method with return value and parameters in COC is like below :
class COCBaseClass
{
protected int returnMe(int _me)
{
return _me;
}
}
class COCChildClass extends COCBaseClass
{
protected int returnMe(int _me)
{
return super(_me);
}
}
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt_Extension
{
protected int returnMe(int _me)
{
   int ret;
   ret = next returnMe(_me);
   return ret;
}
}
let’s examine some more complex scenarios. Let’s create some other models and add some more chain of command extensions to our testMe method. Here are our two new extension classes in two new models :
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt2_Extension
{
protected void testMe()
{
    info("Extension 2 before next call");
    next testMe()
    info("Extension 2 after next call");
}
}
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt3_Extension
{
protected void testMe()
{
    info("Extension 3 before next call");
    next testMe()
    info("Extension 3 after next call");
}
}
calling all before next () parts of chain of command extension methods, calling the base method, then calling code after the next() calls. :
Capture2
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt2_Extension
{
[PreHandlerFor(classStr(COCChildClass), methodStr(COCChildClass, testMe))]
public static void COCChildClass_Pre_testMe(XppPrePostArgs args)
{
info("Extension 2 pre-eventhandler");
}

[PostHandlerFor(classStr(COCChildClass), methodStr(COCChildClass, testMe))]
public static void COCChildClass_Post_testMe(XppPrePostArgs args)
{
info("Extension 2 post-eventhandler");
}
}
Repeat the same for extension class 3, and run the test again to see the result :
Capture3
As you see the pre and post eventhandlers run after and before the chain of command calls. So chain of command wraps the base method, and its pre and post eventhandlers all together. Just as chain of command, the eventhandler methods are also called in a random order, and not mirrored on pre and post like the chain of command calls
==============================================================================================

HI, From Update12, its possible to write COC for forms as well!
[ExtensionOf(formStr(StageUpdate))] final class StageUpdate_Extension { public void closeOk() {
next closeOk(); Formrun thisForm = @this; FormRun callerForm = thisForm.args().caller();
if( callerForm.name() == formstr(WorkOrderTable))
{
FormDataSource woLineDS = callerForm.dataSource(formDataSourceStr(WorkOrderTable,WorkOrderLine )); WorkOrderLine selectedWOLine = woLineDs.cursor();
}
}

No comments:

Post a Comment