12.1.3. Example: Creating a Custom Interface for Fluent Batch Jobs

Engineering Knowledge Manager

Administration Guide | Chapter 12: Defining Custom Dialogs, Wizards and Applications | 12.1. Defining Custom Dialog Boxes |

12.1.2. Defining Dialog Box Steps and Variables |  | 12.2. Defining and Using Custom Applications
Prev |  | Next

### 12.1.3. Example: Creating a Custom Interface for Fluent Batch Jobs

This example shows you the code used and steps taken to create a custom interface that will be incorporated into a job template. When a user executes the job template, the following custom dialog box will be displayed:

Figure 12.3: Custom Dialog Box for Fluent Batch Jobs

To create a custom interface to be used in a job template, you must perform two main tasks:

1. Define the components of the interface in an XHTML file.

2. Define a script with an initial macro, action macro, and ajax macro (if required).

#### Step 1: Define the XHTML Code

The XHTML code shown below can be used to define the components of the interface shown in Figure 12.3: Custom Dialog Box for Fluent Batch Jobs: The code consists of style classes, java script, and a mix of JSF, facelets, tomahawk, richfaces and some built-in EKM component tags.

    <html xmlns="http://www.w3.org/1999/xhtml"
    	xmlns:f="http://java.sun.com/jsf/core"
    	xmlns:h="http://java.sun.com/jsf/html"
    	xmlns:t="http://myfaces.apache.org/tomahawk"
    	xmlns:ui="http://java.sun.com/jsf/facelets"
    	xmlns:rich="http://richfaces.org/rich"
    	xmlns:a4j="http://richfaces.org/a4j"
    	xmlns:ing="http://www.ansys.com/ingress/spdm">

    <body>
    <ui:component>
    	<script>
    		function showHideCores() {
    			if(document.forms['actionForm']['actionForm:processingRadio'][0].checked == true ){
    				document.getElementById('numberOfCoresDiv').style.display='none';
    			}
    			else if(document.forms['actionForm']['actionForm:processingRadio'][1].checked == true ){
    				document.getElementById('numberOfCoresDiv').style.display='block';
    			}
    		}
    	</script>
    	<div style="height:100%; width:100%; min-height:330px; min-width:400px">
    		<h:graphicImage value="#{custom.url}/images/launcher.jpg" style="width:99%; padding-top:5px;"/>
    		<div style="float:left; padding-top:8px; width:49%">
    			<h:outputText value="Dimension" style="padding-bottom: 2px"/>
    			<h:selectOneMenu id="dimensionDropDown" value="#{custom.vars.dimension.value}">
    				<f:selectItem id="_2dDimension" itemLabel="2D" itemValue="2d" />
    				<f:selectItem id="_3dDimension" itemLabel="3D" itemValue="3d" />
    				<f:ajax render="doublePrecisionCheckbox" listener="#{custom.executeMacro('setDoublePrecisionValue')}"
    				event="change" execute="@form"/>
    			</h:selectOneMenu>
    		</div>
    		<div style="float:right; padding-top:8px; width:49%;">
    			<h:outputText value="Options" style="padding-bottom: 2px"/>
    			<div>
    				<h:selectBooleanCheckbox id="doublePrecisionCheckbox" value="#{custom.vars.doublePrecision.value}"
    				style="float:left;padding-right:5px"/>
    				<h:outputText value="Double precision" style="float:left; padding-top:3px"/>
    			</div>
    		</div>
    		<div style="clear:both">
    			<div style="float:right; padding-top:10px; width:49%">
    				<h:outputText value="Processing options" style="padding-bottom: 2px"/>
    				<h:selectOneRadio id="processingRadio" value="serial" onchange="showHideCores()" >
    					<f:selectItem id="serial" itemLabel="Serial" itemValue="serial" />
    					<f:selectItem id="parallel" itemLabel="Parallel" itemValue="parallel" />
    				</h:selectOneRadio>
    				<div id="numberOfCoresDiv" style="padding-top:4px; margin-left:10px; display:none; ">
    					<h:outputText value="Number of processes" style="padding-bottom: 2px"/>
    					<t:div>
    						<rich:inputNumberSpinner id="numberOfCores" value="#{custom.vars.cores.value}" inputSize="1"
    						style="margin-top:5px; padding-left:15px"/>
    					</t:div>
    				</div>
    			</div>
    		</div>
    		<div style="float:left; width:98%;padding:3px 0px">
    			<div style="padding-top:5px; width:100%;clear:both; ">
    				<h:outputText value="Use journal file" style="float:left; padding-top:2px"/>
    				<t:div id="journalFileDiv" style="float:left;">
    					<t:div id="innerJournalFileDiv">
    						<ing:browseWorkingDirectory value="#{custom.vars.journalFile}" width="99%" id="journalFile"
    						render="innerJournalFileDiv"/>
    					</t:div>
    				</t:div>
    			</div>
    		</div>
    		<div style="width:98%; padding-top:8px; clear:both;">
    			<h:outputText value="Other commandline options" style="float:left; width:100%;"/>
    			<h:inputText id="otherCommandLine" value="#{custom.vars.otherCommandLine.value}" style="float:left;
    			width:100%; margin-top:2px"/>
    		</div>
    		<t:div id="queuesDiv" style="width:99%; padding-top:8px; clear:both;">
    			<h:outputText value="Queues" style="float:left; width:100%;"/>
    			<ing:selectQueue value="#{custom.vars.queue}" hasAppKey="#{custom.vars.appKey.value}" style="width:100%"/>
    		</t:div>
    		<t:div id="commandLineDiv" style="padding-top:10px; float:right;">
    			<ing:viewCommandLine label="Command line"/>
    		</t:div>
    	</div>
    </ui:component>
    </body>
    </html>

