Scott Auge
Third Edition for
Webspeed 2.1
Comments: sauge@amduus.com
http://www.amduus.com
Introduction:
This book is written for working programmers. Since these people are busy, and I suspect they are like myself – very little time and lots to do, the book will be written with that in mind. So to keep the content down to under 100 pages, the following is assumed of the reader a familairity of HTML and Javascript (or VBScript).
The book will focus on stateless programming for Webspeed. This is the most inexpensive means of programming regarding licensing issues, and the most typical for web based programming. This volumn will also be interested in setting the basic elements of Webspeed needed to get rolling. Volumn II will work on state-based programming with Webspeed.
Readers who are familiar with HTML 3.2+ and Javascript will benefit quite well. If you do not understand HTML and Javascript, you had better go get a book on that NOW! Webspeed pretty much does away with all the Progress 4GL statements to format screen layout. In fact, the statements DISPLAY, MESSAGE, and PUT will be used infrequently, and the UPDATE, SET, and PROMPT-FOR will never be used for screen input[1].
The Progress 4GL statements most used will be flow control (REPEAT, IF, RUN, PROCEDURE, etc), value manipulation (DEF VAR, DEF BUFFER, ASSIGN, etc), and Database manipulation (FIND, FOR EACH, SELECT, etc).
Some new functions are made available to handle input from the web. These have names such as GET-VALUE(), GET-FIELD(), and GET-COOKIE(). These functions will be explained later on the book.
The book does not explain HTML or Javascript, as there are other books that do that.
Almost all the activity that a user would be doing on the browser, whether filling in blanks for a form, or dragging and dropping entities with Netscape 4.0, will need to be done with javascript and HTML. Granted the programmer can get by on HTML only, but javascript is becoming a major influence to the thin-client paradigm.
Programmers who use Webspeed will probably also need to become familiar with MS Windows Operating Systems and UNIX Operating Systems. I will tell the reader right now I am a UNIX guy, but most people in the world are on MS Windows machines, so the browsers available on MS Windows that the application will support will need to be tested and that requires a familiarity with that operating system. In addition, it seems the best HTML editors are for the MS OS’s other than SGI’s Cosmo application. The hard-core transactions and web servers will likely be on a UNIX machine, as Windows NT has been showing some growing pains[2]. Hence the application programmer will need to be familiar with how UNIX works to gain the most benefit.
The book will cover the components of the Webspeed system. It will not explain in detail how to set up or administer webspeed, as that belongs to Progress. But I will include somethings so that I wished were in the manuals. An overview is included because Webspeed is a new programming paradigm for most Progress programmers.
Special thanks go to Mark Rigney and Mike Emmons for reviewing the manuscript for a sanity check.
About the author:
Scott Auge works for Auge, Emmons, & Ziola, Inc. He lives in Flint, Michigan, but is usually in some part of the country working on a contract for service and manufacturing oriented information systems to increase strategic and competitive standing for companies. It is best to reach him via sauge@aezinc.com .
Why use Webspeed?
Webspeed is more efficient in terms of computer resources. A browser program often requires much fewer resources in terms of memory and CPU speed than an executable client application. This can give hardware a longer life time provided the browser is the only application being handled on the machine.
Since the webspeed agents are actually progress clients, they can be better utilized than shared memory clients and networked clients on the same machine. Since multiple users can ask the client to do something, the memory and cpu space used by the client is better utilized. No more sucking up memory while a logged in user is drinking coffee doing nothing on the machine. As soon as a client is finished responding to a user’s browser, it can be asked by another user to do something – far more efficient regarding licenses and machine utilization[3].
Having the source code centralized on the transaction server machines means there is only one or two places that need source code modifications and updates. For user bases of 100’s and 1000’s, this can reduce program updates drastically!
Webspeed can be used on Progress, Oracle, Sybase, as well as Informix databases. This allows the webspeed application to interface with many legacy systems with a new WWW interface. The 4GL can be used in place of SQL to increase programmer productivity and to simplify the programming language used (though there will be times when SQL will still remain a requirement.) Since Webspeed is a transaction server linked to a web interface, web applications can be designed that transparently use the legacy data in existing DBs as well as create new data in the existing DBs without the user’s even being aware of it. With this, web applications may be able to overtake the functionallity of multiple applications into one unified interface accessable from a centralized location. In short, a web browser could be started up and procede to manipulate the data in multiple databases of multiple systems within the company all from one point in the user’s mind – no more click this icon on the desktop to reach order entry and that icon on the MS Office toolbar to reach the manufacturing system. One can even have one point of login – ya in, ya in. All systems can become one with the web interface, and yet users can still be delineated based on security from reaching different sections of the company.
Webspeed uses HTML and Javascript to handle user activities and 4GL to handle database transactions. Using HTML one can design a more interesting screen for the user to work with. In addition, HTML can transparently transfer the user from one machine to another machine without needing to start another program interface or “window” – though one still has the ability to do so if desired. HTML can be quickly thrown together by the programmers for prototyping to the users. HTML is a powerful means of describing screens.
Javascript will allow the programmers to have actions take place on the client machine. Though not as powerful as a data manipulation language, it can be used to turn fields on and off in the screen as data is entered into fields that effect the user’s ability to populate other fields in the same screen. Also it can be used to verify that a field in the screen has actually been populated when it needs to be populated. Computation can happen on the screen also as the user interacts with the browser before the browser interacts with the webserver.
One bad point on webspeed is that it is network intensive. If the network is overloaded or badly configured (routing or has 1 or more choke points) then the users may see a delayed response from the machine.
in a Webspeed Application
Introduction:
Below is a diagram of the components in a Webspeed application. This is simplified, and will be exponded on later in terms important to a programmer.
A description of the workings:
The user of the webspeed application uses a program known as a WWW Browser, or a WWW client. There are three main clients in use today: Netscape Navigator, Microsoft Internet Explorer and NCSA Mosaic. The browser is a thin-net client that performs rendering of HTML[4] into a human readable interface. The browser also provides rudimentary IO such as movement of the cursor, mouse clicking, and text entry. The Netscape and Microsoft browsers also understand two scripting languages called Javascript and VBScript.
The browser makes contact with the webserver. A webserver is a third party program (usually Netscape’s Enterprise WebServer, Microsoft’s IIS, or the internet’s Apache server.) It is a program that handles client requests for web pages.
In order for a Webspeed to function, the webserver will need a gateway feature. A gateway feature allows the webserver to execute programs that can create web pages on the fly. This is how data can be entered into a web page, or content relevent to the users interest can be made programmatically.
Most webservers handle the CGI gateway, but the Netscape servers can have special coding made available to the server thru the NSAPI as can the Microsoft servers can have special coding made available to the server thru ISAPI. It is thru this gateway a Progress component called a messenger is added to the web server to begin the ability of the web server to execute Progress programs (which of course can access the Progress DB, or any of the other major DB vendors[5] Progress supports.)
The messenger contacts a process called a broker (also a Progress component) who determines an available agent process (a Progress supplied component), and passes control to that agent.
The agent then executes a Progress .r file, allowing it to interact with the database, and generate the HTML that will be returned to the web browser thru the webserver. One can think of the agent as the progress client in the usual Progress paradigm, as in fact, it performs the same function as the client in terms of executing code and preparing output for the browser to use to render the screen.
Since the agents usually are using a different shared memory version than the database servers, a network connection inside the machine must be established. If the agents are to be communicating with a database on another machine, a network based connection will need to be made anyhow.
In order for the agents to execute any code that uses a database, they must talk to a database server process or a data server process (both supplied by Progress).
Quite often the processes are spread across multiple machines. This way inexpensive computing hardware can be used instead of one huge honkin machine. In general, the browser will execute on the users computer, though if the users machine is an X terminal, the browser may be executing on a different computer and the GUI interface is being sent to the X terminal. The webserver and the messenger processes must always be executing on the same machine. The broker and the agents also usually are executing on the same machine, though it may be different from all the other machines. The database server process can also be executing on it’s own machine. So in a very large system, there could be four or more computers involved. In a smaller system, there could be two computers involved. In general, the system will have three computers involved: Browser computer, web server/messenger/broker/agent computer and a database computer. Larger systems can handle more users by spreading the processes needed to handle the users across more hardware.
Following the activities thru the system (UNIX):
First the browser uses a DNS server to determine the IP address of the machine named in the URL to be contacted[6].
Next the port specified[7] is tickled and the webserver answers the connection. The webserver then parses the URL sent to it and decides if it needs to run a program in the CGI directory[8] or if it can serve a page directly from a document directory[9].
Should the URL point to a document directory, the server returns the static HTML stored in the file specified.
The more interesting part is when the URL means to execute a program on the web server and that program is the messenger component of the Webspeed Transaction server.
That program in the CGI world is a script that sets the environmental varibles WEBSPEEDCNF and DLC that is used by $DLC/cgiip to begin communication with the transaction server portion.
A connection is made between the messenger and an agent handling the broker service that the messenger is asking to be handled. The agent is passed the program name to run[10] and performs the run according to the default directory or PROPATH it is was instructed to use in startup.
The agent then usually interacts with the database thru a network connection.
Below is a diagram showing the steps involved diagramatically without the DNS entries as the /etc/hosts or \windows\hosts files could be used on an intranet based application.
How to set up a messenger on a different machine than the transaction server (UNIX):
To help seperate the pain of computation, the implementor may want to use a machine to act as the web server and another to handle database transactions. Seperating the processes to multiple machines can reduce the size of the machines needed, and the implementor may even be able to use machines in existing inventory. The more powerful machine should be made the transaction server, and the less powerful machine can be made the web server.
1. The messenger portion of the Webspeed transaction server will need to be installed on the webserver, and the webserver will need to be made aware of the messenger thru the webserver's configuration file.
2. Set up the webserver to have a scripts directory
3. Place the wbsp_cgi.sh file into this directory
4. Rename it to something easier to remember in terms of the application.
5. Edit this file, you will want to hardcode the DLC environmental varible environmental varible so unneeded processing is required to find the webspeed.cnf file that will handle this application and messager. (There is a small do loop in the script that searchs a set of directories, this means disk accesses for the messenger on every hit which can slow things down a tad bit – if your a purist.)
6. If the webspeed.cnf file is not in the DLC directory, you will want to hardcode the WEBSPEEDCNF environmental varible to point to the correct webspeed.cnf file[11].
7. Edit the webspeed.cnf file pointed to by the environmental varible WEBSPEEDCNF in the messenger script file in the webserver's CGI directory. The entries of most interest will be:
PortNum 2001 # Service TCP/IP listening port
Location 100 # 200=Local, 100=Remote
AgentMinPort 2002 # Minimum port number for Agents
AgentMaxPort 2202 # Maximum port number for Agents
HostName remotemachine # Name of local or remote hostname
A different webspeed.cnf file, pointed to be the wtb script to start up the broker and agents will have the same information, except for the Location parameter, which will be 200 to state the webspeed.cnf file refers to a local broker and agent process(s).
PortNum 2001 # Service TCP/IP listening port
Location 200 # 200=Local, 100=Remote
AgentMinPort 2002 # Minimum port number for Agents
AgentMaxPort 2202 # Maximum port number for Agents
HostName remotemachine # Name of local or remote hostname
The port numbers for the webspeed broker and agents should be the same for the given application environment.
Those seven steps pretty much explain how to get two machines talking to each other in regards to messenger-broker-agent communications.
How to set up the transaction server on a machine different from the database server machine:
The following describes the entries and processes related to getting agents and brokers on one machine to talk to a database server on another machine.
Files and processes involved in getting agents-broker-database server communications....
The broker and agent processes are spawned from the wtb script found in the webspeed DLC/bin directory. These scripts make reference to a webspeed.cnf file that will include the connection parameters for connection to the remote database.
DefaultDirectory /appl/rel1 # Broker & Agents working directory
AgentParams -p web/objects/web-disp.p -cpstream iso8859-1 -db d1prod -ld dispatch -H aupaix1.fld.rolm.com -S d1prodpost -N TCP -db rolmdbd1 -ld rolmdbd1 -H aupaix1.fld.rolm.com -S rolmdbd1post -N TCP -db websecurity -ld websecurity -H scraix11 -S websec –N TCP -T /tmp
As can be seen, the connection parameters are based on -db, -ld, -H, -S, and -N parameters normal to Progress clients. These parameters mean the following:
-db Physical name of the database
-ld Logical name of the database
-H Host name with the database to be connected to
-S Service used by the network connection - defined in /etc/services
-N Type of network connection (TCP is usual value)
A .pf file can also be used instead of specifying the database connection parameters.
How to set up multiple environments on the same machine:
This is how I prefer to do things, but there is more information within the Webspeed Administration manual. I find the following steps allow you to construct URLS that are a bit more easier to remember than including the WSbroker=blah in the text.
1. You will want a cgiip script in the cgi directory for each environment. Give each script a name that describes the environment. Within the script, there will be a call to $DLC/cgiip –i [brokername]. Yep, you guessed it, put the broker name after the –i in the script.
In the webspeed.cnf file used:
2. You will want to set up multiple broker settings, give each broker a name that describes the environment. This can be helpful for remembering what application the broker is for, and whether the application environment is develop, test, or production. Examples could be cdrdev, cdrtst and cdrprod.
3. Set up different ports for each set of brokers, agents of different brokers can share the same ports. You definately do not want to mix up the ports for the various brokers in the system.
4. Set up the parameters in the webspeed.cnf file as mentioned above or from the explainations in the Progress Webspeed Administration book.
Basic Components in a Webspeed Development Environment
Introduction:
Developing web based applications requires many components and third party tools. Below is a diagram attempting to describe the relationships between the major source files and the tools. Some of the source files are not needed depending on what method of development used.
The programmer or screen designer will layout the screen in an HTML editor(1). It is always best to have the screen laid out before adding the javascripting, 4GL, or Java added.
Then an HTML file(2) is created from the editor.
The Progress programmer then uses Progress’ Workshop(3) tool to prepare a webobject that will prepare the page with Progress’ 4GL language.
The next step depends on if the programmer will use the E4GL method of development or the HTML-Mapped method of development. The HTML-Mapping method requires an offset file(4) and a .w file(5). The E4GL can have a .w file(5) if needed for deployment on another machine, but does not need the offset file(4). The Workshop product can automatically create these files – but note that some of them will merely be skeletal renderings of the file (basically what it takes to get data in and out of the screen – but no processing.
The Workshop tool is then used to create a Progress .r file(6).
The Progress Transaction Server(7) tool is used to execute the .r file against a given database (should the code state so under the conditions) and then to return the output of the .r file to the browser(8).
The First Step: Developing the Web Page
Introduction:
When coding is ready to begin on a Webspeed application, the fastest way to prepare the webpage is thru the use of an HTML editor. There are many editors available for both UNIX and MS OS’s. The best type of tool to use is one that allows drag and drop of various web page entities, such as buttons, fields, and images.
Developing the web pages also allows the users to actual see a mock up of the application as it is being developed. The users should be made aware that at times the application will need much work to be done under the hood even though it may look to be almost finished because it is appearing in a browser. A good explaination might be that it is drawn out like on electronic paper instead of on solid paper, and has as much functionallity as a screen drawn on paper.
Some tools to use in the MS Environment:
Hotmetal Pro has an editor that I like. Just about the only thing I do not like about it is being unable to re-size images by dragging an achor point. If you wish the browser to show a certain size, ya will need to work the numbers your self.
Another potential tool to use is MS Front Page. This tool is good for developing the intial page, but be aware that it does add some additional comments and tags to communicate with other Microsoft tools. I fear that this tool is becoming proprietary to Microsoft systems and is slowly evolving away from being useful in other environments.
A third canidate is the HTML editor available from Netscape called Composer. This tool is a bit weak in terms of capability. It is good for general layout, but for more complex tags, such as forms and the like, it requires the user to enter the actual HTML.
Finally a text editor can be used for people who are hard core HTML authors and have the skills to create HTML pages on the fly without help from a tool.
Some tools in the UNIX Environment:
Often the UNIX vendor will have an HTML editor available for it’s machine, or will be aware of an editor(s) that will function on the machine.
SGI has the Cosmo suite, that allows the user to develop web pages. This is a very nice editor with drag and drop and is user friendly.
Netscape provides it’s Composer tool in many UNIX environments, including Sun, Linux, UNIXWare, and Open Desktop, HP-UX among others….
Usually HTML editors are available at various internet sites, as one editor on one version of UNIX is made available on other versions as well. Linux has many HTML editors available for it for those who prefer a UNIX work station environment.
Some ways to documenting and analyzing web pages:
As you can consider, developing a web based system will require some changes in what information you want to document and how to document it. Below is an example of some of the notation[12] that could be used to express your ideas about how screens are interconnected and what data is passed between them.
There are three main types of symbols: screens, data arrows, and flow control arrows. Screens would represent the screens that you wish to have a web object generate. It could be the same web object generating different screens, could be a single web object generating all the screens, though I would think this would be a nightmare.
The screens are named or denoted in some way for reference. They are represented by boxes with a shadow underneath.
Flow between screens by activities of the user is denoted with a special arrow. This helps identify the activities the user could do to move from screen to screen. Examples would be a button with an onclick event opening a window and page, or more simply a submit button. It could be a hyperlink that would be available to the user, or some types of events that could be programmed in the client’s (read that – browser’s) scripting language.
Data is passed between the screens, and this tends to be important to us programmers who need to understand what is coming in and what is coming out. Data can be in different forms when it comes out of a web page, the two most popular being in a cookie and a form field of somekind. In the future it may even be coming from a Java applet.
Since the data is coming in different entities and HTTP methods, that data will have differing properties. For example, it is much easier to reload()[13] a page activated by a GET than a POST. The data could be encapsulated in a form field, or sent via a cookie. The use of a symbol to denote the encapsulation method of the data can help sort out how the data is being transferred around in the system of pages. Some denotations I use are ( C ) for cookie, (H) for a hidden field, and a visible form field with (F). Next to the symbol for how the data is being transferred, I place the name referencing the data in the HTML.
Documenting the Progress 4GL can be a little tricky also, but will probably be more familiar to the users. A separate diagram can be set up to document calls into various routines with the 4GL:
This diagram shows a screen with calls into multiple modules of Progress 4GL. Two modules are Progress internal procedures contained within an include file that are given certain arguments to work with. Two modules are external procedures stored in their respective files who are also given values to be worked with.
Between these two diagrams, a lot of information can be provided about the interaction of pages and of Progress modules that are generating the pages. It may be difficult to separate the two at first, and in a way they are related. But I usually try to differentiate data passed in Progress syntax at one level, and data passed in HTTP syntax at another level.
Integrating these diagrams into programming documentation seperated out by feature or function can help explain what is happening in the system, and potentially what is can be optimized. In addition, if customizations are occuring in the system, whether in the form of maintenance or in feature modification, the consequence of changes can be better determined.
A sample outline for a specification document is given below:
Business Scenerio
- Describe what the program or feature is attempting to do within the organization
- Who the players are
- What process the person using the application will be in
- Where they will be getting data to place into the screen
- Who they will be giving their data to when they are finished manipulating it
User Interaction
- Give a screen layout
- If buttons on the screen, then say what they are going to do
- Screen field validations
System Interaction
- The not so obvious stuff such as database triggers involved
- Program Names that will be created or re-used
- What is going to happen on all the tables involved within the system
- What screen field lands in what tables in what conditions
- What screens are interacted with and data passed between
Database Tables
- Which ones are used
- Which ones are created
- Fields, Indexes, etc.
Note that you documenting system should be able to handle keyword searching or somekind of indexing for easy referening.
Could be MS WORD with keywords for the document. Then set up keywords for questions you will want to ask:
- Tables used by other programs (to make sure something else doesn't get broken)
- Other Validations for the data
- Programs used (for feature interaction)
General New Features in
Progress 4GL for Webspeed
Introduction:
As can probably be guessed now, the usual 4GL statements associated with interacting with the user are rarely relevent[14]. In the web paradigm, a browser takes the place of the GUI front end for an application. The following chapter explains the general programming functions the programmer will need to be aware of to create web objects executing near or at the back-end of the process chain to implement a webspeed application.
If the HTML is used to gain and store values for values, how do I get them from the HTML into the 4GL?
We know that HTML provides the information to the browser on how to render the pages: where to put words, diagrams, and input fields. Some examples of instructions to a browser are:
<input type=”button” name=”userbutton” value=”OK”>
will create a button on the page, label it with OK and name the button (for internal reference from javascript and the 4GL as we will see in a bit) as userbutton. Note the entire instruction in HTML, no 4GL has been used yet. In essence, we have created an HTML varible, and named it userbutton. We have instructed the browser to render values of the varible on a button on the web page.
Another more interesting HTML “widget” would be the text field. An example coding for a text field is given below:
<input type=”text” name=”firstname” value=”” width=”30”>
This would create a 30 character wide (but usually able to hold more than thirty characters – think of it as a fill-in widget in the 4GL) entry space for the user to type some string of characters into. Here we have created a varible named firstname and issued instructions to the browser to render it as a textual field.
So then, how do we get the value from the HTML varibles into the 4GL varibles? By the use of a special function made available in the Workshop product. It is called:
GET-VALUE()
This function will return a string representing the entry performed by the user on a form on the browser. It’s argument is the HTML varible name.
An example would be:
<!DOCTYPE HTML PUBLIC "-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//EN"
"hmpro4.dtd">
<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<P>First Name: </P>
<FORM><INPUT TYPE="text" NAME="firstname" WIDTH="20">
<INPUT TYPE="submit" VALUE=" OK "></FORM>
</BODY>
</HTML>
which would be the HTML used to render a screen appearing as:
As can be seen, there is one text box on the screen that the user can use to input a name and one button to “submit” the screen.
To receive the data from the browser (which is controlling the user interaction with the program, NOT your 4GL as in previous progress programming), one uses the following:
DEF VAR FirstName AS CHARACTER NO-UNDO.
ASSIGN FirstName = GET-VALUE(“firstname”).
These two 4GL statements will define a varible to move the contents of the HTML varible firstname into the 4GL varible FirstName. How to mix the 4GL and the HTML together depends on which development method is used: HTML-Mapping, or E4GL scripting.
There are additional functions available to nab the values of types of widgets in an HTML page, see your Webspeed Programmer’s guide for more information on this.
In addition to what is seen on the screen, there is a special means of storing data on the browser called a cookie. A cookie can be stored on a browser during a given unit of time, or as long as the browser is open and then destroyed. Cookies are an excellent means of storing information about who is logged on to the application for application security. More on that follows.
The means to get a cookie set on the browser is by using the SET-COOKIE() function[15].
To read a cookie one uses the GET-COOKIE() function.
Note that all values passed between the HTML and the 4GL are in the data type character. If integers are passed in from the HTML, they will come into the Progress code as CHARACTER. Same for dates, logicals, and other data types.
An example of how to handle potential trouble is via:
DEF VAR a AS INTEGER NO-UNDO.
{error.i}
ASSIGN a = INTEGER (GET-VALUE (“thenumber”)) NO-ERROR.
IF SESSION:ERROR THEN RUN handletheerror({&BADINTEGER}).
Developing with the E4GL method
Introduction:
The E4GL method is the fastest method to learn if the programmer is already familiar with web based programming. It involves using special HTML markers to note where the 4GL code is. It is a convenient way to combine HTML, Javascript, VBScript, and 4GL code together into one source file, that way all the peices to the puzzle are made available immediately to the programmer.
The term E4GL stands for Embedded 4th Generation Language.
About the Method:
E4GL is directly embedded in a program that appears more like a static HTML page, than a program. But as we will see later, the page is manipulated by a tool called Workshop available from Progress to convert the page into a progress program.
Embedding is done via two ways, one is a special comment tag as follows:
<!—WSS
Progress 4GL code
à
and the other tag more familiar to HTML authors and Javascript/VBScript programmers:
<script language=”speedscript”>
Progress 4GL code
</script>
In addition, the accent grave or back tic (`) as it is known is used in special cases within the HTML or Javascript making up a webpage. This tic is used to output values of a varible, or any 4GL expression that returns a value. For example, the following code outputs a textbox with a default value derived from the varible textdefault:
… Some other HTML
<!—WSS
DEF VAR textdefault AS CHARACTER NO-UNDO.
à
<form>
<input type=”text” name=”t1” value=”`textdefault`”>
</form>
One can see in the browser a text box whose value is set to the value of textdefault in the Progress 4GL language.
Now the question is probably coming up on how do we compile this HTML file into a Progress executable. The WebSpeed Workshop will be required to go into this next step, unless a third party converter is used[16].
What workshop does in short is create a STREAM WebStream that is for output. It then puts PUT STREAM WebStream[17] in front of all the HTML statements quoting the statements with single quotes in the HTML file. If this converter encounters the special tags, it stops putting the PUT STREAM WebStream statement in front of the lines and leaves them alone creating a pure Progress source file.
So the line:
<input type=”text” name=”t1” value=”`textdefault`”>
will be turned by the converter into:
&{OUT} ‘<input type=”text” name=”t1” value=”’ /** Tag ` **/ textdefault /** Tag ` **/ ‘”>’.
Which when the Preprocessor is finished with it comes out effectively as:
PUT STREAM WebStream ‘<input type=”text” name=”t1” value=”’ textdefault ‘”>’.
So as one can see, the WebSpeed Workshop, when creating .w’s or .r’s from HTML pages creates PUT statements that will output HTML (and javascript or VBScript) to stdout (in UNIX terms) that is passed directly by all the components between the agent and the browser.
Those parts delimited by the special tags are left alone, because they are already Progress 4GL statements. Placement of the Progress 4GL statements in the E4GL style is very important in the HTML file. Because the execution of the program goes top down with it’s processing the programmer will always want their HTML PUT statements to be at the end. If the programmer has their HTML at the top, and processing of varibles and the like at the bottom, the HTML will not have the correct values because it was output before the values where computed.
In general, the following outline is best for E4GL programs:
1. Varible Definitions
2. Populate varibles
3. Perform record processing
4. HTML code
5. Internal Procedures
Below is a simple program that will create a record using the outline as specified above:
<!DOCTYPE HTML PUBLIC "-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//EN"
"hmpro4.dtd">
<!--WSS
DEF VAR CustomerName AS CHARACTER NO-UNDO.
DEF VAR CustomerNumber AS INTEGER NO-UNDO.
ASSIGN CustomerName = GET-VALUE ("custname")
CustomerNumber = IF CustomerName <> "" THEN NEXT-VALUE (CustomerNumber)
ELSE 0.
IF CustomerName <> "" THEN DO:
CREATE Customer.
ASSIGN
Customer.Name = CustomerName
Customer.Number = CustomerNumber.
END. /* CustomerName populated */
-->
<html>
<body>
<form method="POST">
Customer Name: <input type="text" name="custname" value="`CustomerName`"> <br>
Customer Num : <input type="text" name="custnum" value="`CustomerNumber`"> <br>
<center>
<input type="submit" name="Submit" value="OK">
</center>
</form>
</body>
</html>
Documenting it under the above mentioned diagrammic method would appear as:
And viewing the screen would appear as:
In general, the programmer will always want the HTML to be the last thing in the main program procedure. The entirety of the HTML can be encapsulated into an internal procedure that is called from the program. This can allow better control as to when the HTML is going to be output. In fact, the same program could output an entirely different page based on processing by calling one internal procedure with the HTML in it versus another internal procedure with HTML in it.
So, how does this program work?
Here, an understanding of how the Browser and the Web Server interact comes into play. Initally the browser will request thru an URL that this program be executed. On this initial connection, the REQUEST_METHOD is GET.
1. The program will receive no input, causing the GET-VALUE() functions to return nothing.
2. Some processing shows up where it is determined if any input was sent or not and the creation of a record is based upon this decision.
3. After that, the results are output to the browser, which is pretty much the empty form.
4. The user will enter some information and press the OK button causing a submit to occur using the POST method. Since the ACTION in the form is not defined, the browser will call for the same URL as used in the GET and pass information along to the program.
5. This time, the GET-VALUE()s in the program will receive some data firing the IF and a record will be created, where the output will refect that because of the existance of a customer number.
It must be remembered that the program is executed twice! Once when it is first entered and second when the OK button is pressed. Based on the values available to the program from the GET-VALUE() is what really drives the activity of the program. It is stateless and thereby started up and shut down with each request from the browser. One can think of it as starting up a client session and getting some output on the screen. Then kill the connection. At this point the browser takes over allowing editing of the fields. The user presses OK, and the browser recognizing the submit will again establish a client session to the database and execute a program[18].
So a continous connection is not in the plan for this particular program.
Coding for HTML elements:
Text Box
Text boxes are among the simplist to handle. If the user wishes to default a value thru Progress 4GL, then the programmer would use the accent graves to delimit the varible in 4GL from the HTML.
<input type=”text” name=”thename” value=”thevalue” width=”20”>
Button
Buttons dont really do anything unless they are a type of submit or reset. Else, to get the button to be functional, javascript or vbscript will need to be used.
<input type=”button” name=”thename” value=”thevalue”>
Submit
These buttons do the brunt of the work when activities on the server side need to be performed. This can be the creation, modification, and deletion of records in the database, or for changing “state” information used within the program.
<input type=”submit” name=”thename” value=”thevalue” >
Radio
Radio widgets are good for “this or this or this but only one of em buddy” situations. Only one out of a group can be checked at a time.
<INPUT TYPE="RADIO" NAME="Radio1" VALUE="Value1" CHECKED="CHECKED">
<INPUT TYPE="RADIO" NAME="Radio1" VALUE="Value2">
By having the same name, the buttons become dependent on each other. This way when the user checks on one, the other will become unchecked. By using the CHECKED parameter within the tag, the programmer can specify a default value. To determine which widget was checked, do a GET-VALUE(“Radio1”). A return of Value1 will mean that the first item was chosen by the user, a return of Value2 means the user overrode the default from the first radio button the the second radio button.
Checkbox
Check boxes are like radio buttons, but have a different look about them. Mostly used in those areas where interdependence between check boxes are not required.
<input type=”checkbox” name=”thename” value=”thevalue”>
Text Area
The textarea widget allows the programmer the ability to give the user someplace that acts as a small editor.
<input type=”text” name=”thename” width=”20”>defaulted text</textarea>
The above were very small descriptions on the main items a programmer would be using to construct a web application. More information about other input mechinisms and additional properties of the ones above can be referenced from any HTML reference book.
Keeping business logic out of the HTML:
This is becoming a very important issue for companies, as we are seeing tools for user interfaces propagate in the market – there are many many more choices.
In general, the programmers should make an API for nearly every business rule in the company. Really there should be no CREATEs, DELETEs, or database record ASSIGNs in the E4GL portion of the code. The user interface portion of the application should use RUN’s to perform the work of business logic. Business logic APIs will accept only arguments and will not provide any output or input to the screen (this does not mean it cannot provide a list of ROW Ids or Record Ids for the interface to work with however!)
For example, there could be an order entry screen, and on that screen there are entry lines and a few buttons.
We would name all the buttons the same way, and they would all be submit buttons (we need to use submit buttons to interact with the web object on the other side of the webserver)
The following code allows the programmer to know what button was pressed to submit the page into the webserver:
DEF VAR ButtonValue AS CHARACTER NO-UNDO.
ASSIGN ButtonValue = GET-VALUE (“SubmitButton”).
There will be additional code to read in the various values from the form using the GET-VALUE() function:
ASSIGN CustomerNumber = GET-VALUE(“customernumber”)
Item1 = GET-VALUE (“item1”).
A call would be made into the API for the button called Create Order:
/* ID Button Pressed – the event dispatcher*/
CASE ButtonValue:
WHEN “Create” THEN RUN ipButtonCreate.
WHEN “Cancel” THEN RUN ipButtonCancel.
END. /* CASE ButtonValue */
This allows the programmer to become somewhat event oriented, on the event the Create button was pressed, then the ipButtonCreate[19] program will handle that activity of the user. A general feeling of what happens could be done like this:
/* An event handler */
PROCEDURE ipCreateButton:
ASSIGN var1 = GET-VALUE (“var1”)
var2 = GET-VALUE (“var2”).
RUN CreateOrder (INPUT var1, INPUT var2, OUTPUT result).
END. /* PROCEDURE ipCreateButton */
Inside the CreateOrder program would be all the business rules associated with creating an order. If an error occurred because a business rule was broken, then coding would be used to explain to the user what went wrong. For example, there may be a credit hold on the customer, or there may not be inventory available for that product. A result would be passed back from the CreateOrder program and that result would be examined by the event handling code to determine what message, if any, needs to be displayed to the customer.
Coding Architecture for Seperating Business Logic from UI in Webspeed E4GL applications
Note, that GET-VALUE must be used in a program with {e4gl.i} included at the top, else it will not be defined for use. So in these APIs which are .p files, the programmer will not be able to use GET-VALUE because it will not be defined in that program. The recommended way of getting information on an event spawned execution, is to perform this in an internal procedure. The internal procedure would act as the wrapper between the interface and the API.
Author's note: I have stopped developing this chapter of the book because I do not believe in the HTML-Mapped method of development in Webspeed. It is difficult to use, creates larger .r files than the E4GL method, requires the distribution of three files (.r, .off, html) instead of one .r, is slower due to parsing of .html and .off files, more fragile to html changes, and generally requires more development time than the E4GL method of coding.
Introduction:
This second method of development will probably be more familiar to Progress programmers as there is little to no work done on the HTML file.
Using this method requires heavy use of the Workshop product as it creates a lot of code for the programmer getting values into and out of the HTML form.
One of the bad points of this method is that it requires parsing the HTML file nearly everytime the program associated with it is run. In addition, coding a program in E4GL took significantly fewer lines of code to write than in the HTML-Mapped method, resulting in a smaller and assumingly faster .r file. In fact, one test with the exact same functionallity showed that the E4GL program compiled to a 17KB .r while the HTML-Mapped program compiled to a 38KB .r file.
In addition, the HTML and .off files need to be sent along with the .w files. While the .w files can be encrypted, the html and the .off files cannot be encrypted and can be manipulated by the user. Adding a field to the HTML file will cause an error and requires a new offset file and a re-compile of the .w to work properly.
With E4GL, only the .w files need to be sent in encrypted form and compiled to be useable on a customers site.
About the method:
Use a HTML Editor to create the HTML Page.
Use the Workshop to create an offset file.
Use the Workshop to map the fields from the form, to varibles or fields in the CGI Wrapper.
Save the CGI Wrapper file (it will be a .w)
Edit the CGI Wrapper with the business logic.
Components of interest in an HTML-Mapped .w file:
WEB-FILE
This is a preprocessor definition that identifies the HTML file to map to and to use to format the output of the wrapper program.
ENABLED-OBJECTS
This preprocessor definiton identifies fields that will be editable in the browser.
DISPLAYED-OBJECTS
This preprocessor identifies the fields in the web frame that will be displayed, ie, used to replace the fields on the HTML form shown in the browser.
Local Varible Definitions[20]
For fields that do not directly effect a database record, local varible definitions are created. These are the varibles as defined in the HTML-Mapping phase in the Workshop.
Web-Frame Definition
This will act as the screen buffer for those familiar with such an entity. There really is not a screen buffer in the Webspeed world, as the program really is not interacting with the screen. But it is a convenience for those familiar with using a screen buffer for various activities.
RUN web/support/rdoffr.p
This pretty much makes sure the fields in the offset file created via the Workshop match what is in the HTML file.
RUN htm-associate IN THIS PROCEDURE ()
This procedure associates the form fields name, the varible or buffer field, and a handle into the screen buffer defined in the Web-Frame. This where all the values are glued together.
PROCEDURE output-header
This is where the user will set cookies or other information before the browser starts to receive HTML.
PROCEDURE process-web-request
This is the procedure that defines the heart of the business logic in the application. There are two main parts, one part for handling a GET and one part for handling a POST. A GET will usually be the first time the screen is brought up by the user, and so it is useful to place default values into fields that the user may be editing, as well as prepare hidden fields that the user may be using to keep state information.
For a POST REQUEST_METHOD:
RUN dispatch in THIS-PROCEDURE (‘input-fields’:U).
This function will take fields and values from the URL and set them into the Web-Frame as defined in the htm-associate procedure.
RUN dispatch in THIS-PROCEDURE (‘assign-fields’:U).
For those fields that have been manipulated in the form buffer, a movement from the buffer into the database occurs.
RUN dispatch in THIS-PROCEDURE (‘display-fields’:U).
This allows the user to manipulate the form buffer again for values that should be displayed.
RUN dispatch in THIS-PROCEDURE (‘enable-fields’:U).
Running this procedure identifies the fields that should be enabled for user interaction. If you wish some fields to become inactive, Ie, display, but not allow the user to change the value, the programmer should enter a DISABLE statement after a call to this program.
RUN dispatch in THIS-PROCEDURE (‘output-fields’:U).
This is where the screen is rendered to the browser with the values from the form buffer entered into the fields and the fields made interactive or not interactive.
For a GET REQUEST_METHOD:
RUN dispatch in THIS-PROCEDURE (‘display-fields’:U).
See display-fields in the POST REQUEST_METHOD.
RUN dispatch in THIS-PROCEDURE (‘enable-fields’:U).
See enable-fields in the POST REQUEST-METHOD.
RUN dispatch in THIS-PROCEDURE (‘output-fields’:U).
See output-fields in the POST REQUEST-METHOD.
Deploying your webspeed application:
Tips and Tricks in Webspeed
Introduction:
A lot of the tricks achieved are really in the HTML and the Javascript/VBScript used in the application. The 4GL really just manipulates the database in the system.
How to get agents to handle different databases:
You want the webspeed environment to handle different databases. This is done by having a different brokering service.
Looking inside the webspeed configuration file, one
Since I usually use CGI as the interface into the web server, to create access into the given database is by running a different cgiip. Here is what I do, I have two databases: one handles customer orders, and one handles customers support questions.
Copy the wspd_cgi.sh to orders and to support. Inside orders, I would set cgiip –i WSbroker where Wsbroker handles connections to the orders database. Inside support I would set cgiip –I Wsbroker2 where Wsbroker2 handles connections to the support database.
Hence the URL the user would see would read something like:
http://machinename/online/orders/login.html
for the orders submission and lookup, and
http://machinename/online/support/login.html
for the support submissions the customer might have.
Both orders and support would reference the same webspeed.cnf file. Inside the webspeed.cnf file I would set up a set of Messenger/Broker ports for the WSbroker connections to the databases and another different set of Messenger/Broker ports for the WSbroker2 connections.
Starting up the support system would entail:
1) Starting the databases needed by the transaction server
2) Entering wtb –i WSbroker2
Starting up the order system would entail:
1) Starting the databases needed by the transaction server
2) Entering wtb –i WSbroker
To check the status of the systems would use the commands:
wtbman –q –i WSbroker
for the order system and
wtbman –q –i WSbroker2
for the support system.
To shutdown the transaction server for a given system would use the following commands:
wtbman –e –i WSbroker
for the order system and
wtbman –e –i WSbroker2
for the support system.
Laying out the files for webspeed system:
This is generally a UNIX centric layout for applications, but something like it can be done with MS OS’s.
/appl
This is usually the central trunk for the tree that will contain the components of an application. If multiple applications are involved in a system, then a further break down may be desired.
/appl/db
Keeping the database in a close place next the rest of the application in the system can be a much more clean and clear explanation of where to find data for an application. One may want to further subdivide the /appl/db tree into /appl/db/devlp for development versions of the database, /appl/db/prod for the production databases and /appl/db/qa for the qa database.
As can be expected, the implementor will probably want to keep the database on a separate drive than the source code. Most UNIX systems will allow you to mount a hard drive to a directory “in the middle” of the directories of another hard drive, thus looking like the directory is all togetther. This can help in contention and changing hard drives out to bigger drives without needing to reconfigure the scripts and such used to connect and interact with the database.
If you have logical volumns, which can make a couple of drives look like one, I won’t even go further as you should already have an idea of what I am talking about.
/appl/bin
Usually the startup and shutdown scripts are stored here for a given environment. You will need a startup and shutdown script for the db (if the db is on the same machine as the transaction server) as well as a startup and shutdown script for the transaction server portion of webspeed.
If you are managing multiple applications with Webspeed you will probably want separate scripts for each application. Then include those scripts in calls from a superscript if so desired. Be aware that the “super script” that does everything may freeze up because of some un expected event that may not relate to any of the other applications the script is suppose to handle. So keeping the scripts separate allows the administer to get other applications running in case one application causes trouble.
/appl/src
As you may guess, I usually keep the source for the application in this area. It could be encrypted or .r source.
/appl/static
Webspeed applications have a new component to them, and that is the use of icons and graphics within the application that can be directly served by the web server without any intervention of the Webspeed application. I generally make a rule in the webserver’s configuration to map the directory of an url into this directory[21].
Use relative URLs in your application:
Only use relative URLs in application unless one must hyperlink to another machine than what is being used. Using SCRIPT_PATH and other such available varibles may be tempting, but having the machine within a fire wall can cause trouble.
For example, the customer did not want the web server and the messengers to be outside the fire wall. To solve this problem, they used the fire wall software’s ability to translate IP addresses into another IP address to get access to the internal machine. In other words, the machine to the internet looked like machine1.a.com, but the machine thought it’s name was machine.b.com as the internal domain was different from the external connection domain. Of course, the varibles were giving the internal name of the machine, and not what it looked like outside of the firewall – thus the URLs supplied the machine were giving the wrong name and the internet users could not find that machine. Some tricks with DNS and aliasing managed to save time re-programming, but it still was a bit of a hocky way to do things.
Design the pages before entering E4GL coding:
I have found that designing a page up front with Front Page or Hot Metal Pro can help the customer to see what things are going to look like before programming needs to be done. These layouts can be provided to them with sample data in the layout allowing them to explain modifications that need to be done before actual programming begins.
Once programming has begin, you will likely not want to return to the HTML editor as most of them totally trash the formatting of your 4GL coding after you enter it into the file. So having the layout agreed upon before coding can save a lot of time, and explaination.
How to get agents to handle a PROPATH:
The agents may be asked to handle working two application, which are differentiated by the broker service they are providing. In this way, the agents can actually handle two different applications at the same time with different database connection (isnt that rocking!)
To make the agents aware of the different directories of source code can be achieved by two means.
One is to have the default working directory[22] for the set of agents started under one broker service to be set to an application directory, and the other broker service to have a different default working directory.
Another is to make a copy of the wtb command found in the bin directory of the DLC the transaction server was installed under. The wtb command is actually a script describing where to find the executables and webspeed configuration files for starting the transaction server under. By copying these files and adding a notation for PROPATH, all the agents started with that script will be aware of the PROPATH and use them like the client versions of Progress.[23]
Some examples can be:
To start the orders transaction server:
#!/sbin/ksh
# start orders transaction server
PROPATH=$PROPATH:/appl/orders/custom:/appl/orders/src
wtb –i OrderBrkr
and the script to start the agents for the support transaction could be:
#!/sbin/ksh
# start support transaction server
PROPATH=$PROPATH:/appl/support/custom:/appl/support/src
wtb –i SupportBrkr
Use surrogate keys:
Surrogate keys is a database architecture technique that can help reduce the number of record changes that occur when the value of a relational field is changed. In addition, it can help reduce table size in databases for a common relation thru-out the database table architecture by the elimination of a column.
For example the table:
Header:
Code
Description
Is related to the table Detail via Code:
Detail:
Code
IsGood
such that a change on the field Code of a record in Header requires a change on the field Code of a record in Detail.
Example Data for Header Table:
Code |
Description |
a |
A Description |
b |
B Description |
c |
C Description |
d |
D Description |
Code |
IsGood |
a |
1 |
a |
2 |
a |
1 |
a |
3 |
a |
4 |
b |
1 |
c |
1 |
We can see from this example, that if the Header record whose code is changed from “a” into say “t”, then there are five additional record changes that need to happen in the Detail table, for a total of 6 database changes needed.
If Detail is hundreds of records all relating to a Header record via code, then hundrends of record changes need to be propagated thru the database (in the Detail table and any others that may use Code from Header as relational information). This can definately effect the speed at which an agent may respond to a transaction, and can cause additional work on the database manager side that propagates into disk writes and reads and we know how those can slow things down.
So the way to reduce the number of changes is by implementing something called a surrogate key. By adding an integer field into the tables:
Header
Code
HeaderSurrogate
Description
Detail
HeaderSurrogate
IsGood
The relation becomes based on the Surrogate key. The data for the surrogate can come from a database sequence named for that particular relation, such as “headersurrkey.” The database then looks like this:
Example Data for Header Table:
Code |
Description |
HeaderSurrogate |
a |
A Description |
1 |
b |
B Description |
2 |
c |
C Description |
3 |
d |
D Description |
4 |
HeaderSurrogate |
IsGood |
1 |
1 |
1 |
2 |
1 |
1 |
1 |
3 |
1 |
4 |
2 |
1 |
3 |
1 |
We can then use the surrogate key to relate by and not the code. So a change of the field code in the table “Header” from an “a” to a “t” will require only one record change, the Header record and none of the Detail records. They will be implicitly changed by the relation back into the Header record by the HeaderSurrogate field.
One the outset, it may appear that some additional coding may be required to find tables that could be related to the Detail record, but by making these records also relate by the surrogate key, this is removed.
FIND Header WHERE
HEADER.Code = “a”
NO-LOCK NO-ERROR.
FOR EACH Detail WHERE
Detail.HeaderSurrogate = Header.HeaderSurrogate ...
FOR EACH CreditDetail WHERE
CreditDetail.HeaderSurrogate = Detail.HeaderSurrogate AND
CreditDetail.IsTax = ....
/* Since Code is no longer in CreditDetail, need to */
/* translate for the user. */
DISPLAY Header.Code CreditDetail.Qty ....
END. /* FOR EACH CreditDetail */
END. /* FOR EACH Detail */
In addition, the use of surrogate keys may be able to reduce the number of columns needed in a table to create a relation. This is in the case of records that are directly related to other records that need two or more columns to be related.
An example across three tables of fields (a, b, c), (a, b, d) and (a, b, e) would be:
a |
b |
c |
1 |
1 |
t1 |
2 |
1 |
t2 |
1 |
2 |
t3 |
a |
b |
d |
1 |
1 |
d1 |
2 |
1 |
d2 |
1 |
2 |
d3 |
a |
b |
e |
1 |
1 |
e1 |
2 |
1 |
e2 |
1 |
2 |
e3 |
By making the table of (a, b, c) the relational header, one can set up a surrogate key, s, for the relations (a, b) on the other tables, with a single column, transforming the tables into:
a |
b |
c |
s |
1 |
1 |
t1 |
1 |
2 |
1 |
t2 |
2 |
1 |
2 |
t3 |
3 |
s |
d |
1 |
d1 |
2 |
d2 |
3 |
d3 |
s |
e |
1 |
e1 |
2 |
e2 |
3 |
e3 |
So in effect, we have removed one column of data the database needs to store, and potentially index (as indices are on the relational fields most of the time!) These space and time savings can be brought across multiple tables if the relation described in the surrogate key is used in multiple tables.
The con to this, is on the outset, it appears the database is heavily de-normalized. There is still some commotion among the people I know if this truthfully is de-normailizing the database architecture or not, as there still are pure relations involved, just at a more abstracted level.[24]
Also, the number of records in a table is limited to the largest integer Progress is capable of generating and storing. So it’s use may be limited if you are expecting the table to contain more than 2 billion (that’s US billions or 2 x 109 ) records. Using Decimal can make the number of records reach into 50 digits according to Progress Limits.
In addition, additional coding may be needed to translate a code the user may enter into the surrogate key by finding the appropriate header record. A small price to pay in large databases.
If the relation is unique, the surrogate key should be unique. If the relation is not unique, then a buffer find may be required to get the original surrogate key value for that combination from a previous CREATE for a new CREATE or MODIFY of a record using that combination.
Setting up a security algorithm:
For security, there needs to be four levels of access.
The following diagram describes the relations visually.
At the lowest level called 1, is the URL. This would be each and every web page we want to handle with the security feature. This level answers if someone bookmarks or attempts to enter the URL into the browser, whether or not if they have any business in the URL.
At the next level called 2, we group sets of URLs into features to handle those sequences of screens that make up some peice of functionallity in the application. These features within a given application can have security set for various users, so as those users can have access to all the URLs in that feature. Some users may have access to a feature (that is actually a collection of URLS) or they may not have access to the feature. However, one set of users could have access to another set of URLs thru a different Feature, thereby giving the application some security over who can go into what feature within the application.
Additional resistance to users accessing an URL can be added at a higher level named 3, by collecting features (which are a collection of URLS) into applications. Access to wide sets of URLs can be denied to a user if they do not have access to the application or any of the lower levels. Applications are made up of features, which in turn are made up of URLs, and any access given to them in the lower levels will give them access to that level and below of URLs in this scheme of doing things.
Finally, determining the applications available to the User can be stored at the top level called 4.
The following describe the basic tables and fields needed to make the above. They do not provide space for naming urls, features, applicactions or suites. They concentrate on grouping elements as described above. Implementors will probably want to add additional information or relations to additional information, such a feature description, application description, and suite description for appearing on a menu of some sort to the user.
TABLE: User
FeatureCode integer Relates to Feature.FeatureCode
URLData character
UserAllowed character
INDEX: Key – URLData, UserAllowed
TABLE: Feature
FeatureCode integer
ApplicationCode integer Relates to Application.ApplicationCode
UserAllowed character
INDEX: Key – FeatureCode, UserAllowed
TABLE: Application
ApplicationCode integer
Suite Code integer Relates to SuiteCode
UserAllowed character
INDEX: Key – ApplicationCode, UserAllowed
TABLE: Suite
SuiteCode integer
UserAllowed character
INDEX: Key – SuiteCode, UserAllowed
The algorithm to check user access would be:
First would be a set of inputes. The data needed are the URL visited, which can be the base name of the URL. It should match what the page would call itself. Also needed would be the visitors name. Right now, that would probably be coming from a cookie. More on that later on in this section.
INPUT URLVisited
INPUT UserName
The first step is to find a level 1 record that would show the given user has access to the URL. If a record with the URL and the user name shows up, then they definately have access to the URL. If not, then we will need to move up the ladder to the next level to determine if they have been given access at that point.
Find URL
where URLValue = URLVisited
and UserAllowed = UserName
if available, allow access
If that original record is not found, then we will need to see if we can find a record with the URL and what feature that URL is a part of. Once that is establised we can then move up to the feature records with the correct feature code. If we cannot find such a record, then the URL probably is not in the security system, and the default in this algorithm is to deny access. Others may want to default to allowing access.
Find URL
where URLValue = URLVisited
if not available, deny access.
Now that we have a URL record that matches the URL visited and the feature that URL is a part of, we can move up and attempt to find a Feature record with the user’s name on it and a feature code matching the feature that URL is a part of.
Find Feature
where UserAllowed = UserName
and Feature.FeatureCode = URL.FeatureCode
If available, allow access
When we cannot find a feature with the user’s name on it, we then need to again move up a level by attempting to find a Feature by the URL’s feature code. Then use that record to find out what Application that Feature is a member of. If no such Feature can be found, then simply deny access.
Find Feature
where Feature.FeatureCode = URL.FeatureCode
if not available, deny access.
Once a Feature record is found, we can use it’s ApplicationCode to locate the Application Record that might be available with the user’s id on it. If such a record exists, then we can allow the user access to the full set of features under the application, as well the full set of urls under that applications’s features.
Find Application
where Application.UserAllowed = UserName
and Application.FeatureCode = Feature.ApplicationCode
If available, allow access
Again if we cannot find the user at the application level, we need to find out what suite the application is under, and if the user has access to the full suite of applications based on an entry in the Suite table.
Find Application
where Application.FeatureCode = Feature.ApplicationCode
if not available, deny access.
Find Suite
where Suite.SuiteCode = Application.SuiteCode
and UserAllowed = UserName.
if available, allow access.
else deny acess.
To run thru a sample:
URL
URL |
FeatureCode |
UserAllowed |
inp_order |
1 |
scottauge |
Feature
FeatureCode |
ApplicationCode |
UserAllowed |
1 |
2 |
markrigney |
Application
ApplicationCode |
SuiteCode |
UserAllowed |
2 |
1 |
mikeemmons |
Lets explore what happens when scottauge tries to access the URL inp_order.
The algorithm attempts to find an URL record with scottauge and the URL. In this example data, we see such a record exists, and so the user scottauge would be allowed into the page.
When markrigney attempts to access URL inp_order, we can see that no such URL record exists with his name on it, so we need to start moving up levels. The algorithm would attempt to find the feature the URL is a member is, in this case 1. Then it would access a feature record with the name markrigney on it, and would allow access to the user.
The user mikeemmons would go thru three such jumps before being allowed access by the algorithm.
If we had a user john doe, which is not mentioned in any of the records, the algorithm would deny john doe access to the page.
This algorithm should be run before any HTML is sent to the browser. This way a RUN statement can be performed that may output another HTML page (like “your not authorized to use this part of the web application.”) To do this effectively, the OUTPUT-HEADERS internal procedure should be used.
The E4GL method’s OUTPUT-HEADERS internal procedure
Using the E4GL method, a special internal procedure is run before any of the main program is executed. By making a listing of the program, one can see what the architecture of the application truely is[25], compared to what one might think it is simply by looking at the coding provided by the application’s programmer.
Before any output is sent to the browser, this program is executed. Inside this program, you may want to put your security algorithms and definately your cookie setting code, as strange things will appear in the browser after the <content text/html> tag is put out (an automatic thing).
In my programs, security is usually always implemented, so I make an include file:
/* security.i include file */
DEFINE OUTPUT-HEADERS:
/* some security based stuff */
/* allow the application programmer to create a local-output-header */
/* to be run after the security is set. */
IF SESSION:GET-SIGNATURE(“local-output-headers”) BEGINS “PROCEDURE” THEN RUN local-output-header.
END. /* OUTPUT-HEADERS */
Javascript for active and inactive fields:
<html>
<head>
<title>New Page 1</title>
<meta name="GENERATOR" content="Microsoft FrontPage 3.0 Sucks">
</head>
<script language="javascript">
// Explore how to make fields active and inactive
// Explore how to determine if fields were changed
// General Theory of Operation:
// Have a set of rules to set varibles describing "activeness" for each input object. Basically,
// onchange()s on input objects will be used to set varibles to describe the "activeness" of other input
// objects. Those objects will have onfocus()s to determine if the user can enter data or
// not.
// Use a set of varibles to determine if an input object should be active,
// initially all input items are active.
var abutton = true;
var aselect = true;
var aradio = true;
var acheckbox = true;
var atexted = true;
var atext = true;
// Have a set of rules to determine if the object is active. Each object
// should have a onfocus() event handler attached to it, to call into this
// function to determine if the input item is active. If not active, blur will
// be applied.
// This is a general function, from here, individual functions determine the activeness
// of an input object. This is so all input objects have one place to go to determine
// activeness. If the object does not have it's activeness controlled, then return
// true at all times.
function isactive (objectptr) {
if (objectptr.name == "button") {
if (abutton == false) objectptr.blur();
}
else
if (objectptr.name == "select") {
if (aselect == false) objectptr.blur();
}
else
if (objectptr.name == "checkbox") {
if (acheckbox == false) objectptr.blur();
}
else
if (objectptr.name == "texted") {
if (atexted == false) objectptr.blur();
}
else
if (objectptr.name == "text") {
if (atext == false) objectptr.blur();
}
return true;
} // isactive()
// This function actually applies rules to if an input object should be
// active or not. This is done by calling from the onchange handler on
// each input object.
function setactive (objectptr) {
alert (objectptr.name);
alert (objectptr.value);
// If the object is the text box, then make the text editor box
// inactive.
if (objectptr.name == "checkbox") {
if (objectptr.checked)
atext = false;
else
atext = true;
alert("set atext to " + atext);
} // text box was populated
} // setactive()
</script>
<body>
<form method="POST">
<p><input type="button" value="Button" name="button" onfocus="isactive(this)"></p>
<p><select name="select" size="1" onfocus="isactive(this)" onchange="setactive(this)">
</select></p>
<p><input type="radio" value="radio" checked name="radio" onfocus="isactive(this)"
onclick="setactive(this)"></p>
<p><input type="checkbox" name="checkbox" value="checked" onfocus="isactive(this)"
onclick="setactive(this)"></p>
<p><textarea rows="2" name="texted" cols="20" onfocus="isactive(this)"
onchange="setactive(this)"></textarea></p>
<p><input type="text" name="text" size="20" onfocus="isactive(this)"
onchange="setactive(this)"></p>
<p> </p>
</form>
</body>
</html>
Javascript for required fields:
<html>
<head>
<title>New Page 1</title>
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
</head>
<script language="javascript">
// Determine that required fields in the form have been entered
// Function to call on the submit of the form. This should be mentioned
// in the FORM tags event handle onsubmit()
function valreqfld (formptr) {
var noerror = true;
var errormsg = "";
// Here we check if required fields have been entered.
if (formptr.T1.value == "") {
errormsg = errormsg + "T1 is required entry\n";
noerror = false;
}
if (formptr.T3.value == "") {
errormsg = errormsg + "T3 is required entry\n";
noerror = false;
}
if (! noerror) alert (errormsg);
return noerror;
}
</script>
<body>
<form method="POST" name="test" onsubmit="valreqfld (test)">
<p><input type="text" name="T1" size="20"></p>
<p><input type="text" name="T2" size="20"></p>
<p><input type="text" name="T3" size="20"></p>
<p><input type="text" name="T4" size="20"></p>
<p><input type="submit" value="Submit" name="B1"><input type="reset" value="Reset"
name="B2"></p>
</form>
</body>
</html>
Javascript for client level calculations:
<html>
<head>
<title>New Page 1</title>
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
</head>
<body>
<form method="POST" name="calc">
<script language="javascript">
// How to set up a calculation between fields and how to make the sum
// fields "read only"
// Note that the function is in the form object which contains the input
// objects that will be used to calculate with.
function calculate () {
document.calc.t3.value = Number(document.calc.t1.value)
+ Number(document.calc.t2.value);
} // calculate
</script>
<p><input type="text" name="t1" size="20"
onchange="calculate()"></p>
<p><input type="text" name="t2" size="20" onchange="calculate()"></p>
<p><input type="text" name="t3" size="20" onfocus="this.blur()"></p>
<p><input type="submit" value="Submit" name="B1"><input type="reset" value="Reset"
name="B2"></p>
</form>
</body>
</html>
Where to get more information
Since the web has become so hot, there are new books and new technologies out there all the time. So I will skip over the book category, as one can glean thru them at the book store (or the web site!)
I will say, you will want a book on HTML that provides a reference section, because once you understand it, you will be more interested in “what was that again” instead of surfing thru tutorial content. Same goes for Javascript, Java, and VB Script.
Online:
Though I like my tutorial kinds of books to be hardcopy, I prefer my reference types of books to be on-line.
Netscape keeps developers informed about the abilities of it’s browsers at this site. Usually one can find the latest javascript reference and HTML reference for their browsers in HTML archived within a ZIP file for download. At the time of this writing, it was free.
Microsoft also keeps documents on HTML, VBScript, and Javascript at it’s site. At the time of this writing, the user would need to register with Microsoft to access this information.
Web application development can be handled by the company I helped found: Auge, Emmons, & Ziola, Inc.
http://www.amduus.com
I can be reached at sauge@amduus.com or thru the main Progress E-Mail Group .
[1] The screen is controlled by the browser, and not by any of Progress’ web tools, so to make the browser display properly, the programmer will need to be familiar with HTML, the language the browser uses to render the output to the screen.
[2] See www.gartnergroup.com as well other advisory organizations.
[3] How much memory have you bought for your machines so people can log in and not use that memory continously while away at a meeting or a brief brain break?
[4] HTML is Hyper-Text Markup Language. A browser can be thought of as a visual printer. Just as a printer uses special codes to define where characters should be bolded and where they should be italized, a browser uses this special language to explain how a page should be rendered on the screen.
[5] Oracle, Informix, Symantec, ODBC, SQL Server, etc.
[6] Hence, if the webserver is on the internet, you will need a domain name server registered with the internic that the internet root servers can use to find the IP address of your machine with.
[7] Generally this is port 80. For processes not running under root authority, the port 8080 is common.
[8] Depending on the web server used, the options of an NSAPI and ISAPI interface could be used.
[9] These distrinctions are noted usually in a web server configuration file that is modified and used by the web server on start up. For example, Lotus Dominoe uses /etc/httpd.conf or a web based configuration can be performed. Lotus Dominoe, Netscape Fast Track, and Microsoft IIS all have web based configuration available for the server to be set up. See the server operations guide for more information.
[10] Part of the URL after the cgi program name
[11] I usually put it in the same place as the *.pf file used by the agents to connect to the database for the given application. This way everything is in one spot for a given application.
[12] Many of these ideas are heavily borrowing ideas on Software Diagraming developed in the book ___, by ____ ISBN _____. Their ideas were modified to meet the needs of web programming which was not present at the time the book was written.
[13] A method in javascript that allows the same page to be reloaded. Unfortunately if the page was made available from a POST on the action of a form, the hidden fields are lost in some browsers. Using a GET as the action at least encodes all the form fields into the URL instead of thru stdin. See the tips section for more information about this behavior.
[14] My condolences to the programmer responsible for getting the UPDATE EDITING statement to work, as I can imagine it was quite an effort and now is useless in Webspeed.
[15] Javascript and VBScript can also be used to set and read cookie information on a browser, but using javascript and VBScript will give the application user some insight on what is happening inside the application if done thru these languages, as the instructions are transmitted to the browser and a View Source will lay naked the HTML, Javascript, and VBScript code. This may be of concern if you have an internet application as it gives clues about what is happening. The 4GL language elements are never sent to the browser as these are server side instructions.
[16] Of which, none exist to my knowledge, though I have tossed around the idea. Since there is a competing product out there that is made by the actual vendor, that would be the best route to take.
[17] This is actually defined by a proprocessor symbol known as OUT and is referenced by {&OUT} in the source. See your Workshop Programming Guide for more information on preprocessor definitions available.
[18] All this client starting up and shutting down may strike the reader as a lot of overhead. This would be true if the architecture has been like Progress architectures before. In Webspeed the broker and agent processes are already always running – they pretty much just run the program specified outputting the results and then waiting again for a program to be specified.
[19] The ip prefix identifies the program as being an internal procedure to the source procedure.
[20] It is recommended that local varibles be used to store the values of form fields. This way they can be conveniently checked and validated before assignment to the database record, which may cause a Progress error – and we know how ugly those are on the screen.
[21] Be sure to remember the mapping of the directory in the URL must be fore thought out as the directory is often hard coded into the application with such items as <IMG SRC=”images/button.gif”> where images would be mapped into /appl/static by the web server. One may not want to mix up icons and maybe one does to have one point of maintenace for marketing graphics guidelines. Just note that this is something to think about.
[22] Set inside the webspeed.cnf file for each broker service defined.
[23] Note that you will want a new wtb for each agents to start up for an application. If an application has a commonly named file, at least one of the agents are going to be confused by it.
[24] My short argument on this, is that since the relation is described by a simple substitution of (a,b) with (s), and that (s) is equivalent to (a,b), that is an onto relationship or one-to-one, then the table is still normalized as s is merely a substitution for the values of a and b. It is really quite mechanical....
[25] There is a great deal of interesting plumbing involved to make the application work in a clean and concise manner.