Advanced programming


An ACComponent has the property InitState of the type gip.core.datamodel.ACInitState which represents an enumeration. The InitState indicates the life phase of the ACComponent. The following picture shows which states the ACComponent can pass through during its lifetime:


In general, the life cycle can be divided into three types of cycles:

  • Standard cycle (blue highlighted).
  • Pooling cycle (orange highlighted)
  • Update cycle (green highlighted)

Initialization phases
The ACComponents are generated automatically by the runtime environment by reflection. The database provides information about the component. These are, for example:

  • properties,
  • default values,
  • configuration data,
  • variable bindings,
  • and script methods.

During this phase, the component passes through the blue highlighted state graph from Contructing to Initialized.

Scheduling phases

If an instance is no longer required or the iPlus program is terminated, then the second part of the blue highlighted state graph is run through (Destructing->Destructed).


During runtime, instances of the same type must often be instantiated and unloaded. The initialization process described in the standard cycle is relatively time-consuming and costs valuable CPU time. Optimization is possible by pooling instances that are no longer needed. If an instance of the type already exists in the pool, the iPlus runtime can retrieve the instance from the pool and reuse it. The iPlus runtime takes over the pooling mechanism and the necessary caching for you.

So that the iPlus runtime knows whether your own ACComponent class is poolable, you must overwrite the virtual property IsPoolable in your implementation and return true as the return value.


Disposing phases
If an instance is no longer needed, the first part of the orange highlighted state graph is executed. (DisposingToPool->DisposedToPool).

Recycling phases
If a new instance is required, the iPlusRuntime checks in the pool whether an instance already exists for the type searched for.

  • If yes, then it is reprocessed and the second part of the orange colored state graph is cycled through. (RecyclingFromPool->RecycledFromPool->Initialized).
  • If not, a new instance is created according to the standard cycle.

During commissioning it may happen that:

  • Corrections in scripts and workflows are implemented,
  • Additional properties are added,
  • or new routes are added.
Such changes require a restart of the corresponding Variobatch services. Often there is hardly any time frame for this, as the production plant is running at the same time. To avoid a restart, the affected components are reinitialized by means of an Update cylce.

Attention: This functionality is still in beta phase, use is not yet possible!

An ACComponent is created using one of the StartACComponent methods by reflection. For this reason, all constructors must have the same signature. The signature must be structured as follows:


Parameters:

acTypeACClassThe iPlus-Datatype (table ACClass)
contentIACObjectThe entity that encapsulates the component. Workflow instances (derivatives of the class PWBase) are an instance of ACClassWF when a workflow is reloaded. Otherwise it is a reference to ACClassTask which represents the persistent form of an ACComponent in the database.
parentACObjectIACObjectReference to the parent ACComponent.
parameterACValueListParameter list that provides individual or project-related information. The parameter list serves as a replacement for the fact that the constructor signature must always be the same.
acIdentiferstringDefined ACIdentifier which can be set with program-controlled instantiation or passed when the start methods are called. Is usually empty because the iPlusRuntime assigns the ACIdentifier and the sequential instance number.

 

You must always call the constructor of its base class, since the constructor from the ACComponent class is called last via the derivation hierarchy. The constructor then performs the following actions:

  1. State change of the InitState property to ACInitState.Constructing.
  2. Call of the virtual construct method, that you do not need to overwrite. If you want to overwrite them, make the base call. The Construct method loads the ACClassTask instance that is required to read persistent data for properties, asynchronous calls, event subscriptions, configuration data and thus restore / reconstruct the state on a iPlus restart.
  3. State change of the InitState property to ACInitState.Constructed.

Example on hwo to override the Construct-method:

 


The ACInit method is called directly after construction. You can also overwrite the ACInit method. When booting or dynamically reloading ACComponent trees, such as loading a workflow, the trees pass through the "Depth-First" + "Pre-Order" algorithm. This means that the generation of child ACComponents is always carried out in depth first and then the next ACComponent at the same recursion depth.


The algorithm is executed in the ACInit method of the ACComponent class. Therefore, you must always make the base call. This means that as soon as you execute your initialization logic after the basic call, you know that the child components were created and that they are in initialization state.

 
The Base-ACInit method of the ACComponent performs the following tasks:

  • Initializes all properties with their default and/or persistent values,
  • Performs property bindings between source and target properties,
  • Initializes point properties and their connections (e. g. routes),
  • Compiles script methods that have been added via the development environment.

After all new instances have been initialized by the pre-initialization phase, the post-initialization phase starts. After passing the same Depth-First + Post-Order algorithm, the ACPostInit method is called. The parental element is passed if there are no more child elements at the same recursion depth, starting with the lowest recursion depth:


You can also overwrite the ACPostInit method to program the remaining initialization logic. If these are dependent on all instances having to exist. In the Base-ACPostInit method of the ACComponent, the remaining property bindings are performed so that the target properties then have the value of the bound source property. Therefore, you must always execute the base call when overwriting this method.

 
After calling the base. ACPostInit method, the instance gets the status Initialized.


The termination of an ACComponent instance is initiated by the StopACComponent() method. The ACPreDeInit method informs the affected child instances in advance that deinitialization is taking place. The ACPreDeInit is called after the "Depth-First" + "Pre-Order" algorithm.

 


After the notification of all affected instances by calling the ACPreDeInit method, the actual deinitialization starts. This runs through the instances according to the "Depth-First" + "Post-Order" algorithm and calls the ACDeInit method. You should overwrite this so that you can release references or unsubscribe from events, among other things.


Don't forget to make the base call!
The basic ACDeInit method of theCComponent executes some functions to clear up the garbage collector. Before calling this function, first:

  • the state is set to Destructing.
  • If the instance is "poolable" (IsDisposable == true), it is given the status DisposingToPool instead.

At the end of the deinitialization process:

  • the state is set to Destructed,
  • or for a "poolable" instance on DisposedToPool. In this case, the instance is not cleaned up by the .NET garbage collector, but waits in a pool to be reactivated.

  1. In order for your ACComponent-Class to be poolable, you must reset all your class members and remove references in the overridden ACDeInit method. This corresponds to the state that is present after creation by the constructor.
  2. Override the IsPoolable-Property an return true.
  3. Optional: Test your class by assigning an object ID in the MS Visual-Studio-Debugger for the instance that will land in the pool. When the iPlus runtime then retrieves the instance again, the Recycle() method is invoked first, which you can override. Use then the object ID to compare whether it is the same object. Alternatively, you can overwrite the method Construct and make the object ID comparison in it. Check the behavior up to the ACPostInit call using the object ID. If the component behaves in the same way as for a new generated component, you can remove the overwritten methods if you no longer need them.

Sequence of recycling:
The recovery of an instance from the pool takes place in the same cycle as it is described in the pre- and post-initialization phase (Traversing tree). The only difference is that the recycle method is called instead of the constructor.

  1. The basic implementation of the recycling method first sets the status to RecyclingFromPool.
  2. Then the Construct-method is called and the state is set to RecycledFromPool.
  3. Finally the ACInit() and ACPostInit() calls are made as usual. In the Init methods, you can use the InitState property to distinguish between a newly created instance (Initializing) and a recycled instance (RecycledFromPool).

 


Sometimes the initialization methods described above are not the right way to insert individual logic during the initialization or deinitiilization phases. You often want to include your own special de-/initialization logic, for example, during a callback or when calling another method. To do this, use the methods AddToPostInitQueue (Action action) and AddToPostDeInitQueue (Action action). As a parameter, pass a delegate that contains your logic. This makes an entry in a queue. This queue is always processed after either all ACPostInit() or ACDeInit() calls have been executed.