In addition to components described in Defining a Custom User Interface, the following built-in EKM components are used:

Queue Selector Component

This built-in component shows a list of available queues. To following code is used to add the Queues drop box to the interface:

    <ing:selectQueue value="#{custom.vars.queue}" hasAppKey="#{custom.vars.appKey.value}" style="width:100%"/>

Required attributes:

- value. The variable for the queues defined by the user in the initial macro. In this example, a `queue` variable whose type is `QueuesVariableInterface` is defined in the initial macro.

- hasAppKey. The application key for which queues need to be found. This variable is defined in the initial macro. In this example, an `appKey` variable is defined in the initial macro.

Optional attributes:

- style. The CSS style definition to be applied to the component.

- styleClass. The CSS class to be applied to the component. If not defined, the default EKM style is applied.

- id. A unique identifier for this component. The value must be unique within the closest naming container.

File Selector Component

This built-in component enables the user to browse the working directory on the server and select an input file. It consists of an input box and browse button. When a file/folder is selected it will be shown in the input box. The following code is used to add the file selector component to the interface:

    <ing:browseWorkingDirectory value="#{custom.vars.journalFile}" width="99%" id="journalFile"
    render="innerJournalFileDiv"/>

Required attributes:

- id. An identifier for the component.

- value. The variable for the journal file defined in the initial macro. In this example, a `journalFile` variable whose type is `ServerFileVariableInterface` is defined in the initial macro.

- width. The width of the component.

- render. A comma-separated list of component ids that will be rendered after clicking a node in the tree.

Command Line Component

This built-in component enables the user to view the command line. When the user clicks the View Command Line link, a pop-up box will be displayed that shows the current command line. The following code is used to add the command line component to the interface:

    <ing:viewCommandLine label="Command line"/>

Optional attributes:

- linkStyle. The CSS style definition to be applied to the link.

- linkStyleClass. The CSS class to be applied to the link. If not defined, the default EKM style is applied.

- popupStyle. The CSS style definition to be applied to the pop-up box.

- popupStyleClass. The CSS class to be applied to the pop-up box. If not defined, the default EKM style is applied.

- id. A unique identifier for the component. The value must be unique within the closest naming container.

- label. The text of the link.

#### Step 2: Define Macros

To define the functionality of the custom interface, you must define a script that contains the following macros:

- An initial macro

- An action macro

- An ajax macro (if required)

You can define the macros on the Script tab of the Edit Job Template dialog box when creating the job template in which the custom interface will be used. See Creating a Custom Job Template in the User’s Guide for more information.

Defining the Initial Macro

The initial macro specifies the following:

- The name of the XHTML file that defines the content of the custom interface

- The name of the action macro that is used when the Finish button is clicked in the job submission wizard

