Lifecycle Applications |
Action Editor |
Implementing Lifecycle Condition/CommandWorking with action lifecycle |
Use Case |
AbstractThe document is related to the use case CAAVpiAFLLifecycle. It describes how to implement a lifecycle condition and/or command for ActionFlow entities such as Action, AffectedObject or Link. |
This use case is intended to help you make your first steps in programming lifecycle conditions and commands. More particularly, it shows how to implement a condition and a command defined in an Action lifecycle.
[Top]
CAAVpiAFLLifecycle is a use case of the CAAVpiInterfaces.edu framework that illustrates VPMInterfaces framework functionalities.
[Top]
The goal of CAAVpiAFLLifecycle use-case is to show how to implement a condition and a command defined in a lifecycle Action. The condition and command would be triggered when an Action is promoted.
To do so, the use case goes through the following steps:
The implementation of the lifecycle condition and command are contained in the files CAAVpiAFLCondSample.cpp and CAAVpiAFLCmdSample.cpp respectively.
[Top]
To launch CAAVpiAFLLifecycle, you will need to set up the build-time environment, next compile CAAVpiAFLLifecycle, CAAVpiAFLCondSample, and CAAVpiAFLCmdSample, then set up the run-time environment, and finally execute the use case [1].
First, load the graph into the database. To this end, from ht run time
environment, run the VPMGRAPHADM
command:
e:>VPMGRAPHADM Import $INSTALLDIR\CAAVPMInterfaces.edu\CNext\reffiles\sample\ENOVIA_ACTION_DESIGN_CAASample.VGraph |
Then, launch the use case as follows:
e:>CAAVpiAFLLifecycle |
$ CAAVpiAFLLifecycle |
[Top]
The use case is made of three source files named CAAVpiAFLLifecycle.cpp, CAAVpiAFLCondSample.cpp, and CAAVpiAFLCmdSample. All the three are located in the module CAACAAVpiAFLLifecycle.m of the framework CAAVPMInterfaces.edu.
Windows | InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiAFLLifecycle.m\src |
Unix | InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiAFLLifecycle.m/src |
The lifecycle graph is defined in the STEP file ENOVIA_ACTION_DESIGN_CAASample.VGraph located in the directory CNext of the framework CAAVPMInterfaces.edu.
Windows | InstallRootDirectory\CAAVPMInterfaces.edu\CNext\reffiles\sample |
Unix | InstallRootDirectory/CAAVPMInterfaces.edu/CNext/reffiles/sample |
Where InstallRootDirectory is the directory where the CAA CD-ROM is installed.
[Top]
There are five main steps in CAAVpiLifecycle:
In the following sections, the different steps are commented in detail.
[Top]
CAAVpiAFLLifecycle.cpp is the main program that actually implements and run the Use Case. It creates an action which will be promoted based on its lifecycle. This latter is defined in a Step file and uses a condition and a command also described in this use-case. The condition ensures that the action has an abstract before to promote it. If so, the action is actually promoted from its initial status Created to the final status Accepted. As a side effect, the command will be triggered to promote all the actions defined as children of the first.
[Top]
Generally, a lifecycle graph in ENOVIA is defined using a STEP file. The objective of this use-case is not to describe the full syntax of a lifecycle definition. Instead, we will only focus on some relevant aspects that are directly related to the Action modeler.
Let us see what are the main constructs for the definition of our use-case lifecycle.
The following lines declares the lifecycle to be defined with its internal name ENOVIA_ACTION_DESIGN_CAASample and the list of status. They are 2 states declared Created and Accepted. From the initial status Created, any object which has this lifecycle attached to it could move to status Accepted through a transition referred to as #30 which is described below.
... #10=GIMaster($,$,$,$,$,$,$,$,$,$,$,$,$,'ENOVIA_ACTION_DESIGN_CAASample',$,$,$,$,$,$,'',''); #11=GIVersion($,$,$,$,$,$,$,$,$,$,$,$,$,'---',1,'Active',$,$,$,#10,$,#20,(#20,#21),$); #20=status((#30),'Created',''); #21=status($,'Accepted',' '); ... |
The transition from Created to Accepted can be triggered with terminal Promote. Also, there is a condition (#40) and an operation (#50) attached to it.
The condition must be satisfied in order for the transition to be actually triggered, i.e. the object status moves to status Accepted. It is specified that this condition must be implemented with late-type VPMAFLCondSample.
The operation is a set of commands that can be executed once the transition has been actually triggered. Each command may itself have a condition associated with, in which case the condition must be fulfilled in order for the command to be executed. In our example, there is only one command which has to be implemented using late-type VPMAFLCmdSample. The command also uses a predicate that allows to search for all Actions that are related to the current Action through AFLParent and then promote it. Finally the predicate specifies that for each child Action found, its attribute V_abstract must be set with the string "Promoted automatically from parent.".
... #30=transition('Promote',1,0,#40,#50,'Accepted',''); #40=condition('Cond_HasAbstract','VPMAFLCondSample',$,''); #50=operation('Op_PromoteChildren',(#60),$); #60=command('Cmd_PromoteChildren','VPMAFLCmdSample',$,(#70),$,''); #70=predicat('Action>AFLParent','V_abstract','=','Promoted automatically from parent.'); ... |
Finally, notice that the lifecycle graph must be loaded into the database. To this end, the command VPMGRAPHADM must be executed in a runtime environment.
> ls ENOVIA_ACTION_DESIGN_CAASample.VGraph >VPMGRAPHADM Import $INSTALLDIR\CAAVPMInterfaces.edu\CNext\reffiles\sample\ENOVIA_ACTION_DESIGN_CAASample.VGraph > |
[Top]
As mentioned before, the condition declared in the lifecycle STEP file specifies that it must be implement through late-type VPMAFLCondSample. In the following piece of code, this what the CATImplementClass() line is about. Next the implementation class CAAVpiAFLLifecycleCond must adhere to the interface CATIVpmObjectOperation. Notice that lifecycle command implementation must also adhere to this interface. However, for a condition it is the method RunUserCondition() which must be implemented, while for a command it is RunUserCommand().
The method takes 4 parameters. The first one specifies the condition internal name (Cond_HasAbstract in our lifecycle), the list of predicates that might be associated with the condition (empty in our example), the current object to which the lifecycle is attached to (should be an Action in our use-case), and finally the simulation mode. For more information about how to handle the different constructs in a lifecycle please see [2].
... CATImplementClass (CAAVpiAFLLifecycleCond, DataExtension, CATBaseUnknown, VPMAFLCondSample); #include "TIE_CATIVpmObjectOperation.h" TIE_CATIVpmObjectOperation(CAAVpiAFLLifecycleCond); HRESULT CAAVpiAFLLifecycleCond::RunUserCondition( const CATUnicodeString& iConditionName, const CATLISTV(CATBaseUnknown_var)& iGraphPredicateList, const CATBaseUnknown_var& iObject, const long& iSimulateMode) const { ... |
The method body is pretty simple. In the code below, after querying the interface CATIVpmAFLAction on the object iObject, the attribute V_abstract is checked using the method GetAbstract(). Depending whether this attribute is valuated or not, a hresult S_OK or S_FALSE is returned.
... // Query for interface CATIVpmAFLAction on the current LC object iObject CATIVpmAFLAction_var action(iObject); ... // Check the Action abstract CATUnicodeString actAbstract; action->GetAbstract(actAbstract); if (actAbstract.GetLengthInChar()<1) { cout << "Action abstract is not set. Could not accept this Action." << endl; rc = S_FALSE; } else { cout << "Action abstract is specified. Action can be accepted." << endl; rc = S_OK; } return rc; ... |
[Top]
The implementation of the lifecycle command is similar to a condition. A class must be implemented as an extension to the late-type specified in the lifecycle for the command (VPMAFLCmdSample). Also the class must adhere to the interface CATIVpmObjectOperation but this time it is the method RunUserCommand() which must be implemented.
The method parameters are slightly different. The first is the operation internal name (in our lifecycle it is Op_PormoteChildren). The second parameter specifies the command internal name (Cmd_PromoteChildren). The third specifies a list of predicates associated with the command. In our lifecycle, there is only one defined for the command (#70). The fourth parameter of the method specifies the arguments that may be used for the command. For the use-case, it should be empty since our command requires no arguments. The fifth parameter gives the internal name of the condition that may attached to the command (none), with its predicates specified in the sixth parameter (none). Finally, the last two parameters are the same as for the method RunUserCondition().
... CATImplementClass (CAAVpiAFLLifecycleCmd, DataExtension, CATBaseUnknown, VPMAFLCmdSample); ... #include "TIE_CATIVpmObjectOperation.h" TIE_CATIVpmObjectOperation (CAAVpiAFLLifecycleCmd); HRESULT CAAVpiAFLLifecycleCmd::RunUserCommand( const CATUnicodeString& iOperationName, const CATUnicodeString& iCommandName, const CATLISTV(CATBaseUnknown_var)& iCmdPredicateList, const CATUnicodeString& iParameters, const CATUnicodeString& iConditionName, const CATLISTV(CATBaseUnknown_var)& iCondPredicateList, const CATBaseUnknown_var& iObject, const long& iSimulateMode) const { ... |
The first step in the method body is to get the ActionFlow manager.
... // Get a session VPMSession* session = VPMSession::OpenSession(); ... // Get a factory manager from the session CATIVpmFactoryManager_var factoryMgr = NULL_var; session->GetVPMObjectFactory(factoryMgr); ... // Query an interface on CATIVpmAFLManager CATIVpmAFLManager_var aflMgr(factoryMgr); ... |
Next, a checking is performed for a command condition. This is normally useless since there is no condition specified for the command in the lifecycle.
... // Check the condition related to the current command. // If it is not satisfied, the command is not executed CATUnicodeString currentCond = iConditionName; rc = aflMgr->CheckCondition(iCondPredicateList, failObj, currentCond); ... |
Next the predicate attached to the command (#70) is handled in order to find the objects involved in the command. To do so, the different elements of the predicates are extracted. In general, a predicate consists of 4 fields: (name, expression, operator, value). In our example, the predicate looks like:
... #70=predicat('Action>AFLParent','V_abstract','=','Promoted automatically from parent.'); ... |
The first field contains a navigation path that specifies the objects related to the current Action through the link AFLParent. This path is retrieved before to be parsed using static method GetObjectsFromPath().
... CATIVpmGraphPredicat_var pred(iCmdPredicateList[i]); CATUnicodeString pathToObjs; // Get the path to objects pred->GetName(pathToObjs); // Look up for the objects specified by the navigation path CATLISTV(CATIVpmFactoryObject_var) listObjs; rc = aflMgr->GetObjectsFromPath(pathToObjs, listObjs); ... |
The objects found in the previous step should be of type Action and are children of the current one. The following loop statement allows to promote each of the child Action and update its abstract (attribute specified in the second field of the predicate) with the text specified in the 4th field of the predicate.
... int nbObj = listObjs.Size(); if (nbObj>0) { // Normally the objects found are of type AFLAction for (int j=1; j<=nbObj; j++) { childAction = listObjs[i]; ... rc = aflMgr->StepForwardActionStatus(childAction, "Promote"); ... rc = childAction->SetAbstract(value); ... |
This last step in this use case is to write a main program which makes use of the lifecycle. It consists of the following sub-steps.
[Top]
First the lifecycle to be used is checked to see whether it is defined or not. Next, an Action is created by specifying the lifecycle to be attached to. Notice that in general, if a lifecycle is not explicitly specified at the creation time, the lifecycle associated with the Action type is set by default. Also, once the Action is created, its status will be automatically set to the initial status defined in the lifecycle, which is "Created".
... // The name of the graph used is ENOVIA_ACTION_DESIGN_CAASample CATUnicodeString graphName("ENOVIA_ACTION_DESIGN_CAASample"); // The AFL manager provides a method which allows to get easily a graph manager CATIVpmGraphMng_var graphMgr; rc = aflMgr->GetGraphManager("Not_Relevant", graphMgr); ... CATListOfCATUnicodeString listOfGraph; graphMgr->GetListOfGraphName(listOfGraph); if (listOfGraph.Size()>0 && listOfGraph.Locate(graphName)>0) { cout << "Lifecycle graph '" << graphName.ConvertToChar() << "' is defined (out of " << listOfGraph.Size() << "). Continue..." << endl; } else { cout << "Could not execute this Use Case. Lifecycle graph '" << graphName.ConvertToChar() << "' is not defined (out of " << listOfGraph.Size() << ")." << endl; VPMSession::CloseSession(); return 2; } // Create an action of type Action_Design with the customized lifecycle called ENOVIA_ACTION_DESIGN_CAASample CATIVpmAFLAction_var action; CATUnicodeString actionType("Action_Design"); rc = aflMgr->CreateAction(actionType, action, "ENOVIA_ACTION_DESIGN_CAASample"); ... |
The ActionFlow Manger manages some object creations as well as their lifecycles. It also provides useful functions to query various types of objects.
A session is needed to retrieve a smart pointer to the standard FactoryManager. An interface query on CATIVpmAFLManager is then performed to retrieve the specific ActionFlow manager.
CATIVpmAFLManager | The ActionFlow Manager interface |
[Top]
In this step, two child actions are created and linked to the one created in the previous step. The relationship used is AFLParent.
... // Create 2 child actions CATIVpmAFLAction_var childAction1, childAction2; aflMgr->CreateAction(actionType, childAction1); aflMgr->CreateAction(actionType, childAction2); // Create Parent link between action and its children CATIVpmAFLLink_var link1, link2; aflMgr->CreateLink(action, childAction1, link1, "AFLParent"); aflMgr->CreateLink(action, childAction2, link2, "AFLParent"); ... |
[Top]
The last step consists of promoting the Action using the method StepForwardActionStatus() provided by the interface CATIVpmAFLManager. This first attempt will fail because the condition attached to the transition will fail since no abstract is defined for the parent Action. Once the abstract is set, the second attempt for promotion will succeed and the child Actions will be promoted as well after the command execution.
... // Promote the action // This should fail since the Action has no abstract specified rc = aflMgr->StepForwardActionStatus(action, "Promote"); if (rc==S_OK) { cout << "Promotion should fail because Action abstract is missing. Abnormal behaviour!" << endl; VPMSession::CloseSession(); return E_FAIL; } cout << "Promotion failed because Action abstract is not defined." << endl; cout << "Set the abstract and promote again..." << endl; action->SetAbstract("This Action is used for a CAA Use Case."); // Try again to promote the parent Action rc = aflMgr->StepForwardActionStatus(action, "Promote"); ... |
[Top]
This use-case demonstrates how conditions and commands for ActionFlow
lifecycles can be defined can be defined and implemented.
Despite the simplicity of the scenario, even more complex behavior could be
implemented thanks to a wide range of predefined commands already provided by
the ActionFlow. For more information about this list of commands and the full
syntax used for ActionFlow lifecycle see related documentation.
[Top]
[1] | Building and Launching a CAA V5 Use Case |
[2] | Working with VPM Graphs |
[Top] |
Version: 1 [Jan 2002] | Document created |
[Top] |
Copyright © 2001, Dassault Systèmes. All rights reserved.