Paradox Community
Search:

 Welcome |  What is Paradox |  Paradox Folk |  Paradox Solutions |
 Interactive Paradox |  Paradox Programming |  Internet/Intranet Development |
 Support Options |  Classified Ads |  Wish List |  Submissions 


Paradox OCX Internet/Intranet Articles  |  Non-OCX Internet/Intranet Articles  


Paradox Web Server
Lesson 3 - Some More Meat
© 2001 Tony McGuire

Lesson 3 - Some More Meat

I have the beginnings of an FAQ on the technical side of request to response on the Internet. Placing it on the Internet allows me to present this concept along with screen shots of the OCX and the Paradox form and library methods/procedures/const/uses etc. sections.

I was a little leary of opening this up yet, as it is very much a work in progress and may be updated hour to hour. Also, it "ass"-"u"-"me"s that the viewer is a little more familiar with the OCX and the Paradox libraries than I would prefer to start out with. I think it may be helpful enough, however, that I am including a link to these pages: FAQ.

Please don't play in any other sections of the site or I will get skinned by my boss. The above is on a production server that we are relying on heavily.

Now, some more meat. First, you need to go to the Examples ":wsample:" (C:\Program Files\Corel\WordPerfect Office 2000\Paradox\Websrv\Sample if you accepted the default) directory and open the Server.fsl and Hercules.lsl files in "edit form design".

When the form on a page on the Internet gets activated (we will work only with, and assume, POST requests), the request gets sent to the server indicated in the "action" portion of the form statement. If there isn't a full URL, your browser directs the request to the site that sent the form. Thus, you could actually "redirect" the action of the form to another site to handle the request if necessary, by putting the full "http" etc. within the action statement. Otherwise, the location of the site that should handle the request is automatically included, along with whatever explicit action you declare. (i.e. If the form was generated by "http://www.foo.com" and the action statement on the form was simply "getname", the form information would be sent to "http://www.foo.com/getname". On the other hand, you could spell out in the form's "action" statement action="http://www.redir.com/getname" and the form information would be sent to this other domain for processing.)