- The variables used to store inputs specified by the user in the custom interface

    def init(ui, jobTemplate):
        ui.setCustomUi("ui/fluent_launcher.xhtml")
        ui.setActionMacro("action")

        ui.addVar("dimension", ui.VARIABLE_TYPE_STRING, "2d", False)
        ui.addVar("doublePrecision", ui.VARIABLE_TYPE_BOOLEAN, False, False)
        ui.addVar("cores", ui.VARIABLE_TYPE_STRING, "1", False)
        journalFile=ui.addVar("journalFile", ui.VARIABLE_TYPE_SERVER_FILE, "", False)
        journalFile.setFilterTypes("jou")
        ui.addVar("otherCommandLine", ui.VARIABLE_TYPE_STRING, "", False)

        appKeyVar=ui.addVar("appKey", ui.VARIABLE_TYPE_STRING, "", False)
        defaultAppKey=jobTemplate.getAppKey()
        appKeyVar.setValue(defaultAppKey)

        queueVar=ui.addVar("queue", ui.VARIABLE_TYPE_QUEUE, "", False)
        queueOptions=[]
        selectableQueues=jobTemplate.getSelectableQueues()
        for queue in selectableQueues:
            if queue not in queueOptions:
                queueOptions.append(queue)
        queueVar.setSelectableQueues(queueOptions)

The name of the initial macro is `init`. It has two arguments:

- ui. An instance of `CustomUiInterface`

- jobTemplate. An instance of `JobTemplateInterface`

The first line specifies the location of the XHTML file:

    ui.setCustomUi("ui/fluent_launcher.xhtml")

The argument is the path of the XHTML file that defines the content of the custom interface. The location of the XHTML file (and other resource files such as images, CSS files, JavaScript files, and so on) is dictated by the `customResourcesPath` setting in the ekm.xml file, which by default is set to `EKM_HOME/conf/resources`. The XHTML file can be placed in any sub-folder in the custom resources folder. You can then use the path `/custom/<relative path of file in custom resources folder>` to refer to the XHTML file in the custom resources folder. Job templates can be added to EKM by any user who may or may not have access to the EKM server’s file system. EKM handles this issue in the following ways:

- The resource files needed for the custom interface are added to the job template as an archive (in .zip, .tar, .tar.gx or .tgz format).

- The resource archive becomes a child of the job template object in EKM.

- When a custom interface needs to be opened, the resource archive is extracted to the following location:

  `<path to custom resources folder>/_custom_resource_cache_/<id of object>`

  where `<id of object>` is the internal ID of the object in EKM.

Because you do not know the ID of an object before it has been added to EKM, you cannot use an absolute path to specify the location of the XHTML file. When you specify a relative path, EKM will create the full path behind the scenes before the dialog box is opened. If the XHTML file is at the top level of the archive, then you can simply specify the file name (for example, `test-variables.xhtml`). However, if the file is in a folder then you will need to include the parent folder in the path (for example, `folder-name/test-variables.xhtml`).

The second line specifies the action macro that will be called when the Finish button is clicked in the job submission wizard.

    ui.setActionMacro("action")

When the initialization is complete, you can then add the variables used in the interface. This is done using the `addVar ()` method of the `CustomUiInterface` as shown in the following line:

    ui.addVar("dimension", ui.VARIABLE_TYPE_STRING, "2d", False)

The arguments are as follows:

1. The name of the variable

2. The type of variable

3. The default value of the variable

4. Whether or not the variable is multi-valued

The following types can be specified:

- VARIABLE_TYPE_LONG: For integers

- VARIABLE_TYPE_DOUBLE: For real numbers

- VARIABLE_TYPE_BOOLEAN: For Boolean (true/false) values

- VARIABLE_TYPE_STRING: For strings

- VARIABLE_TYPE_DATE: For date and time

  The default value must be an instance of the `java.util.Date` class. You can set the default to the current time by calling `Calendar.getInstance().getTime()`.

- VARIABLE_TYPE_FILE: For files that are uploaded to EKM

  The default value must be `null`.

- VARIABLE_TYPE_QUEUES: For specifying the queues

  To use the Queues drop-down box as defined in the Example: Creating a Custom Interface for Fluent Batch Jobs section, you must add a variable of type VARIABLE_TYPE_QUEUE in the initial macro:

      queueVar=ui.addVar("queue", ui.VARIABLE_TYPE_QUEUE, "", False)
          queueOptions=[]
          selectableQueues=jobTemplate.getSelectableQueues()
          for queue in selectableQueues:
              if queue not in queueOptions:
                  queueOptions.append(queue)
          queueVar.setSelectableQueues(queueOptions)

  This will create a variable of type `QueuesVariableInterface`. Optionally, you can get the list of selectable queues as defined in the job template using the `setSelectableQueues()` method. If the list of selectable queues is also specified for the queues variable, only the selectable queues containing the application will be shown in the drop-down list.

