Services Builder for Screens


The Server-Side API technology provided in this package is used for both the Custom Step and Pinpoint Customization features in the Services Builder product.


Interface Summary
IController Custom Steps Only
This interface describes the interaction between IQAScreen and IDirectAccess objects.
IFieldData This interface describes a host field.
INavSystem This interface provides access to system level functions of the navigation engine from a custom step and scripted portions.
IPerformanceTool Custom Steps Only
This interface defines helper methods to assist the IController objects in increasing performance.
IQAScreen IQAScreen describes the Attachmate Quick Application for Java interface.
ITable This interface provides methods for populating and querying tabular data as it is supported in the navigation engine.
ITaskData This interface describes the interaction between a custom step and task variables.

Class Summary
BaseCustomNavStep Deprecated. use BaseCustomNavStepEx
BaseCustomNavStepEx Custom Steps Only
This class is the base for custom steps.
DefaultController Custom Steps Only
This class is the default controller for the IQAScreen.sendKeys.
VTBaseCustomNavStep Custom Steps Only
This class is the base for custom VT steps.
VTController VT controller for IQAScreen.sendKeys.

Exception Summary
ProtectedFieldException This exception will be thrown when an attempt is made to write to a protected field.
UserCustomStepException This exception should be used to wrap any exception that occures is a custom step and thrown from the custom step code.
UserScriptException This exception should be used to wrap any exception that occurs in script code and thrown from the script code.

Package Description

The Server-Side API technology provided in this package is used for both the Custom Step and Pinpoint Customization features in the Services Builder product. These features provide the ability to handle difficult navigation scenarios without having to resort to Native Access, but differ in the fact that Custom Steps allows users to customize all aspects of a given task step and Pinpoint Customization allows users to customers one or more phases of task step execution. The information found in the javadocs for this package pertain to both features unless otherwise noted.

Classes and Interfaces
The most important objects in this package are:

Best Practices for Custom Steps

All nav tasks are broken down into steps. Each step may consist of zero or more transient screens and one settled screen. Since no action is required to transition past transient screens, the nav engine simply loops until the settled screen is recognized. The nav engine executes each task step in three phases:

  1. Recognize the screen. In a branching scenario, the nav engine has a list of possible next steps. Each step is asked in turn to recognize the screen. When one of the steps recognizes the screen, that branch is taken. If none of the next steps recognize the screen, the global handlers are asked to recognize the screen. If the screen is still unrecognized, the task fails.
  2. Scrape data off the screen and apply data to the screen. Data is copied from the any specified screen fields into the task variables, then data is copied from the task variables to any specified screen fields.
  3. Transition to the next step. An AID key is sent to the host to cause the host to transition to the next screen. Execution then continues at phase one, or until the task endpoint is reached. Depending on whether task chaining is in effect, the nav engine will either recycle the task back to the beginning, or wait for the chained task to run.
SSA is an event-based API that reflects the activities of the nav engine. The nav engine will call your custom code to carry out each of the three phases listed above. The main class in SSA, BaseCustomNavStep has three methods that map to the three phases.
  1. isRecognized -- This method is called to give your custom step a chance to recognize the screen. Your code should look at the screen and return true or false to indicate if you recognize the screen or not. If not, the nav engine will move on to another branch, look for transients, global screens, or fail the task with an unrecognized screen. If true, your custom code will be called to process the data. If you want, you can have your custom code recognize more than one screen, and/or keep track of other information for use in a later phase, such as selecting different transition actions (AID keys).
  2. processData -- This method is called if isRecognized returned true. You can perform any screen processing you want in this step. Usually, you will copy screen data to task variables, and/or copy task variables to host fields. You can also keep track of host and/or user data for use in selecting different transition actions. You can accumulate table data for use in later steps. You can also introduce new variables to task data for use in later steps (you can arrange for your custom step to be called repeatedly in a task loop by using Task Builder to modify step destinations).
  3. getTransitionAction -- The nav engine calls this method after you have processed the data. You return the AID key that you want the nav engine to use to move to the next screen and/or step. If you want, you can return different values depending on the results from the earlier calls to isRecognized and processData.
For best integration with the rest of the task, and the general design of the nav engine and the Screen Connector product as a whole, it's best to stick to the scenario described above.

Best Practice considerations for both Custom Steps and Pinpoint Customization
IQAScreen is based on QACOM, and includes methods such as sendKeys, which will cause the host to navigate to another screen. This behavior isn't consistent with the operation of the nav engine, but it was provided for historical reasons, and because sometimes, it may be the only way to accomplish a particular goal.