(Hint: I use POST rather than GET as the form method, since the GET command shows all variables being passed in the "Location" or "Address" bar on the user's browser. There isn't really anything confidential about this information, but it tends to be a little less confusing when the user doesn't see all the junk being passed. It also adds a little security, since a POST requires a form, whereas a GET can be typed into the "location" or "address" section of the browser. More on the security part later. This also simplifies programming, since the OCX/Paradox form then only watch for POSTs and process with OnPostRequest(). Totally a personal preference, but it has worked well for me.)

OK. The POST has been sent from the user's browser to the location named in the "action" portion of the Internet form. Your OCX is set to watch for and process requests for POST actions by passing the information to Paradox. This kicks in the OnPostRequest() method (this method is within the OCX, not the Paradox form), which checks with OpenLibrary() (another method in the OCX, not Paradox form) to see if there is an associated library/function declared that should handle this request.

Here is where the flow of processing seems to get a little convoluted (seem convoluted already?) but in reality the flow is designed for maximum flexibility.

In the Example, there is a table named SERVER.DB. This table contains 4 fields.
REQTYPE, which is "is this a POST or GET" type of request.
URI, which is the action that is defined in the Internet form
LIBRARY, which is the library file that should handle this request for action
HANDLER, which is the function (method) that should handle the request for action. (Remember, in lesson #2 I stated that the form "Action" and the method name didn't have to match? This is one place where you could change the method that should handle the action.)

Using a table to break the requests down and define a library/routine to handle the requests is not a requirement to making this all work. You could take several approaches. This is how the examples showed, and this methodology has worked _very_ well for me.

OK. In the OCX, the VAR section defines a tcursor, and in the DoStartUp() method the tcursor is opened on the "server.db" table. This means that there is always a tcursor opened on the table that contains the information that the OCX will use to determine what to do with a request for action. The table is keyed on REQTYPE and URI, which makes it possible to use qlocate(); this is a nearly instantaneous lookup.

When a request for action arrives at the OCX, and it is a POST request, the OCX activates the OnPostRequest() method. This method (OPR for reference) uses the open tcursor to check if there is a matching REQTYPE and URI. If not it does nothing but display a "404 - not found".

If it does find a match, it uses openlibrary() to ensure that the library defined in the matching record is either open or can be opened. Then, it passes to that library's "handlerequest()" method the "HANDLER" field in the matching record of the tcursor. This is why the uses block of the OCX does not have to contain every method within the library, or libraries, that it will use. "handlerequest()" is the only method that will ever be referenced; this is also why "handlerequest()" MUST be in every library that will be used by the OCX. Through the above process, the uses block need reference only 1 method (handlerequest) and it applies to every library. This makes utilizing multiple libraries incredibly easy. And the "server.db" handles all the references; even though your site is "live" you can revise server.db and update your site on the fly. Same applies to libraries being used (the Paradox form with OCX has an "unload helper libraries" button for this specific purpose; with it the openlibrary() method is forced to reopen libraries, which causes code changes to take effect "live").

Next, of course, you have to have a library with the HandleRequest() method defined. But first, the in the library's "Open" section, there is a declaration for a dynarray[] String. This dynarray[] accepts a split of the library's path on disk, and attempts to open a tcursor "tctemplate" (defined in the library's "var" section so it is available to all methods within the library) on a named .db file (in the example this is "hercules.db") that you use to store templates. If the tcursor can't be open, you get an error. In practice, you could eliminate this portion if you don't use templates of HTML; in reality you will probably rely heavily on templates. Templates, as utilized in the examples, are stored HTML that you can use over and over. For instance, I use these templates to store a common "look & feel" for the headers of various pages. You can also store portions of pages (such as a disclaimer that can be used specifically as needed), or dropdown lists that are common to several pages on your site. While the OCX also has a tab that allows "header" and "footer" pages that it automatically adds to every page it pushes to the user, I don't necessarily want the top and bottom of every page to be exactly the same. This is where templates allow more flexibility.

Anyway, with the tcursor defined at form level, and opened when the library opens, a defined method (fetchtemplate() in the example) can be used with the various methods in the library to retrieve a specific template. The hercules.db (stored templates) has 2 fields
1. Template. A primary key field with the name of the template
2. HTML. A memo field that contains the HTML that makes up the template.

In the "const" section of the library, there are declarations for "1" and "2". These represent "field #1" and "field #2" in the hurcules.db table. Fetchtemplate() then uses these constants to look for the named template in field 1, and sends back the content (memo field) of field #2 if it finds a record with matching "template" field. Thus, a declaration of the fetchtemplate() method might be retvar=tctemplate.fetchtemplate("tony"). This would do a qlocate() and return the HTML field contents, storing them in retvar (I use retvar as a standard variable declaration in most methods - "ret"urn "var"iable from the old Paradox DOS days).

Now, the real real meat of how a request is passed to, and the response passed back from, Paradox:

The HandleRequest() method is the start of EVERY call to a library. Its declaration is:
method handleRequest(strHandler String, var Request OleAuto, var Response OleAuto) Logical

strHandler contains the information from Server.db's HANDLER field, passed from the OnPostRequest() method within the OCX. I have no idea why the "Request OleAuto" and "Response OleAuto" are part of this declaration; I have always guessed that they create handles back to the OCX, and therefore to the Internet. I do know that it works. (Perhaps someone out there could shed some light on this.)

Within the HandleRequest(), I use (and so does the example) a switch.....endswitch construct to determine which method within the library should _actually_ handle the request.

Using the original "getname" from the Internet forms "action" statement, and assuming that the "handler" field in "server.db" matched with this, HandleRequest() might contain the following:
switch
  case strHandler="getname" : return getname(request,response)
  otherwise : return notfound(request,response)
endswitch
; notfound() is a custom method with a message I wish to display when I don't have any other method defined to handle a request

What this apparently does, using request, is create the link from all data available from the Internet form to the Paradox method. All other data (browser version, IP address, etc.) normally available about the browser/machine is also available to the Paradox method defined here (getname).

This is where lesson #1 comes in. Remember
method getname(var Request OleAuto, var Response OleAuto) logical
var
  namvar string
endvar
namvar=request.getfield("fullname")
Yep, HandleRequest() has activated this method within the library. getname now has access to the data being sent by the browser making this request - the form data, as well as a slew of information about the browser and machine making the request.

As in example #1, everything done within getname() is plain OPAL, except the request.getfield() and response.resultstring="" statements. (There are others, but I don't want to cloud the issue any more than necessary.)

Once you process the incoming data from the form (in this case, the data from the "fullname" field), and take any other actions you wish, the information you wish to go back to the user is sent using the "response" OleAuto function (?).
response.resultstring="whatever you want to send back to the Internet user goes in here"
return true
endmethod
*****************

I hope this "flow" really did flow. It may be an oversimplification to some of you, and it may have confused some. I realize that I got off-track with the fetchtemplate() stuff, but this is pretty important for allowing flexibility and reuse of HTML code. Also, while the other methods in the example library can be dumped, handlerequest() and fetchtemplate() should not, in my opinion. Handlerequest() is absolutely required (although you could rename this to anything, as long as all references in the OCX were changed), and fetchtemplate() is just too darned useful.

Please try to keep in mind that I didn't create any of the processes described in these "lessons". Paradox came standard with every bit of it.

Whoever figured this all out gave us a pretty darned flexible system for creating database-driven web sites. They just forgot the roadmap.

Again, please speak up if you have any questions, comments, or a different way to apply this stuff. There may well be a lot of better ways to put the stuff Corel gave us to better use. _ALL_ ideas welcome. I am more than willing to learn to make this stuff work better.


Lesson 4


Discussion of this article


 Feedback |  Paradox Day |  Who Uses Paradox |  I Use Paradox |  Downloads 


 The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation.
 Paradox is a registered trademark of Corel Corporation.


 Modified: 15 May 2003
 Terms of Use / Legal Disclaimer


 Copyright © 2001- 2003 Paradox Community. All rights reserved. 
 Company and product names are trademarks or registered trademarks of their respective companies. 
 Authors hold the copyrights to their own works. Please contact the author of any article for details.