- VARIABLE_TYPE_TABLE: For tables

- VARIABLE_TYPE_SERVER_FILE: For selecting a file from the server

  To use the server file selection component defined in the Example: Creating a Custom Interface for Fluent Batch Jobs section, you must add a variable of type VARIABLE_TYPE_SERVER_FILE in the initial macro:

      journalFile=ui.addVar("journalFile", ui.VARIABLE_TYPE_SERVER_FILE, "", False)
          journalFile.setFilterTypes("jou")

  This will create a variable of type `ServerFileVariableInterface`. Optionally, you can specify a comma-separated list of file types using the `setFilterTypes()` method. If filter types are specified, only files of those type in the working directory will be shown in the tree.

For multi-valued variables, the default value must be a list. For example:

    ui.addVar("listBox", dialog.VARIABLE_TYPE_STRING, new String[]  {"List Option 1", "List Option 2"}, true);

In the above line, the variable `listBox` is a multi-valued variable whose default value is a list with two elements: `List Option 1` and `List Option 2`.

Defining the Action Macro

An action macro is called when the user clicks Finish in the job submission wizard. This macro processes user inputs and executes commands. The code for the tutorial example is shown below.

    def action(ui, jobTemplate):
        jobTemplate.addParam("-hidden")
        defaultAppKey=jobTemplate.getAppKey()
        jobTemplate.setAppKey(defaultAppKey)
        dim= ui.getVar("dimension").getValue()
        precision=ui.getVar("doublePrecision").getValue()
        if precision:
            precisionString="dp"
        else:
            precisionString=""
        if dim:
            jobTemplate.addParam(dim+precisionString)
        journalFile=ui.getVar("journalFile").getValue()
        if journalFile:
            jobTemplate.addParam("-i")
            jobTemplate.addParam(journalFile)
        cores= ui.getVar("cores").getValue()
        if cores:
            jobTemplate.addParam("-t")
            jobTemplate.setCores(int(cores))
            jobTemplate.addParam(cores)
        otherCommandLine= ui.getVar("otherCommandLine").getValue()
        if otherCommandLine:
            jobTemplate.addParam(otherCommandLine)
        queue=ui.getVar("queue").getValue()
        if queue:
            jobTemplate.setQueue(queue)

The name of the macro is `action`. It has two arguments:

- ui. An instance of `CustomUiInterface`

- jobTemplate. An instance of `JobTemplateInterface`

You must update the values in `JobTemplateInterface`; in other words update the job execution settings with the values specified in the variables of `CustomUiInterface`. The updated job settings will be used to execute the job.

Defining the Ajax Macro

An ajax macro is used to partially update the interface when a user interacts with it. For example, if the user enables a check-box or radio button, you may need to re-render a portion of the interface so that different content is displayed.

You can define an ajax macro for any component specified in the XHTML file using the `f:ajax` tag of jsf, as shown below:

    <f:ajax render="componentId1, componentId2" listener="#{custom.executeMacro('ajaxMacro')}"
    event="change" execute="@form"/>

The `executeMacro` method of `CustomUiInterface` has a single `String` argument, which is the name of the ajax macro. In this example the name of the macro is `ajaxMacro` and it has a single argument, `ui`, that is an instance of `CustomUiInterface`. You can change the value of any variable in `CustomUiInterface` using another variable and render the corresponding component again to see the changes.

#### Final Step: Adding the Custom Interface to the Job Template

When the XHTML file and macros have been defined, you can incorporate the custom interface into the job template by following these steps:

1. Save the XHTML file and all required resource files in an archive file (.zip, .tar, .tar.gz or .tgz) on your local computer. In this example, the name of the resource archive is Fluent Launcher.zip.

2. In the Edit Job Template dialog box, select the UI tab, and specify the name of the initial macro (for example, `init`) and the location of the resource archive, as shown below:

For more information, see Using a Custom Interface for Job Execution in the User’s Guide.

Contains proprietary and confidential information of ANSYS, Inc. and its subsidiaries and affiliates.

Prev | Up / Contents | Next

Release 18.2 - © ANSYS, Inc. All rights reserved.