In addition to accessing the Omnis App Server via the JavaScript Client, Omnis Studio lets you interact with a Remote Task in your Omnis application using standard HTML forms. This approach is often referred to as “Ultra-thin Omnis” since the client’s browser uses standard GET and POST methods without any other client access layers.
In the Ultra-thin Omnis environment, the HTML form sends parameters and data directly to the Omnis App Server via the Omnis web server plug-in located in the cgi-bin or scripts folder. When the ‘Submit’ button in your HTML form is pressed, the Omnis web server plug-in is executed and passed all the form’s parameters. The Omnis web server plug-in sends the request to the Omnis App Server, which creates an instance of the specified Remote Task Class and calls its $construct method.
The parameters required in the GET request in your HTML form contain the necessary criteria for interacting with the Omnis Remote Task in the Omnis library running on the Omnis App Server. Your HTML contains the location of the web server plug-in, the port number, the remote task name, the Omnis library name, as well as the specification for the fields in the form. For example, the following constructs a form with the GET method:
<form method="GET" action="/cgi-bin/omnisapi.dll">
<input type="hidden" name="OmnisServer" value="PortNumber">
<input type="hidden" name="OmnisClass" value="RemoteTaskName">
<input type="hidden" name="OmnisLibrary" value="LibraryName">
<p><input type="password" name="pPassword" size="20"></p>
<p><input type="text" name="pQuery" size="80"></p>
<p><input type="submit" value="Submit" name="B1">
<input type="reset" value="Reset" name="B2"></p>
</form>
The form has the special parameters:
OmnisServer
specifies the port number or service name of the Omnis App Server, that is, the value specified in the $serverport preference (in the range 1-65535) in the Omnis App Server.
The following example HTML source code implements a feedback form. The Omnis specific parameters are marked in bold; the remainder of the source specifies the form fields and text labels in the form, including a standard Submit button.
<form method="GET" action="/cgi-bin/omnisapi.dll">
<input type="hidden" name="OmnisClass" value="tFeedback"> ;; the remote task name
<input type="hidden" name="OmnisLibrary" value="FeedbackApp"> ;; the library name
<input type="hidden" name="OmnisServer" value="5912"> ;; the port number
<table border="0" cellspacing="0" cellpadding="0" width="760">
<tr>
<td width="788" valign="top"><div align="right">
<p><strong><font face="Arial">Developer Name:</font></strong></p></div></td>
<td width="564" height="25"><font face="Arial">
<input type="text" name="Name" size="27"></font></td>
</tr>
<tr>
<td width="788"><div align="right">
<p><strong><font face="Arial">Serial No:</font></strong></p></div></td>
<td width="564" height="25"><font face="Arial">
<input type="text" name="Serial" size="27"></font></td>
</tr>
<tr>
<td width="788" valign="top"><strong><font face="Arial">
<div align="right">
<p>Platform:</font></strong></td>
<td width="564" height="23"><table border="0" cellspacing="0" cellpadding="0" width="520">
<tr>
<td width="135"><font face="Arial">
<input type="checkbox" name="Macintosh" value="YES"> <strong>Macintosh</strong></font></td>
<td width="385"><font face="Arial">
<strong><input type="checkbox" name="Windows" value="YES">Windows</strong></font></td>
</tr>
</table>
</td>
</tr>
<tr>
<td width="788" valign="top"><strong><font face="Arial">
<div align="right"><p>Client:</font></strong></td>
<td width="564" height="23">
<table border="0" cellspacing="0" cellpadding="0" width="601">
<tr>
<td width="136" height="13"><font face="Arial"> <input type="checkbox" name="ActiveX" value="YES"> <strong>ActiveX </strong></font></td>
<td width="135" height="13"><font face="Arial"><strong><input type="checkbox" name="Netscape" value="YES">Netscape </strong></font></td>
<td width="330" height="13"><font face="Arial"><strong> <input type="checkbox" name="RAWHTML" value="YES">RawHTML</strong></font></td>
</tr>
</table>
</td>
</tr>
<tr>
<td width="788" valign="top"><strong><font face="Arial"> <div align="right"> <p>Comments:</font></strong></td>
<td width="564" height="249" valign="top"> <font face="Arial"><textarea rows="11" name="Comments"
cols="57"></textarea></font></td>
</tr>
</table>
<div align="center"><center><p><font face="Arial">
<input type="submit" value="Send Comments" name="B1"></font></p> </center></div>
</form>
In the above example, the HTML form uses the “GET” method. You can also use the “POST” method. The main difference lies in how the data is transmitted to the server, and this is reflected in cases where the URL generated by the form is displayed in the location bar of the user’s browser. A “GET” method is equivalent to requesting the URL
/cgi-bin/omnisapi.dll?OmnisClass=…&OmnisLibrary=…&…
whereas a “POST” method is equivalent to posting to the URL
/cgi-bin/omnisapi.dll
and sending content which specifies the parameters. If the URL is being displayed in the location bar, you might choose to use “POST” in order to hide the parameters from the user.
You can use secure sockets (HTTPS) if you have installed an SSL certificate on your web server. Omnis will use a secure connection to connect the client to the web server if you prefix the location of your HTML forms with “https://”. In addition, remote tasks have the $issecure property that lets you turn secure mode on and off dynamically, by assigning to the property for the current task at runtime.
Omnis passes a single parameter to the $construct() method of a remote task instance created by a request from an HTML form. This parameter called pParams is a row variable, and it has a column for each parameter in the HTML form.
The code contained in the $construct() method of your remote task could literally do anything you like and depends on the functionality of your application. Having passed in the row variable to your $construct() method you can use any type of Omnis programming to process the information submitted by the user and pass back whatever content or data you wish. Typically and with most complex web applications your library will contain many different methods that can be called from your remote tasks, most of which could be located in object classes to allow reuse of your code. See the Omnis Programming manual for information about programming Omnis methods and using object classes.
The column names in the row variable are the same as the form parameter names, and the values are either the values of the parameters in the form (e.g. hidden fields may have default values), or the values entered by the user. You can use the columns values in the pParams row variable (i.e. values in the form parameters) as input to what you do in $construct().
The following $construct() method is contained in a remote task that handles Studio evaluation download form requests. The method contains a parameter variable called pParams of Row type that receives the values from the form. The row variable contains a column for each field in the form, including the fields Email, Country, Platform, and so on, that are referenced using the syntax pParams.Colname. The method also contains several calls to methods in object classes within the library handling the download requests. After registering the customer, the method sends the customer an email and redirects their browser to the appropriate download page.
# $construct() for processing download requests
If len(pParams.Code)
Do iObj.$getMagazine(pParams.Code,lMagazineRow) Returns lCodeFound
# get magazine data (esp. name and serial number)
Else
Calculate lCodeFound as kTrue
# default to true for straight downloads
End If
If not(lCodeFound) ;; invalid magazine code
Do inherited
If not(len(pParams.Folder)>0)
Do method createFolderName Returns lFolder
; identify the folder name for this user
Else
Calculate lFolder as pParams.Folder
End If
Do iHTMLObj.$setFolder(lFolder)
# set the folder name for this instance of the html page
Do iHTMLObj.$setUrl(iUrl)
Do iHTMLObj.$createRegisterError(pParams,lFolder)
Else
Do iObj.$getDownloadCustID(pParams.Email,lCustID)
# see if this is an existing download customer
Do lAdminObj.$getDistID(pParams.Country) Returns lDistID
If not(lCustID)
Do iSequence.$getNext('ECS_DownloadCustomers') Returns lNextSeq
# get the next sequence number
Do iObj.$createDownloadCustRecord(lNextSeq,pParams,lDistID)
Calculate lCustID as lNextSeq
Else
Do iObj.$getDownloadCustData(lCustID,lCustRow)
# get their data
Calculate lCustRow.DistID as lDistID
# if the user has changed country their DistID may
# also have changed, so update it anyway
Do iObj.$updateDownloadCustData(pParams,lCustRow)
# update their account data
End If
Do iObj.$getPlatformID(pParams.Platform,lPlatformID)
# get the platform
Do iSequence.$getNext('ECS_Downloads') Returns lNextSeq
# get the next sequence number
Do iObj.$createDownloadRecord(lNextSeq,lCustID,lPlatformID,,,,pParams.Code, pParams.ProductID,pParams.HowDidYouHear)
If len(pParams.Code)
# if they have entered a magazine code, they need an
# email with a serial number
# send user email with the appropriate serial number
Do iEmailObj.$sendEmail(2,lCustID,lMagazineRow.SerialNumber,,kTrue)
# 4th parm is blank, 5th parm for using downloadcustomer table
Calculate lUrl as 'http://www.omnis.net'
Else
Do iEmailObj.$sendEmail(1,lCustID,,,kTrue)
# 3rd & 4th parm are blank; 5th parm is for using
# downloadcustomer table
Switch pParams.Platform
Case 'Win95'
Calculate lUrl as iWin95download
Break to end of switch
Case 'WinNT'
Calculate lUrl as iWinNTdownload
Break to end of switch
Case 'Ppc'
Calculate lUrl as iPpcdownload
Break to end of switch
Case 'Linux'
Calculate lUrl as iLinuxdownload
Break to end of switch
Case 'OSX'
Calculate lUrl as iMacosxdownload
Break to end of switch
Default
Calculate lUrl as iWin95download
Break to end of switch
End Switch
End If
End If
If not(lCodeFound)
Do $itasks.DOWNLOAD.$getUnsecuredUrl(lServerUrl)
# get the server path
Calculate lUrl as con(lServerUrl,sys(9),'downloadhtml',sys(9),lFolder,sys(9),iUrl,'.htm')
End If
Quit method lUrl ;; return the path to the approp download
The final command in the $construct() method is the Quit method <url> which returns an URL to the client’s browser. See the next section for further details.
After completing its processing, $construct() returns its results as the return value of the method, using the Quit method command. There are three possible types of return from such a remote task instance: <url>, <data>, and <error>.
$construct() can generate a file (typically HTML), and any files it references, and then return the URL of that file. For example, it can use the HTML report destination, and print a report to HTML.
You return the <url> in one of two forms.
Quit method "http://www.myhost.com/myfile.html"
Quit method "/omnishtml/00000001/myfile.html"
will result in the browser being redirected to
http://www.myhost.com/omnishtml/00000001/myfile.html
If you do generate dynamic HTML files, perhaps by printing reports to HTML, you can use the oDirClean object to periodically check for expired files, and delete them. The HTML report task wizard contains an example of how to do this. You should also note that if you are generating new output for each request, you need to use a different file name or folder for each request. The oDirClean object provides a mechanism which allows this.
$construct() can generate content directly in memory, and return that content to the user. The content can be of any content type supported by a browser, typically HTML, or perhaps a JPEG image. You build the content in either an Omnis character or binary variable. The content must start with the text “content-type:” to differentiates the data from a <url> or <error> (the other possible returns from $construct). The syntax of the data in the variable is:
HTTP headers starting with “content-type:” and separated by carriage return-linefeed pairs. There must also be a content-length header.
An empty line terminated by a carriage return-linefeed pair.
The content, for example HTML or JPEG data, the length of which must match that specified by the content-length header.
For example:
Begin text block
Text: Content-type: text/html (Carriage return,Linefeed)
Text: Content-len 12 (Carriage return,Linefeed)
Text: (Carriage return,Linefeed)
Text: Some con
End text block
Get text block iReturn
Quit method iReturn
returns the 12 character string “Some content” to the browser.
If you want to return binary content, you can build up the HTTP headers in a character variable, and then use the bytecon() function to combine the character variable and the binary content, storing the result in a binary variable. You can return the result as the return value of Quit method.
In addition to the content type and length headers, you can specify other HTTP headers if you wish. However, note that Omnis will automatically generate Expires: and Pragma: no-cache headers, so you should not generate these.
The following extract of code is an HTML based storefront that presents with many different HTML forms for logging in, choosing products, and so on, and heavily uses remote tasks to process user requests and compose HTML on-the-fly to display in the client’s browser.
# $create_rtOrder1 method for composing the store login screen
# do some preparation...
Begin text block
Text: <html> (Platform newline)
Text: (Platform newline)
Text: <head> (Platform newline)
Text: <title>Omnis Store - Login</title> (Platform newline)
Do method getCSSHeader
Do method getJSHelpHeader
Do method getHeader (kTrue) ;; kTrue - wide table
Text: <td width="262" ><span class="titletext">Login to the Omnis Store</span></td> (Platform newline)
Text: <td width="220"></td> (Platform newline)
Text: </tr> (Platform newline)
Text: <tr> (Platform newline)
Text: <td width="500" colspan="3"><span class="bodytext"> (Platform newline)
Text: The Omnis Store lets you purchase the Omnis Studio rapid application (Platform newline)
Text: development environment. Ordering is easy, just follow the step by step process.</span></td> (Platform newline)
Text: </tr> (Platform newline)
Text: <tr> (Platform newline)
Text: <td width="500" colspan="3"> </td> (Platform newline)
Text: </tr> (Platform newline)
Text: <tr> (Platform newline)
Text: <td width="500" colspan="3"><table border="0" width="100%" cellspacing="0" cellpadding="0"> (Platform newline)
Text: <tr> (Platform newline)
Text: <td width="500" colspan="3"><form method="Get" action="[iOmnisDll]"> (Platform newline)
Text: <input type="hidden" nam="OmnisLibrary" value="[iLibName]"> (Platform newline)
Text: <input type="hidden" nam="OmnisClass" value="rtNewCustomer"> (Platform newline)
Text: <input type="hidden" nam="OmnisServer" value="[iServerPort]"> (Platform newline)
Text: <input type="hidden" nam="IEBrowser" value="[pParams.IEBrowser]"> (Platform newline)
# store browser type
Text: <input type="hidden" nam="Folder" value="[pParams.Folder]"> (Platform newline)
Text: <input type="hidden" nam="BasketID" value="[pParams.BasketID]"> (Platform newline)
# store basket id if there is one
Text: <input type="hidden" nam="AcctsCountry" value="[pParams.AcctsCountry]"> (Platform newline)
# so we know the accounts country
Text: <input type="hidden" nam="InitialCountry" value="[pParams.InitialCountry]"> (Platform newline)
# so we know the initla country
Text: <input type="hidden" nam="SessionID" value="[pParams.SessionID]"> (Platform newline)
# so we know the session
Text: <table border="0" width="100%" cellspacing="0" cellpadding="0" bordercolor="#FFFFFF"> (Platform newline)
Text: <tr><td width="50%"> (Platform newline)
Text: <span class="subtitle">New Customers</span><br> (Platform newline)
Text: <span class="bodytext">Click here to create a new account:</span><br> (Platform newline)
Text: <input type=image src="../../images/buttons/newaccount/new1.gif" width="135" border="0" height="39" nam="NewAccount" (Platform newline)
Text: onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('NewAccount','','../../images/buttons/newaccount/new2.gif',1)"> (Platform newline)
Text: </td></tr></table> (Platform newline)
Text: </form> (Platform newline)
# etc etc etc...
The above code gives you some idea of how you can use the Text: command to build up complete HTML files and pass them back to the client. Note you can use Omnis variables enclosed in square brackets to fill in parameter values for form objects, such as:
<input type="hidden" name="OmnisServer" value="[iServerPort]">
$construct() can return an error to the browser. To do this, you use Quit method ‘nnn The Error message’, where nnn is a three digit error code followed by a single space before the error text.
The "x-omnis-ctrl:" control header can be returned at the start of the content to allow you to turn off the pragma:nocache header.
When returning content, it can either start with "content-type:" or "x-omnis-ctrl:". If x-omnis-ctrl: is present, it must be at the start of the content, to have any effect. To prevent the Omnis web server plug-in from generating the pragma:nocache header, start the content with:
x-omnis-ctrl:nopragma<cr><lf>
The letters can be in any case, but there must be no white space.
When a request arrives at the web server from an HTML form, there are some HTTP headers sent from the client that may be of interest to the remote task instance. These include “Cookie:” and “Referer”. (Note that a discussion of how the various HTTP headers work is beyond the scope of this document; there are many good sources of information on the Web). You can gain access to these parameters using the following mechanism.
In your HTML form, include an empty parameter with the name HTTP_<normalized header name>, where <normalized header name> is the header name in upper case with any – (hyphen) characters changed to _ (underscore), for example, HTTP_COOKIE. This is an instruction to the Omnis web server plug-in, telling it to insert the value of the corresponding HTTP header into the form parameter. This means that when $construct() runs, there is a column HTTP_<header name> in the row variable parameter, and its value is the value of the HTTP header. Note that the header value can be empty if it is either not present, or not available to the Omnis web server plug-in.
Normally, the remote task instance created to process an HTML form destructs, as soon as Omnis has called $construct(), and received the result to return to the user. It is possible that you may want to keep the remote task instance available, so that it can receive further requests. This mechanism is explained here. You should note:
This mechanism does not work in conjunction with Load Sharing (Load Sharing is described in a later chapter).
This mechanism does not detect use of the ‘back’ button on the browser, meaning that remote task instances can build up; these only go away when they time-out.
Each time Omnis receives a request from an HTML form, its default behavior is to destruct the remote task instance after returning the result. You can prevent this behavior, by implementing the $canclose method for the remote task instance, and returning kFalse if the task is to stay open. The remote task instance has a property $connectionid, which identifies the particular Omnis web client connection. The data you return to the user must contain $connectionid, so that the next request to the Omnis App Server addresses the remote task instance. Typically, you return a new HTML form to the user. This must contain a parameter “ConnectionID” which contains the value of $connectionid.
When an HTML form request arrives at the Omnis App Server, Omnis looks for the ConnectionID parameter. If there is none, processing proceeds in the usual manner, calling $construct() for a new remote task instance. If there is a ConnectionID parameter, Omnis tries to locate the existing remote task instance. If it is no longer present, Omnis returns an error to the user. Otherwise, Omnis sends an evPost event to the $event() method of the remote task instance.
evPost works in exactly the same way as $construct(). In other words, there is a parameter which is a row variable containing the HTML form parameters, HTTP header processing occurs for the parameters, and the result is one of the three alternatives allowed for the result of $construct(). The only difference is that the parameters and return value are handled using event parameters. Event parameter pPostData is a row variable containing the form parameters from the client, and you use the field reference event parameter pPostResult to return the result to the client.
After each call to evPost, Omnis calls $canclose, to see if the remote task instance can now be closed.
You can pass data and upload files from HTML forms to the Omnis App Server, using the Multipart form data type. The content type “multipart/form-data” can be used for submitting forms that contain files, non-ASCII data, and binary data files.
To use multipart form data, add the following attribute to the form tag:
enctype=”multipart/form-data”
and use the file=“type” attribute to identify files to be uploaded. For example:
<FORM method="POST" action="/omnis_apache" enctype="multipart/form-data" accept-charset="utf-8">
<input type="hidden" name="OmnisServer" value="3012">
<input type="hidden" name="OmnisLibrary" value="LIB">
<input type="hidden" name="OmnisClass" value="rt">
<input type="text" name="test">
<input type="file" filename="myfilename" name="fileparam">
<input type="submit" value="Send">
</FORM>
Note that the “get” method restricts form data set values to ASCII characters. Only the “post” method (with enctype="multipart/form-data") will cover the entire character set.
The form parameters are passed to the remote task using a row variable. Parameters without the filename attribute behave as in previous versions, that is, their contents is passed to the row variable. Parameters with the filename attribute are passed to the remote task via a column in the row variable, called MultiPartFileList. This column is a list, with a row for each filename parameter. The list has seven columns:
| Column | Description |
|---|---|
| ParamName | the name of the filename parameter |
| ReceivedFileName | the pathname of the file as it was specified on the client machine |
| DataLength | the length of the file data in bytes |
| IsText | if the length of the file is less than or equal to 16384 bytes, the data is in one of the following two cols, depending on the value of IsText |
| CharData | if IsText is kTrue, this contains the character data read from the file. |
| BinData | if IsText is kFalse, this contains the binary data read from the file. |
| TempFilePath | if the length of the file is greater than 16384 bytes, TempFilePath contains the pathname of a temporary file containing the file data; the temporary file is deleted after the remote task has returned from its $construct() |
In addition to the technique of connecting web based clients to an Omnis App Server via a standalone Web Server, you can connect directly to Omnis, without the need to install a Web Server (Omnis has its own built-in web server). Using the built-in http server may be a convenient way to test an Omnis Ultra-thin application, where the only difference is the format of the http call itself to Omnis: in all other respects your application, including the code in your remote tasks, is the same.
To enable direct connections to the Omnis App Server you need to make some modifications to the html file.
The WebServer script attribute needs to be set to /webclient
The WebServer url attribute needs to be set to
http://<ipaddress>:port
In this case, the OmnisServer address attribute is not relevant when connecting directly to Omnis in this way.
The direct http call to Omnis is structured like this:
http://<Server>:<Serverport>/Ultra
<Server> is the domain name or the IP address of the computer on which Omnis Studio is running. This is often 127.0.0.1 for your own local machine, but will be configured using a different address or server name on a remote server.
<Serverport> is the port number which has been set in $serverport of Omnis Studio; this is 5912 by default, but you can change it to anything you wish, in the range 1-65535. The $serverport property is an Omnis preference ($root.$prefs).
To try this out, create a library called "DirectHTTP" and add a remote task called "rtDirectHTTP". Then insert the following code into the $construct() method of the remote task:
# $construct() method
# create the following variables
# Parameter var: pParams (Row)
# Local vars: fullhtml (Char 100000000) & html (Char 100000000)
Begin text block
Text: <html> (Carriage return,Linefeed)
Text: <body bgcolor="FFFFFF"> (Carriage return,Linefeed)
Text: <title>Hello [pParams.User] </title> (Carriage return,Linefeed)
Text: <H1>Hello [pParams.User] </H1> (Carriage return,Linefeed)
Text: <a href="javascript:history.go(-1);">Go back</a> (Carriage return,Linefeed)
Text: </BODY> (Carriage return,Linefeed)
Text: </html> (Carriage return,Linefeed)
End text block
Get text block html
Calculate fullhtml as con('content-type: text/html',chr(13,10),'content-len ',len(html),chr(13,10,13,10),html)
Quit method fullhtml
The Remote task can be called within an HTML form with the following source text:
<html>
<form action="http://127.0.0.1:5912/ultra" method="Get"> What is your name?
<input type="Text" name="User" size="30" maxlength="50"></br></br>
<input type="Submit" name="Send" value="Send">
<input type="hidden" name="OmnisLibrary" value="DirectHTTP">
<input type="hidden" name="OmnisClass" value="rtDirectHTTP">
</form>
</html>
You must change the IP address and the port according to your configuration, although the IP address and port number given above are the default values.
Then open the HTML form in a browser, enter a name in the field, and click Send.
This will call the $construct method in the remote task "rtDirectHTTP", passing a parameter called "User" to it, which will contain the text you entered in the form. The full http call is like this:
http://127.0.0.1:5912/ultra?User=Username&Send=Send&OmnisLibrary=DirectHTTP&OmnisClass=rtDirectHTTP
The remote task processes the form values (and performs whatever other functions you like), and returns standard HTML text that is displayed in the browser.