As much as possible it is best to avoid sending AID keys from custom code. In other words, sendKeys is either not used, or if it is used, strings sent to it contain no AID keys. Note that this is only a suggestion, we do not enforce it. So if you know exactly what you want to do, and if you are willing to take full responsibility for all screen recognition, branching, global screens, unexpected screens, error detection and recovery, resource management and navigation back to a known state for task chaining and returning the session to SAM in good condition, by all means, do so. Just keep in mind that the nav engine does all this for you if you work within the architecture.

Although anything supported by the Java language is theoretically possible, it's probably not advisable to get too elaborate in your custom code. Both SSA and Pinpoint Customization code is running inside the server, and as such, you can have a very negative impact on scalability, performance and reliability. Since you're in the driver's seat, we don't tell you how to drive. It's quite possible for you to crash the entire run-time by using up all available memory, or making a recursive call that overflows the stack, for just two examples.

For performance, scalability and reliability, the nav engine is designed to use one thread (or less) per session. This keeps the thread count to a minimum and completely eliminates synchronization and deadlock. It also means that nothing is thread safe. As long as you use the thread that is given to you, this presents no problems. If you create a thread in your custom code, you are responsible for protecting your data from concurrent thread access. Furthermore, you should not call any SSA methods from your thread.

In addition to creating threads, there are other Java features that may not be advisable (or supported), such as network or file I/O. For performance, scalability and reliability, threads may be shared by more than one session. If you elect to perform a very lengthy I/O operation on the system thread, an entire pool may stop responding. Even if you spawn off a new thread to perform the I/O, the system thread will have to wait while your thread does its work. In either case, the net result is the same.

Finally, a word about error handling. You should catch all exceptions coming out of your custom code, and convert them to a UserCustomStepException if using custom steps or a UserScriptException if using pinpoint customization. When you catch the original exception, you can either get the message from the original exception and/or create a new message. Messages from UserCustomStepException and UserScriptException will get logged as a user error, and can also be returned to the client through the connector.

For example, in a custom step you should write code like the following:

    // all custom code inside this try block
catch(ProtectedFieldException severe)
    throw(new UserCustomStepException(severe.getMessage());
catch(NavException severe)
    throw(new UserCustomStepException("Navigation error:" + severe.getMessage());
catch(Exception unexpected)
    throw(new UserCustomStepException("Unexpected error:" + unexpected.getMessage());
In pinpoint customization script the code should look like the following:
    // all script inside this try block
catch(ProtectedFieldException severe)
    throw(new UserScriptException(severe.getMessage());
catch(NavException severe)
    throw(new UserScriptException("Navigation error:" + severe.getMessage());
catch(Exception unexpected)
    throw(new UserScriptException("Unexpected error:" + unexpected.getMessage());

Practical Considerations
There are a few idiosyncracies that you might find annoying if you aren't aware of them up front. Most of them are based on historical features of other APIs that may not map exactly to the server-side environment.

  1. Field indexes are zero-based. Fields are numbered starting with 0. Fields in Task Builder are numbered starting with 1. If you encounter problems getting field data, double check your numbering.
  2. Screen names and field names may not be reliable. Field accessor methods have "by index" and "by name" versions. Accessing fields by name only works if the screen you're dealing with happens to be on the nav map. Accessing fields by index will always work.

Once you have created your custom step, and converted your standard step to a custom step, you can test your custom step in Task Builder from the Test Task menu. You can debug your custom step in one of two ways:

  1. You can insert System.out.println statements in your code, and start Task Builder with the Java console turned on (as described in Task Builder help).
  2. You can attach a debugger to the Java VM. You can do this in Task Builder or in the run-time. Please see your debugger documentation for how to prepare the Java VM for remote debugging, and refer to the Task Builder or Screen Connector Run-Time help for setting Java VM startup options.
Life Cycle of a Custom Step
An instance of your custom step adapter comes into existence when the step that you have customized comes into scope, i.e., when the nav engine needs it to recognize a screen. This instance remains in existence until some time after the step has completed (after getTransitionAction) and the instance is garbage collected. A new instance is created each time the custom step executes. If you think of a step as a method call, your custom step adapter is like a local variable. Member data will not persist from one step to the next. If you want to persist step data, you can add it to the task data.

Many instances of a class may be created, but the class itself is loaded only once. The initial load is the most costly, because the classpath must be scanned, jars opened, and the class de-serialized. The class remains cached for the lifetime of the pool. Instance creation is then simply a matter of allocating the necessary memory and running some initialization code (if any). Similarly, though certainly not free, garbage collection has been fairly well optimized. Your custom step adapter instance is just one of many thousands of class instances that get created and destroyed every minute.

Your custom step adapter is only visible to the current invocation of the task step that you customized. So if you have hundreds of connections each running the same task, each step of each task has it's own personal instance of your custom step adapter. Since only one copy of the class is loaded, you can share data between all instances using static data, however access to such shared data can be very difficult to manage reliably.

Services Builder for Screens