Wednesday, May 04, 2011

Best Practice checks for objects in the current layer only

There are many Best Practice checks implemented in the standard AX application, which can help you to verify and improve your (or someone’s) source code and other application artifacts. But it should be noted that the execution of Best Practice checks:

  • Dramatically degrades compilation speed;
  • Is pointless for application objects that are not present in the current application layer.

So I decided to make Best Practice checks work only for objects in the current application layer. It turned out to be pretty easy to implement - all you need is add a new enum field to turn on or off this new behavior, for instance, to the SysBPParameters table and customize the SysBPCheck class a little.

private void doTreeNode(TreeNode _treeNode)
{
    TreeNodeTraverser   treeNodeTraverser;
    SysBPCheckBase      sysBPCheckBase;
    TreeNode            treeNodeToRelease;
    boolean             checkChildren = true;
    TreeNodePath        parentPath;
    int                 infologLines;

    Map map = new Map(Types::Integer, Types::Integer);
    MapEnumerator enum;
    int length;
    ;
    treeNodeToRelease = null;
//  if (_treeNode)                              //-gl00mie, 14.02.2011
    if (this.mustCheckTreeNode(_treeNode))      //+gl00mie, 14.02.2011
    {
        treeNodeTraverser = new TreeNodeTraverser(_treeNode);

        while (treeNodeTraverser.next()) // Check Best Practices
        {
            if (!sysCompilerOutput)
            {
                setprefix(treeNodeTraverser.infologPrefix());
            }

            treeNode = treeNodeTraverser.currentNode();
            if(treeNode)
            {
                length=strlen(treeNode.treeNodePath());
            }
            else
            {
                length=0;
            }
            if (treeNodeToRelease && SysTreeNode::isApplObject(treeNode) &&
                (treeNodeToRelease.sysNodeType()!= #NT_DBVIEW || 
                (treeNode && treeNode.sysNodeType()!= #NT_QE) ||
                length < strlen(treeNodeToRelease.treeNodePath()) ||
                substr(treeNode.treeNodePath(),1,strlen(treeNodeToRelease.treeNodePath())) !=
                treeNodeToRelease.treeNodePath()))
            {
                treeNodeToRelease.treeNodeRelease();
                treeNodeToRelease = null;
            }
//          if (checkChildren ||                        //-gl00mie, 14.02.2011
            if ((checkChildren ||                       //+gl00mie, 14.02.2011
                substr(treeNode.treeNodePath(),1,strlen(parentPath)) != parentPath)
                &&  this.mustCheckTreeNode( treeNode )) //+gl00mie, 14.02.2011
            {
                sysBPCheckBase = this.getSysBpCheckBase(treeNode);
                sysBPCheckBase.parmSysBPCheck(this);
                // ...
And here's the new SysBPCheck method that decides whether to run BP checks for a TreeNode:
// gl00mie, 14.02.2011
protected boolean mustCheckTreeNode(TreeNode _treeNode)
{
    UtilEntryLevel  applObjectLayer;
    UtilEntryLevel  currentAOLayer;
    boolean         ret;
    ;
    if (_treeNode)
    {
        ret = true;
        currentAOLayer = currentAOLayer();
        // if you develop on the sys layer then this modification is obviously pointless
        if (currentAOLayer > UtilEntryLevel::sys)
        {
            applObjectLayer = _treeNode.applObjectLayer();
            if (    applObjectLayer < currentAOLayer
                &&  enum2str(_treeNode.applObjectType()) != ''
               )
            {
                // depending on your setup we can skip BP checks for objects situated on lower layers
                // NB! you'll have to add this new field to a table and to a form by yourself
                ret = !SysBPParameters::find().CheckBPForCurrentAOLayerOnly;
            }
        }
    }
    return ret;
}