Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

At first glance each of the above scenarios seems very different. Some of the examples work with already running engines while others dynamically launch engines. Some work with local engines while others connect to engines running on a different machine. Despite these differences, they all use the same basic logic to accomplish their tasks. Therefore, it will be well worth the effort to build a generic or “black box” system for working with multiple engines. This white paper will help you to design this foundation.

Getting Started 
Anchor
Getting Started
Getting Started

Our intent is to provide you everything you need in this document to begin designing applications capable of using multiple engines. Nevertheless, you might be interested in getting a copy of the previously mentioned OI 4.1 New Features.pdf document. In some areas it has more detail regarding the new OpenEngine which might be helpful to programmers who desire to dig a little deeper.

...

ErrorCreateRequest(hRequest, hQueue, ExecLine, Arg1, Arg2, Argn, …)
ErrorReturns error number or 0 if no error (see the References section below.)
hRequestReturns the handle to the request if successful. Variable should be initialized to null beforehand.
hQueueThe handle returned by the CreateQueue function.
ExecLine

Remote process to execute. Use the same syntax as when entering commands in the System Monitor and the System Editor’s Exec line:

Code Block
RUN RoutineName 'Param1', 'Param2', 'Paramn', . . .

Note: Any command line that is passed through the ExecLine parameter will be a literal string. Here is an example of how this might look:

Code Block
ExecLine = "RUN CHECKLEGALUSER 'ADMIN', 'MYSECRET'"
Error = CreateRequest(hRequest, hQueue, ExecLine)

As this example demonstrates, parameters are always literals. Addtionally, CreateRequest does not wait for the remote request to finish processing. Therefore we do not have the ability to detect changes that are made to these parameters as we normally would when passing parameters by reference. If this is a requirement then there are two options: 1.) Design the remote request to send back changes through the normal return data process (see the Twiddling Our Thumbs section below), or 2.) use the previously mentioned CallFunction or CallSubroutine commands instead (see the Requests for Dummies section below.) Using these commands, however, means that our local engine will be waiting for the remote engine to finish processing. While this provides us the ability to connect to remote engines, it defeats our purpose of “multitasking”.

Arg1…Argn

Actual arguments to pass into the ExecLine if replaceable parameters are used. In the example used above we embedded the RoutineName parameters in the ExecLine string. CreateRequest can also work with replaceable parameters. Using the CHECKLEGALUSER command this alternative syntax would look like this:

Code Block
ExecLine = "RUN CHECKLEGALUSER #1, #2"
Arg1 = "EXAMPLES"
Arg2 = "MYSECRET"
Error = CreateRequest(hRequest, hQueue, ExecLine, Arg1, Arg2)

Note that the replaceable parameters were not quoted. Otherwise, RemoteRequest will treat them as the literal values to be passed.

...

ErrorReturns error number or 0 if no error (see the References section below.)
hQueueThe handle returned by the CreateQueue function.
Subroutine

Remote subroutine to execute. Unlike CreateRequest, the RUN command is not needed nor is it supported. If the function is local to the database that was specified in the CreateQueue function then only the subroutine name is required. Otherwise, append an asterisk and the application name to the subroutine name:

Code Block
Subroutine = "MyDivSub" ; * Or "MyDivSub*APPNAME" if necessary
Arg1 = 70
Arg2 = 5
ReturnValue = "" ; * Initialize the variable
Error = CallSubroutine(hQueue, Function, Arg1, Arg2, ReturnValue)
Arg1…ArgnArguments (parameters) for the remote subroutine. Unlike RemoteRequest, these arguments can be passed by reference. That is, any changes made to the original values in the remote subroutine will be returned to the variables used in our calling routine.

Twiddling Our Thumbs 
Anchor
Twiddling Our Thumbs
Twiddling Our Thumbs

Once RemoteRequest has successfully executed our process, it is our responsibility to monitor the status of the remote engine. Two functions are available for this: WaitForReply and PollForReply. In the Getting the Big Picture chart above only PollForReply is mentioned. This is because WaitForReply does exactly what its name implies; that is, it waits for a reply from the remote engine before proceeding. Therefore, if our remote process is busy performing a long process then our local engine will be forced to wait until it is completed. Actually, to be technically correct, if the remote process uses the Send_Info or Send_Dyn commands to send information back then WaitForReply will allow the local engine to receive it. WaitForReply must then be called again to wait for the next information update or until the remote process has completed. Because many processes do not use Send_Dyn or Send_Info (like RList selects), WaitForReply is only a little better than using CallFunction or CallSubroutine.

...

Whenever any of our functions returns a value other than 0 we need to compare this with the list of errors from the Error Definitions (REVCERRS.H) file (see the [[1]]the References section below for a complete list.) Here is a portion of code that can be used:

...

With this final piece tied together you now have a “black box” approach toward managing remote engines. While this does not exhaust all that is possible with remote engines, we believe this will give many applications a significant enhancement boost in functionality. We hope that you will agree.

References 
Anchor
References
References

Further information we think will be helpful are listed here for your convenience:

...