Tivoli Service Desk 6.0 Developer's Toolkit Interface Designer Guide
This following topics are covered in this section:
Before your TSD Script application can begin interacting with the host, the application must be initialized. EHLLAPI uses a handle to refer to the connection it has established and declares a variable of the EHLLAPI type, like this:
conn:EMUCONNECTION;
Next, the handle must be associated with a specific terminal session. The EHLLAPI command used to associate the session is:
EMUConnect(conn, 'A');
In this command, the handle conn is associated with the terminal session A.
Because all of the EHLLAPI commands require that a connection be specified, an interface application must establish these connections.
EHLLAPI supports multiple connections to terminal sessions, so an interface application might look like the following example:
VARIABLES conn1:EMUCONNECTION; conn2:EMUCONNECTION; ACTIONS EMUConnect(conn1, 'A'); EMUConnect(conn2, 'B'); END;
The TSD Script Interpreter associates various attributes to these connections. For instance, on one connection the watch time limit may be set to one second, and on another it may be set to 10 seconds. The TSD Script Interpreter gets the correct time limit from the connection handle specified when the watch command was issued.
Pressing a key signals the host to do something. For example, when you edit data, you may wish to clear a field. To do so, you press the control key named ERASE_EOF (erase to end of field).
Even when the processing required from the host is complex, submitting the data can be
as simple as pressing ENTER.
EHLLAPI provides a command to send data via control keys to the host. The command accepts
integer codes that represent control keys. TSD Script also has built-in constants that
serve as mnemonics for the integers. The code to press ENTER is shown here:
EMUPressKey(conn, $EMUEnter);
Any time a application submits data to the host for processing, there is a period of elapsed time when the application waits for a response from the host. It is necessary for an interface to be able to pause and wait out these periods. These periods are called watches.
There are several TSD Script commands designed to give applications the ability to execute these watches. When one of these commands is issued, the application pauses until the condition is satisfied, or until the watch time limit has expired. The return codes of watch commands indicate which actions were taken.
The conditions on which a application must wait depend on the situation. Generally, a application waits for the input inhibitor to disappear. Other watches may include:
For example, if you want a application to wait until the input inhibitor disappears, you can issue the command:
EMUWaitForNoX(conn);
When you use the EMUWaitForNoX command, you need to pay special attention to the mainframe application's use of the X indicator. Some applications allow the X to "bounce," which means that the X disappears momentarily, then re-appears for several more seconds.
The EMUWaitForNoX command has an optional parameter known as settle time. Settle time specifies how long the X must be gone before the TSD Script Interpreter deems the watch successfully completed. In cases where you do not specify settle time, a default of 500 milliseconds is used.
The previous command with an optional settle time of one second would look like the example below:
EMUWaitForNoX(conn, 1000);
The key to specifying a watch command is to set the watch command to give the user as much information as possible. For example, suppose you use a mainframe application that asks for a name and address and expects you to press the ENTER key to process the data.
The watch command for such an example could be:
rc := EMUWaitForStringAt(conn, 'ADD OPERATION SUCCESSFUL',11,11);
After you press ENTER, the X appears for a moment in the OIA, then a message appears at location 11,11 stating the success of the input operation, for example:
MSG000695 ADD OPERATION SUCCESSFUL
The previous return code indicates that the operation was completed and insertion was successful. If the return code indicates the watch failed, the code must be checked to see if the mainframe is still processing or if insertion failed. Note that this additional code only executes in error conditions.
If you use:
rc :=EMUWaitForNoX(conn);
you only know that the host is finished. The code must still check for a success message and the check must be performed for every instance of the command.
Even though both code segments require the same amount of checking, the first method streamlines successful processing.
Additional checking does not occur unless there is an error. As a result, successful actions (which you expect more often) run faster than unsuccessful actions.
There are numerous facilities provided by EHLLAPI for entering and editing data. These include commands to:
For situations where users type a string at the current host cursor position, the following example shows a sample command:
EMUTypeIn(conn, 'HELLO WORLD');
It is important to note that you cannot execute a TypeIn command when the host cursor is in an area where the host does not allow keystrokes.
One sequence of commands is used so often that a special TSD Script command has been implemented to replace the sequence. This command presses ERASE_EOF before typing in the string you have supplied. The command would look like this example:
EMUClrTypeIn(conn, 'HELLO WORLD');
Most applications allow you to tab between fields on a screen, or to use the arrow keys. In general, tabbing between fields is faster unless you are not using every field. In that case, consider using a move cursor command to go directly between fields.
You should review the maximum length of each field. If the EHLLAPI interface attempts to type when the cursor is in an invalid position on the host screen, the host locks the keyboard until RESET is pushed. To avoid this problem, make certain that either the data to be typed in is shorter than the receiving field, or that you have supplied a truncation length to the EMUTypeIn or EMUClrTypeIn command.
Because most mainframe applications are data entry applications, many EHLLAPI scripts consist of repeated simple operations:
These sequences are used so often that high level functions have been implemented to carry out the repetitive operations. These functions are known as maps. Maps, or mapping functions, allow you to relate host positions to TSD Script record fields.
An application can call one TSD Script command, EMUMapUpload, to fill all the fields. The TSD Script Interpreter processes map file entries much faster than it processes the sequence of simpler EHLLAPI commands. There is, of course, some overhead introduced for map files. As a general rule of thumb, you should consider a map file if you have more than five or six fields on a screen. For more information, see "Map Files and the Map Utility."
Using read commands is less complex than using send commands. First, the host cursor position is not pertinent in a read operation. Second, a application can read data from any place on the host screen.
In the simplest form, a read command looks like the following example:
EMUFillBuffer(conn, inString, row, column, length);
This command reads length characters starting at row, column and places the resulting value into the variable inString.
If you plan to read data fields from a screen, you need to know the maximum length of each field you want read. To see the entire length of the fields, the host application must clear all the data fields in preparation for new data. Generally, the empty fields are filled with underscores, which allows you to see the maximum length of each field.
Like the send commands, there is a map command for downloading a screen of data.
EMUMapDownload allows you to read many fields from a host screen and place their values in the fields of a TSD Script record variable.
There may be situations where you want to capture an entire host screen (or some rectangular portion of it) and store it in a text file. The most likely scenario for this is when your application encounters a screen it does not recognize.
In order to log as much of the occurrence as it can, the application captures the current screen to a text file and sends an alert about the problem. The person who investigates the problem uses the file to piece together the incident and ascertain how the application got to that screen. TSD Script provides the EMUOutFile command to cut the screen to a file.
Generally, you have an understanding of what you want an interface to do. This section is designed to help enhance interface specifications before you begin writing an interface.
The first step in designing an interface is to ensure that you are familiar with the application for which the interface is written.
You should work with the target application until you know exactly how to:
Additionally, you should learn the "ins and outs" of the application.
As you work, keep notes on steps necessary to carry out specific actions. These steps eventually become your interface code.
Look for "hidden" requirements. Analyze the types of data with which your application must work. In the case of call/problem management, you may want the interface to treat open problems with highest priority, while closed problems have more of an "as time permits" priority.
Understand the business rules your company (or department) uses-before you hard-code such rules into an interface, you should determine whether these rules still apply to the current situation. Determine and resolve these issues before you design your interface.
Make sure you have a way to identify the screens that are used. Mainframe applications usually have an identifier somewhere on the screen. The interface code should check that the correct screen is displayed (it can call an error routine and exit if not) before doing a data entry. This is a simple and effective way to provide good traceability of problems in the future.
Concurrency is another issue that must be addressed before an interface is written. In any situation where you have two systems containing the "same" data, there is an opportunity for the same data object to be changed in both systems at once.
First, decide how your application detects such an occurrence. The usual method is to check the update time and date on a record that is about to be overwritten.
Second, determine what should occur upon detection of a "collision." This action could be as simple as capturing the target record to a flat file and sending an alarm to some human administrator. Perhaps there is a business rule that applies, such as the "owner" of the record taking precedence over any other user who makes changes.
When you design an interface it's generally more efficient to use a top-down method (go from general to specific). However, when implementing an interface it is usually better to use a bottom-up method. With this method, you identify and implement the most atomic units of work for the interface. You then test each piece individually. These pieces can then become components of a module which performs a higher-level function.
The following procedure helps you learn more about testing a function.
You should test all routines individually. Routines that have no visible output can use the TSD Script Debugger to see the results. Otherwise you need to write an event group to display the results.
When you test routines that query data, it is recommended that you lock SQL tables as little as possible. Using SQLSelect to loop through a fetch and upload cycle locks the tables longer than necessary or acceptable.
After you test all routines, the steps for the main routine can be tested. The main routine probably needs to do some initialization, which can include:
Caution: Pay attention to the places where you plug one routine component into another. Make sure routine components always leave the host application at a known screen.
Structure main routines so that a key failure in one routine component has appropriate implications in processing. In other words, the main routine should not try to continue if a routine component indicates that there has been an unrecoverable failure.
Interface applications should always be written with error handling in mind. There are many events that can occur during interface operation.
There are several options for handling errors, depending on the type of error detected. Options include:
The best approach is a combination of the previous options. You can install a general error handling routine that notifies a user and logs the relevant information. The routine can be modified later to handle most recoverable errors. Unrecoverable errors always result in an alarm to the user.
Tivoli Service Desk 6.0 Developer's Toolkit Legacy APIs Guide