PSL response function

Response function

The PSL response() function allows you to create interactive dialog boxes on the PATROL Console for information, collection, and presentation.

The function arguments of a response function defines the user interface elements.

Response function control

The first arguments of response() define the attributes of the response function such as title, timeout and appearance. The following arguments define the layout of the generated response window. Each argument contains a newline separated list of "type" with specific attributes of the type. Since each layout component is a separate argument in the call to the response() function, it will be impossible to let your PSL code build the desired response function. The only code variant part of the response() function will be the attributes of each type.

Response() return value

The response() function return value is again a newline separated list. The first line always indicates if OK (1) or the CANCEL (0) was pressed. Regardless of Accept or Cancel status, the return list fully describes the user's choices.

This first line is followed by a list of result values for each of the elements that made up the response window.

The order of the return values is the same as the order that the elements were defined in the response() function.

The following elements do not return values:

  • Labels (element types 0 and 1)
  • Separators (element types 4 and 5)
  • Frames (element type 14)
  • Row and column compound elements (types 15 and 16)
  • Icons (element type 17)

If a response() function time-out occurs, the function returns an empty string.

The PATROL Console can display multiple response() windows as it receives them from the Agent.

If multiple PATROL Consoles are connected to the same PATROL Agent, a response function window produced by a parameter recovery action will appear on each of them. In this situation, the first operator that presses OK or CANCEL will in effect acknowledge them all. Clicking on the remaining response windows will cause any effect on the agent, but they are not automatically removed.

BMC recommends that you not generate response windows from a recovery action. Should multiple agents have an issue, the operator could potentially receive multiple response windows. Since there is no option on the console to close all response windows, this will be a manual task for the operator. In case you really want to create response windows from a recovery action, make sure to provide a toggle so users can turn this option off.

If the response function window is generated in the context of a specific console session, such as a menu command, only that console will see the response window.

Dynamic response functions

If you select the "D=1" property for the response() function, an asynchronous response function will be created. The return value of the response() function will now be an rid (response id).

You can continue to update the response window by specifying this rid as the title of the response function.

Response pitfalls

The following sections describe a few pitfalls with using response.

This is an issue that a couple of developers have faced already.

For example, if you only want to allow one operator at a time to open a specific response box, you will have to use some sort of locking to make sure that the second response function cannot be opened.

If you use locking (the real lock() function), you will see that the agent will automatically release all locks held by the PSL process the moment it dies, so it seems that the PSL lock function will be able to help us out on this.

A piece of PSL code to illustrate that:

if (lock("MYLOCK","x",0))
{
   print("I've got the lock\n");
}
else
{
   print("Lock already held by someone else\n");
   exit;
}
response("LOCK TEST","","","1\nCLICK TO RELEASE THE LOCK");

You will see this will work and will allow you to have only one response function of a specific type active.

But by doing this you have created another issue. Let's say that your customer is using PATROL for 24h support and they have two operator sites (one in Belgium and one in Houston), so they can do "follow the sun" support. An issue occured in Houston during daytime and someone opened the response function.... Now what will happen if the guy who opened the response function forgot to close it? 12 Hours later the same issue occurs. The guy in Belgium tries to open the response function and gets a message that someone else already opened it.

To solve the issue (and get access to the response function), the guy in Belgium has to call the Houston office (probably no answer) or restart the agent (drastic intervention, just to release the lock)

So what do you probably also need here? An emergency unlock feature.

I mentioned that a lock would automatically be released when a PSL process is killed, so we change the PSL script to the following:

if (lock("MYLOCK","x",0))
{
      print("I've got the lock\n");
      set("lockpid",getpid());
      set("locktime",time());
}
else
{
      lockpid=get("lockpid");
      locktime=get("locktime");
      print("Lock already held by pid ".lockpid."
      timestamp=(".locktime.")nn");
      # Probably you would like to ask the user here if he
      # want to use the emergency
      # unlock ... we will presume he wants to
      kill ( lockpid );
      print("We killed the process holding the lock, ".
      "try again\n");
      exit;
}
response("LOCK TEST","","","1\nCLICK TO RELEASE THE LOCK");

Indeed, it seems the process can't be killed.... Well, this is something special. The process is in an IOWAIT state (see %PSLPS) and is therefore not considered to be running. So how can we fix that issue?

Well, it is obvious that we won't be able to kill the response function (because of IOWAIT state) if we write it like that.Maybe we can rewrite the response function so we can kill the PSL process? Take a look at this code:

if (lock("MYLOCK","x",0))
{
    print("I've got the lock\n");
    set("lockpid",getpid());
    set("locktime",time());
}
else
{
    lockpid=get("lockpid");
    locktime=get("locktime");
    print("Lock already held by pid ".lockpid."
    timestamp=(".locktime.")nn");
    # Probably you would like to ask the user here if he
    # wants to use the emergency
    # unlock ... we will presume he wants to
    kill(lockpid);
    print("We killed the process holding the lock, ".
    "try again\n");
    exit;
}
#Open a dynamic response function
rid=response("LOCK TEST",
          "","D=1","1\nCLICK TO RELEASE THE LOCK");
          "","D=1","1\nCLICK TO RELEASE THE LOCK");
output="";
while (!output)
{
    output=response get value(rid,1);
    sleep(1);
}
# Output received, kill it
response(rid,"","K=1");

This will work, because we have created a while loop that will allow the PSL process to come out of the IOWAIT state once every second. This is enough to have the process killed (and release the lock in case of emergency).

There are other workarounds possible to this issue. What you can also do is maintain a list (PIDLIST) with PID's that started this menu command (and will potentially modify something in the response function). If someone saves the info, you check if his PID is (still) in the PIDLIST.

If this is the case, you save the info and clear out the PIDLIST... This will prevent anyone else from saving the info (because the PIDLIST is cleared).

If someone opens the response box after the info was save, his PID will be added to the list again and he will be able to save his info.

I don't know if this procedure is clear, but it is not based on locking and it is secure, because the list will only be cleared if someone saves the info (meaning that we don't care about processes that die/disconnect).

Clicker behavior

For some developers it just seems to be impossible to get the clicker element in the response() function to work. Most of the times because of the inconsistency between the UNIX and the NT console, but sometimes also because they didn't clearly understand how it is supposed to work or behave. Before I get into the known problems, I would like to explain how the clicker is supposed to work.

You know you have to specify a minimum value and a maximum value and a default value. Let's refer to them as min, max, and default.

  • Element syntax: R CLICKER,"MyClick",min,max,default
  • If default doesn't lie between min and max, PATROL will take for default a value of (min+max)/2
  • If min ¿ max then min=0 and max=100

On the UNIX console there is/was indeed an issue.

The clicker window is sized according to the size of the default value. The value will be correct (you just have to scroll in the small window containing the number to see the actual value)

A possible work around is to make sure the default value contains at least as much characters a there are character in min and max. (a leading zero will not work for default)

min= 99;
max=10;
def= 50;
if (def>max) { def=max; }
if (def<min) { def=min; }
lenmin=length(int(min));
lenmax=length(int(max));
lendef=length(int(def));
# Trap clicker problem...set default to something else
if ((lendef<lenmin) || (lendef<lenmax))
{
     def=(length(min) > length(max)) ? min : max;
}
printf("min=%i - max=%i - def=%i\n",min,max,def);

Of course, this limits the use of this control a lot, because you will not be able to set default really as you would like to. (but in cause you don't mind, this might be useful). An alternative might be to use the slider or another response() control.

Was this page helpful? Yes No Submitting... Thank you

Comments