| --- |
| Author: István Kovács |
| Version: 1553-CNL 113 512, Rev. B |
| Date: 2012-06-15 |
| |
| --- |
| = Guideline to create custom GUI |
| :author: István Kovács |
| :revnumber: 1553-CNL 113 512, Rev. B |
| :revdate: 2012-06-15 |
| :toc: |
| |
| == Presumed Knowledge |
| |
| In order to properly understand the documentation you shall be familiar with the TTCN-3 language <<_1, [1]>>, the use of the EPTF Variable feature <<_2, [2]>>, and the XTDP protocol module <<_3, [3]>>, <<_4, [4]>>. |
| |
| == Scope |
| |
| This document is to give some useful suggestions and information to the users of the Core Load Library to make the customized GUI creation easier. |
| |
| = Premises |
| |
| In the former WoW the component types published their data directly on the GUI. The layout of the GUI was built into the code; therefore each customization request needed the change of the code. |
| |
| No one can design a GUI which is suitable for all use cases. The complaints and change requests have been mushroomed, and the customization became more and more complicated. Therefore, a new, customizable GUI description API had to be implemented. |
| |
| = Design your GUI |
| |
| == New WoW |
| |
| In the new WoW the component types publish their data, which can be used to build up a GUI. You can pick the data you are interested in, and put them on the GUI as you wish. You do it using an XML file, which describes both the layout and the data content together. |
| |
| The XML is described by the _XTDL.xsd_ file, which is the part of the XTDP protocol module. It contains the same widgets as its ancestor, the XUL, which was the part of the `XTDPAsp` testport. |
| |
| But as long as in the previous WoW the GUI and the data behind it was absolutely separated (the XUL described the layout, the data was added from code), in the new WoW the GUI description contains both the layout and the data behind it. Descriptors of widgets – which can be joined to some kind of data – have been extended with an "externaldata" element, which describe the data to be joined. |
| |
| [[externaldataelements]] |
| == External Data Elements |
| |
| The component types publish their data in form of named data elements. Hereafter the component type publishing data elements are called to "data sources". |
| |
| The current CPS rate of a scenario is published, for example, by the data source named `ExecCtrl` in a data element which is named to `CurrentCPS`, the state of a traffic case in a data element named to `TcStatus`, the data element behind the start button of a traffic case is called to `TcStartButton`. |
| |
| === Attributes of the Data Elements |
| |
| The data elements have an `element` attribute, which identifies the data element by its name. |
| |
| The `source` attribute identifies the data source which publishes the given data element. Usually one component type publishes its data on one name, usually on its feature name, but it is possible to publish the data of the same component type under different names, and the `source` names can be different than the feature name. For example, the `LoggingServer` CT publishes its data under the name of `Logging`. |
| |
| Usually, more than one CT distributed on different PTCs can extend the same CT, for example, all load generator PTCs extend the `LoggingClient` CT. Therefore there can be more than one PTC in the configuration which publishes its data under the same name. The `ptcname` attribute identifies the PTC from which the required data has been published. This name is the `pl_selfName` parameter of the first call of the `f_EPTF_Base_init_CT` function. |
| |
| If there is only one instance from the given CT, the `ptcname` attribute is optional. |
| |
| So a sample data element description in the XML looks something like this: |
| [source,xml] |
| ---- |
| <externaldata element='CurrentCPS' source='ExecCtrl' ptcname='SimpleExecCtrl'> |
| ---- |
| |
| This means that the widget which contains this element will be joined to the data element called `CurrentCPS` of the ExecCtrl source which is placed on the PTC having the name `SimpleExecCtrl` . |
| |
| === Parameters |
| |
| There are some data elements, which have a real meaning as they are, for example, the `Exit` data element means the element behind the *Exit* button. But most of the data elements need further specification. For example, the `TcStatus` data element mentioned above needs the identification of the traffic case. These data elements have parameters, one or more, depending on the data element. For example, the `TcStatus` has three parameters: entity group name, scenario name, and traffic case name. |
| |
| The parameters have a name to identify them, and a value. The data description of the CPS of a scenario in the XML looks something like this: |
| [source,xml] |
| ---- |
| <externaldata element='CurrentCPS' source='ExecCtrl' ptcname='SimpleExecCtrl'> |
| <params> |
| <dataparam name='EntityGroup' value='DefaultEGrp'/> |
| <dataparam name='Scenario' value='DefaultWSc'/> |
| </params> |
| </externaldata> |
| ---- |
| |
| The order of the parameters is irrelevant. |
| |
| There can be data elements, which have different parameters in different combination, and the meaning of the data element depends on the combination of the parameters. For example, the only data element of the `LoggingServer` CT accepts the following parameters: `ComponentType`, `Class`. If there is no parameter specified, the data element means the global log enabled state. If only the `ComponentType` parameter is set, the data element means component type log state. If both the `ComponentType` and `Class` parameters are set, the data element means the log enabled state of the given log class of the given component type. Any other combination is invalid. |
| |
| [[Ext_Data_Example]] |
| === Example |
| |
| This sample shows how to display a data element (current CPS of the DefaultEGrp.DefaultWSc weighted scenario) in a treecell widget: |
| [source,xml] |
| ---- |
| <Widgets xmlns='http://ttcn.ericsson.se/protocolModules/xtdp/xtdl'> |
| <window> |
| <tree id='SCList'> |
| <treecols> |
| <treecol label='Name' widgetType='string' /> |
| <treecol label='CPS' widgetType='floatField' /> |
| </treecols> |
| <treechildren> |
| <treeitem> |
| <treerow> |
| <treecell label='DefaultEGrp.DefaultEGrp' /> |
| <treecell> |
| <externaldata element='CurrentCPS' source='ExecCtrl'> |
| <params> |
| <dataparam name='EntityGroup' value='DefaultEGrp' /> |
| <dataparam name='Scenario' value='DefaultWSc' /> |
| </params> |
| </externaldata> |
| </treecell> |
| </treerow> |
| </treeitem> |
| </treechildren> |
| </tree> |
| </window> |
| </Widgets> |
| ---- |
| |
| The resulting GUI: |
| |
| image::images/GUI_joined_data_element.png[GUI with a joined data element] |
| |
| [[iterators]] |
| == Iterators |
| |
| It is difficult to describe all scenario-s, traffic cases, etc. of the configuration, and modify the GUI descriptor XML each time when the configuration is modified. To make it possible to write a more flexible GUI description, the data sources provide list elements to go through the main configurable elements. These elements are called to "iterator". |
| |
| If you place an iterator into the GUI descriptor XML, during the process of the XML its embedded content will be multiplied as many times as many elements the iterator contains. For example, if there are two entity groups in the configuration, and the "EntityGroups" iterator contains a label widget, during the build up of the GUI there will be two label widgets instead of the iterator. |
| |
| === Iterator Attributes |
| |
| Iterators have the same attributes as the data elements, and these attributes have the same meaning. However, iterators have an additional attribute: `"id"`. You can write the content of this mandatory string attribute into the value of any string attribute in the content of the iterator between two "%" signs (see <<Iterators_Example, Example>> later), and it will be replaced with the actual value of the iterator. |
| |
| === Iterator Parameters |
| |
| There can be iterators which require parameters, just like the data elements. The use and the behavior of the parameters of the iterators are the same as in case of data elements. |
| |
| [[Iterators_Example]] |
| === Example |
| |
| This sample shows how to use iterators to list the scenarios existing in the configuration: |
| |
| image:images/example_1.PNG[alt] |
| |
| The highlighted parts show how to refer to the iterators in the other elements. |
| |
| [[GUI_which_lists_the_elements_of_an_iterator]] |
| image::images/GUI_elements_iterator.png[GUI which lists the elements of an iterator] |
| |
| == External Values |
| |
| The `externalvalue` element works as an iterator on a single value. The attributes and parameters are the same as in case of the iterators. The %ID%" reference returns the given variable value in charstring format. The "%ID::ref%" returns the variable name. Used in all places, where the iterators as well. |
| |
| [[External_values_Example]] |
| === Example |
| |
| This sample shows how to use `externalvalues` to read existing variable contents in the configuration: |
| |
| image:images/example_2.PNG[alt] |
| |
| The highlighted part shows how to refer to the `externalvalue` in the other elements. |
| |
| == Conditional Elements |
| |
| There are elements which are valid only in specified cases. For example, the CPS of a scenario – which is mentioned in <<Ext_Data_Example, External Data Elements Example>> – is valid only in case of weighted scenarios. |
| |
| === Condition |
| |
| The GUI descriptions can contain `condition` elements. They define a condition which can be used in their content. |
| |
| The `condition` element has the same attributes than the iterators, and they can have parameters too, just like the data elements and the iterators. |
| |
| === `Insertif` |
| |
| To use the conditions, in the GUI description there is an `insertif` element. As its name tells it, the content of the element will be added to the GUI if the referred condition is true. The `insertif` element has an `id` attribute, which refers to the `id` attribute of the referred condition element. |
| |
| The conditions of the `insertif` element can be negated. It has a `negate` optional boolean attribute. If it's set to _``true``_, the negated value of the referred condition will be used during the process. |
| |
| [[example-2]] |
| === Example |
| |
| The following sample describes how to use conditional elements to display only the weighted scenarios with their CPS: |
| |
| image:images/example_3.PNG[alt] |
| |
| As we saw on <<GUI_which_lists_the_elements_of_an_iterator, Figure GUI which lists the elements of an iterator>>, there are 9 "_scenario_"-s in the configuration. But using the `insertif` the resulting GUI contains only the weighted scenarios, as it can be seen on the figure below: |
| |
| image::images/Filtered_list_scenarios.png[Filtered list of scenarios] |
| |
| You can use the `insertif` and its negated version to display different content if the scenario is weighted or not: |
| |
| image:images/example_4.PNG[alt] |
| |
| This sample XML lists all scenarios not taking care if they were weighted or not, but the cells in the second column are linked to data elements only if the scenario was weighted. The resulting GUI is displayed on the figure below: |
| |
| image::images/Name_CPS_GUI_last.png[] |
| |
| = Integrate Into the Code |
| |
| In the `UIHandler` feature there are two functions to create the custom GUI: |
| [source] |
| ---- |
| public function f_EPTF_UIHandler_createGUI ( |
| in charstring pl_xul, |
| in charstring pl_parentWidgetId := "" ) |
| public function f_EPTF_UIHandler_createGUIFromFile( |
| in charstring pl_fileName, |
| in charstring pl_parentWidgetId := "") |
| ---- |
| |
| Both functions do the same, but the `f_EPTF_UIHandler_createGUIFromFile` function reads the layout from a file, and `f_EPTF_UIHandler_createGUI` gets it from a charstring parameter. |
| |
| The GUI description tree must start with the `widgets` element. It can contain `window` element, or any other element from the `widgets` group. |
| |
| The `UIHandler` processes the GUI description, builds up the GUI layout, and joins the data elements to the appropriate widgets. This time the configuration must be ready. If a component starts later, and its referred data source elements not published yet, the process results error. Or, if some configuration elements are not ready at the time of building the GUI, the iterators won't be updated later, and the GUI remains partially configured. |
| |
| You can create a whole window, or its parts. If the first child element of the root `widgets` element is a window, a `clearGUI` call will be performed first. |
| |
| You can call these functions several times and build up the GUI from parts if the first child was not a window. |
| |
| = Under the Hood |
| |
| == Collaboration |
| |
| Each component type which publishes its data must extend the `EPTF_DataSourceClient_CT` component type. In the `init` function it joins to the specified `EPTF_DataSource_CT`, which acts as a server. The data publisher components register their request handler functions. |
| |
| See DataSource client-server architecture in the figure below: |
| |
| image:images/DataSource_client_server_architecture.png[alt] |
| |
| The users of the published data source elements (data elements, iterators, etc.) can ask them from the `EPTF_DataSource_CT`. The `EPTF_DataSource_CT` processes the request, identifies the appropriate client, and forwards the request to it. Using this method the data requesting is independent from the configuration, e.g. from the number of load generators. |
| |
| == The Returned Data |
| |
| === Iterators and Data Elements |
| |
| In the Core Load Library the general way of handling data is the use of the Variable feature. Therefore it is evident that the values behind the published data are represented by EPTF variables. |
| |
| Each publisher component type registers the data request handler function: |
| |
| [source] |
| ---- |
| type function fcb_EPTF_DataSourceClient_dataHandler( |
| out charstring pl_dataVarName, |
| in charstring pl_source, |
| in charstring pl_ptcName, |
| in charstring pl_element, |
| in EPTF_DataSource_Params pl_params |
| ) runs on self return integer; |
| ---- |
| |
| When a request arrives asking a data element or an iterator, the function processes the relevant incoming parameters, and puts the name of the EPTF variable representing the requested data into the `pl_dataVarName` out parameter. The return value of the function must be 0 if the request was successful, otherwise it must be a nonzero value. |
| |
| In case of iterators, the returned EPTF variable always must have `charstringlistVal` direct content. In case of data elements it can be any valid EPTF variable direct content type. |
| |
| === Conditions |
| |
| There is another callback function for the conditions. |
| |
| [source] |
| ---- |
| type function fcb_EPTF_DataSourceClient_conditionHandler( |
| out boolean pl_conditionValue, |
| in charstring pl_source, |
| in charstring pl_ptcName, |
| in charstring pl_method, |
| in EPTF_DataSource_Params pl_params |
| ) runs on self return integer; |
| ---- |
| |
| Since a condition can be `_true_` or `_false_`, its output is a boolean value. The return value is the same as in case of the data request handler function. |
| |
| You have to register as many condition request handler functions, as many conditions your CT provides. |
| |
| = Publish your Data |
| |
| The following chapters demonstrate how easy you can publish your data using the data source. They contain code parts from the source code of the `ExecCtrl` feature. |
| |
| === Initialization |
| |
| The `init` function of the CT has an `EPTF_DataSource_CT` parameter. This `pl_dataSource_compRef` parameter has a default null value to make possible the use of the CT without `DataSource` server. |
| |
| [source] |
| ---- |
| public function f_EPTF_ExecCtrl_init_CT( |
| in charstring pl_selfName, |
| ... |
| in EPTF_DataSource_CT pl_dataSource_compRef := null) |
| runs on EPTF_ExecCtrl_CT { |
| ---- |
| |
| The `init` function initializes the `DataSourceClient` feature and registers the data request and condition request handler functions. |
| |
| [source] |
| ---- |
| f_EPTF_DataSourceClient_init_CT(pl_selfName, pl_dataSource_compRef); |
| if(pl_dataSource_compRef != null){ |
| ... |
| f_EPTF_DataSourceClient_registerData( |
| c_ExecCtrl_DataSource_sourceId, f_EPTF_Base_selfName(), |
| refers(f_EPTF_ExecCtrl_DSProcessData)); |
| f_EPTF_DataSourceClient_registerCondition(c_ExecCtrl_DataSource_sourceId, |
| f_EPTF_Base_selfName(), |
| refers(f_EPTF_ExecCtrl_conditionHandler_isWeightedSc), |
| c_ExecCtrl_conditionIsWeightedSc); |
| f_EPTF_DataSourceClient_registerCondition( |
| c_ExecCtrl_DataSource_sourceId, f_EPTF_Base_selfName(), |
| refers(f_EPTF_ExecCtrl_conditionHandler_isInScGroup), |
| c_ExecCtrl_conditionIsInScGroup); |
| } |
| ---- |
| |
| That is all you have to do during the initialization. |
| |
| === Responding the Data Requests |
| |
| The data request handler function receives all attributes and parameters which are present in the request (as it's described in <<externaldataelements, External Data Elements>>, and the <<iterators, Iterators>> chapters). |
| |
| [source] |
| ---- |
| friend function f_EPTF_ExecCtrl_DSProcessData( |
| out charstring pl_dataVarName, |
| in charstring pl_source, |
| in charstring pl_ptcName, |
| in charstring pl_element, |
| in EPTF_DataSource_Params pl_params) |
| runs on EPTF_ExecCtrl_CT return integer{ |
| ---- |
| |
| Usually the functions need only the `pl_element` attribute and the associated `pl_params`, because the function provides data of one PTC and one data source. But you can create a more complicated distribution if you wish. |
| |
| The function fills out the `pl_dataVarName` function parameter according to the `pl_element` and the `pl_params` with the name of the appropriate variable: |
| |
| [source] |
| ---- |
| select(pl_element){ |
| case(c_ExecCtrl_iteratorEntityTypesForLGen){ |
| ... |
| } |
| case(c_ExecCtrl_iteratorRegulatedItems){ |
| ... |
| pl_dataVarName := c_ExecCtrl_DS_iteratorVar_prefix & |
| c_ExecCtrl_iteratorRegulatedItems_varName; |
| ... |
| } |
| ---- |
| |
| If there was an error, returns a nonzero value. |
| |
| [source] |
| ---- |
| case else { //error, no rule for that |
| pl_dataVarName := ""; |
| f_EPTF_ExecCtrl_warning( |
| %definitionId& ": unhandled element: "& pl_element); |
| return -1; |
| } |
| } |
| ... |
| ---- |
| |
| If there request was successful, returns zero. |
| |
| [source] |
| ---- |
| return 0; |
| ---- |
| |
| === Responding to Condition Requests |
| |
| The condition request handler functions are really similar to the data request handler functions. They receive all attributes and parameters which are present in the request too. |
| |
| [source] |
| ---- |
| friend function f_EPTF_ExecCtrl_conditionHandler_isWeightedSc( |
| out boolean pl_conditionValue, |
| in charstring pl_source, |
| in charstring pl_ptcName, |
| in charstring pl_method, |
| in EPTF_DataSource_Params pl_params |
| ) runs on EPTF_ExecCtrl_CT return integer { |
| ---- |
| |
| And they fill out the `pl_dataVarName` function parameter according to the `pl_method` and the `pl_params`. |
| |
| = Available Data Source Elements |
| |
| The available data source elements, such as source identifiers, data element, iterator and condition names you can find in the APIDoc, in the definition modules of the features as charstring constants. |
| |
| == Abbreviations |
| |
| WoW:: Way of Working |
| |
| CT:: TTCN-3 Component Type |
| |
| CLL:: Core Load Library |
| |
| EPTF:: Ericsson Performance Test Framework, formerly TITAN Load Test Framework |
| |
| CPS:: Call per Second |
| |
| PTC:: Parallel Test Component |
| |
| == References |
| |
| [[_1]] |
| [1] ETSI ES 201 873-1 v3.2.1 (2007-02) + |
| The Testing and Test Control Notation version 3. Part 1: Core Language |
| http://www.etsi.org/deliver/etsi_es/201800_201899/20187303/03.02.01_60/es_20187303v030201p.pdf[Methods for Testing and Specification (MTS)] |
| |
| [[_2]] |
| [2] EPTF CLL Variable, User Guide |
| |
| [[_3]] |
| [3] XTDP Protocol Module Function Specification |
| |
| [[_4]] |
| [4] XTDP Protocol Module User Guide |