Table of Contents

System objects


The model of objects that is used in the XOne script machinery allows access to all the functionality of the application with only some objects of global entity and without having to memorize a hierarchy of objects and functions typical of the runtime, since priority has been given to the knowledge of the structure of the application (collections and relationships between them) that is easiest for the developer.

Following are listed the objects that make up the model used by XOne script machinery.

Element Description
Objects Model in VBScript. Objects Model in VBScript.
Objects Model in JavaScript. Objects Model in JavaScript .

Scopes and Visibility


One of the most important things to understand before using the object model is understanding within which scope each script runs, in order to access the data correctly. At the XOne machinery you can find different areas of execution::

Objects


An script is running in object scope when the action that has invoked has been called from an object.


For instance, the actions of type <action> defined within the behaviour nodes of a collection, such as the case of <create> are in the scope of the object that contains them. .


So when an object is created new, the actions are executed within the <create> node of that object and if any of them calls a script, it will be executed in the scope of the newly created object.
In the object scope the global variable. This contains a reference to the object that the script is executing, in the case at hand, This would be the object that is being created.
In this scope the global variable ThisDataColl is Nothing.
The variables defined in this scope will last while the script execution lasts and they will be destroyed when the action in question ends.


Collection


This scope is much less common than the object. The scripts that are executed in this scope are the ones that are defined in <coll-action> nodes.

When a collection action is called, the scope will be that of the collection that contains the action that is running.

The most representative case in this scope are the <onlogon> actions that are executed when the user connects to the application. In this specific case, the scope in which each script is executed is that of the collection that contains the <onlogon> node.

When scripts are executed in collection scope, the global variable ThisDataColl contains the collection that called the script and the This variable is Nothing.



The variables defined in this scope will have the same lifetime as those in the object scope.

Local Scope


When a function is called (defined within an inclusion file, or within the same script block), a local scope is created in which you can define variables that follow the same rules as any language that allows local variables.

Local variables will be destroyed when leaving the function.Local variables will be destroyed when leaving the function.

Visibility


For each object of the model, the following visibility rules are met:



Nesting


When an script runs an action that causes the execution of events of the machinery:

  
 (e.g.. When an assignment to a property of an object is executed, said action can call another script).\\


It is important to bear in mind that when calling a nested script inside another one that is already running, the value of the global variables may change, since the action may be executing from a different place.
Each nested action must be considered as a completely independent execution. Global variables defined within a script are not visible within a nested action.
If an action wants to exchange data with another nested within it, it has to use methods that do not consist of the use of script variables, but have to resort to storing that data somewhere that is visible to any execution environment:
(e. g. Data objects within the collections, AppData object, parameters stack … etc.)

The nesting of scripts follows “the same rules” than the XML actions nesting of the XOne Machinery, so we will not expand too much on this concept.

Persistence


Although this concept is related to the field of data, we have separated it by the importance of understanding it. Once we have assimilated the operation (data life time) of the local and global variables within a script, we will refer to the storage of data in other media that, although, they are within the reach of the script code, this is not part of the runtime script in concrete, but of the XOne machinery in general.

So we have the following cases:


It is important to take into mind that if inside an script are loaded data in a global collection and from another one this collection is cleaned, the effects of both actions have scope within both scripts (e.g. If an object executes an script in its action <create> and inside this script is assigned value to a property that calls to another script in the <onchange> action, the second script will see the same data that was assigned by the first one, since it is operating over an object of the machinery. If the script of the <create> has created a global variable to save any value on it, this variable will not be visible within the script of the <onchange>.




Good Practices and Useful Information


Before starting to develop processes using a script, it is interesting to review this section, since the questions posed here are common questions that are raised repeatedly. In this way, the objective is to clarify some key concepts that are elementary for the correct understanding and execution of the developments.

Global Collections


If a global collection is “full” using the loadall method, independently of the script language used, will be full after exiting from the script, and therefore the framework will see it like that, full.

If a global collection is emptied or filtered within an script, these changes will affect the framework execution and of course other scripts execution.

This secondary effect may be exploited to search certain functionalities, but it may cause many headaches if it is not taken into account.


For instance, if the application uses the “Clientes” collection to show the clients list on screen and from an script a filter is applied as follows:

AppData.GetCollection(“Clientes”).LinkFilter=”CODIGO=1”


We are going to work only with this client, but when leaving the script, the clients global collection will be filtered by that code, and therefore, in the clients list of the application only will come up the client 1.


This that can be obvious it is a very difficutl problem to find when it is about complex applications, so it is good have into account these rules to minimize this problem:


Set c = AppData.GetCollection(“Clientes”)
c.LinkFilter = “CODIGO=1”
c.StartBrowse


The most suitable is doing:

Set c = AppData.GetCollection(“Clientes”).CreateClone
... resto del proceso ... 
' No olvidar destruir la referencia
Set c = Nothing


Once exiting from the scope in question, the “c” variable is destroyed, and as before the reference was canceled, the local collection is destroyed and the memory recovers.

The global collection “Clientes” has not been touched at all, so it doesn´t affect the UI behaviour of the application.


Startbrowse and Loadall are independent concepts


These two ways of going through a collection are totally differents and do not interfere at all between them, so it is important to understand what they are and how they work.


Although the detailed explanation is in the reference, here we just indicate some wrong behaviors or not at all appropriated that we have found in real applications:



This is not only unnecessary, it can be counterproductive. LoadAll loads all the objects of the collection in memory, so it can be big penalty to the application execution.

In fact, the StartBrowse mechanism has been developed to avoid loading all the objects of a collection in memory to work with them.

If we are going through a collection that have many objects to make any type of work with them, DO NOT call to LoadAll. \\In fact try NOT to call toLoadAll unless it is about cases in which you have the situation totally under control..


This is not necessary.
If we want to count the amount of elements of a collection in most of the platforms, just StartBrowse(True) which counts the elements.
If the platform doesn´t support the counting for this way, the most recommended is preparing a little collection in which you have an SQL of grouping to which put a filter and it is done by StartBrowse to read the counting value.

Loading an undetermined amount of objects in memory only to know how many there are is not necessary and besides consumes much more time than previous solutions.



Those databases that allow modify a table with open cursors they will will not give problems, those that do not allow it will cause execution errors.

As it is about an error not associated to any code but to the database, it can be difficult to determine the problem that originates it.

It have been made this affect affects as little as possible but always there are limitations. If the amount of objects to modify is not big, all of them can be loaded with LoadAll and modify them there.

If it is about a big amount of objects, we can think in modify them with an SQL sentence, or by default, locally store the Ids of the objects affected and then upload and modify them.

Keeping references to destroyed objects


If in an script a backup of a collection is created, or it is been working with a backup of an existing collection already (as it could be a contents, for instance) any reference done to an object of that collection must be canceled before exiting from the script.


If the reference to the collectin is canceled before exiting from the script, the references to the objects this collection contains must be canceled BEFORE canceling the collection.


This is because once the reference to the collection is canceled, the scripting machinery will try to destroy it, and this in turn will destroy the objects it contains. If the object is referenced later, this will try to work with a collection that has been destroyed with the consequent problem of access to released memory.

In some places, this may not cause problems, in anothers may cause the immediate exit from the program.

So, the idea is:

  1. Canceling the references inverse to its creation (Collection and then object, so the object is canceled and then the collection).
  2. Not storing collections created locally in global instances (a collection created inside a function must not be stored in global variable, a collection created within an script must not be stored in a variable of AppData neither in the parameters stack.)


Careful with the reentry: infinite loops


When an script can be called from several different situations it has to be ready to be reentrant.

An example is an script executed within an <insert> node and that in turn it calls to Save, or an script executed within an <onchange> that can causes the call to itself when modifying the same property that has executed it. These cases may cause infinite loops which will derive in an overflow stack.

At any of these cases marks stored in visible backgrounds for any script must be used, such as a property of the object itself, or the variables of the collection or the object in question.

Like this, a reentrant script could be more or less like this one:

<insert....
<action...
	If This(“MAP_SAVING”) = 0 Then
		This(“MAP_SAVING”) = 1
		. . . hacer cositas . . .
		This.Save	' Esto llama a esta acción otra vez
		This(“MAP_SAVING”) = 0
	End If
</action>
</insert>


When the call to Save causes the execution of the action nested inside the script we are executing, the execution in This will be interrupted .Save and it will be created a new scope of the same object called again to the script code.

The first thing it will be done is checking if MAP_SAVING has zero value. As the condition is not fulfilled, the script ends and comes out, so the previous scope is recovered and the script continues after This.Save, the flag is cleaned again and the normal execution of the script is finished.