Chapter

4

Using the LiveWire object framework

iveWire comes with several predefined objects for application development, collectively referred to as the LiveWire object framework: request, client, project, and server. These objects provide an easy way to maintain persistent data using HTTP, which is a stateless protocol.

Some of these objects contain pre-defined properties set by LiveWire. You can also define properties of these objects for application-specific uses.

The LiveWire objects represent a spectrum of lifetimes, with the request object being the shortest-lived, and the server object being the longest-lived. The request object persists only for a single client request from Navigator. The client object persists for the duration of a particular client's connection to an application. The project object persists for the lifetime of the application (until the application is stopped or re-started), and the server object persists for the lifetime of the server process (until the server is stopped).

Built-in LiveWire Objects

As illustrated in Figure 4.1, all applications on the server will share the same server object. All clients accessing the same application will share the same project object, and all requests by the same client will share the same client object.

Using LiveWire objects

LiveWire objects are not global in scope. If you want to access an object's properties from within a function, you must pass the object as a parameter to the function. For example, in the Hangman sample application, the following statement is used to call the Substitute function, passing it properties of request and client:

client.answer = Substitute(request.guess, client.word, client.answer);
Properties of LiveWire objects are always stored as strings. Therefore, if you want to store numeric or Boolean values, you must write your scripts to convert values accordingly. The parseInt and parseFloat functions are useful for this purposte. For more information on these functions, see the corresponding topics in Part 2, "LiveWire Reference."

For example, you can create an integer client property as follows:

client.totalNumber = 17
If you want to increment the value, use parseInt as follows:

client.totalNumber = parseInt(client.totalNumber)++
Similarly, you can create a Boolean client property as follows:

client.bool = true
Then you can check it as follows

if (client.bool == "true")
	write("It's true!")
else
	write("It's false!")
Notice that the conditional expression compares bool to the string "true". You can use other techniques to handle Boolean expressions. For example, to negate a Boolean property, you can use something like this:

request.bool = (request.bool == "true") ? false : true
Because of these limitations, it may be more convenient to perform application logic using top-level JavaScript variables, and then assign the final values to the appropriate object property afterwards.

Request object

The request object contains data specific to the current client request. It has the shortest lifetime of any of the objects. LiveWire creates a new request object for each client request it receives. A client request for a page occurs when one of the following occurs:

Properties

The request object has four predefined properties, described in Table 4.1.

Table 4.1 Request object properties
Property

Description

Example

agent

Name and version of the client software. Use this information to conditionally employ advanced features of certain browsers.

Mozilla/1.1N (Windows; I; 32bit)

ip

The IP address of the client; may be useful to authorize or record access.

198.217.226.34

method

The HTTP method associated with the request. An application can use this to determine the proper response to a request.

For HTTP 1.0, method is either GET, POST, or HEAD

protocol

The HTTP protocol level supported by the client's software.

HTTP/1.0

When you declare top-level variables in server JavaScript, they have the same lifetime as request properties. For example, the declaration

var number = 42
will persist during the current request only.

In addition to the predefined properties and automatically initialized data, you can create request properties by using form elements and by URL encoding properties into the request.

Using form elements

Each input element in an HTML form corresponds to a property of the request object. The property name is specified by the NAME attribute of the form element. For example, the following HTML creates a request property called guess that accepts a single character of input from the user in the text field. You refer to this property in JavaScript as request.guess.

<FORM METHOD="post" ACTION="hangman.html"> 
<P> 
What is your guess? 
<INPUT TYPE="text" NAME="guess" SIZE="1">

Encoding request properties in URLs

You can manually encode request properties into URLs by using the following syntax:

URL?varName=value[&varName=value...]
where URL is the base URL, varName is a variable name, and value is its value. This scheme requires following the base URL by a question mark (?), that is then followed by pairs of variable names and their values. Separate each pair with an ampersand (&). This creates a request property named varName for each variable listed.

For example, the following HTML defines a hyperlink to a page that instantiates the request properties i and j to 1 and 2, respectively. The JavaScript file refpage.html can then reference these variables as request.i and request.j.

<A HREF="refpage.html?i=1&j=2">Click Here</A> 
Values of URL-encoded request properties are not reset when the user reloads a page (for example, by clicking the Reload button). In the previous example, if the user reloaded refpage.html, then i and j would remain 1 and 2, respectively.

Client object

Because many clients can access an application simultaneously, the client object provides a method for dealing with each client individually. It provides a technique for tracking each client's progress through an application across multiple requests.

LiveWire creates a new client object each time a new (unknown) client accesses the application. The server provides the same client object each time the client returns to the application with a subsequent request. Hundreds or thousands of client objects can be active at a single time.

Properties

There are no predefined property values in the client object, since it is intended to contain any data required by the application. JavaScript statements can assign application-specific values to the client object as in the following example:

client.prop1 = "foo"
This statement assigns the value "foo" to the client property named prop1. LiveWire automatically maintains these user-defined property values.

LiveWire does not save client objects that have no property values. Therefore, if an application does not need client objects and does not assign any client object property values, it incurs no additional overhead.

A good example of a client object property is a customer ID number. A user might enter the ID number when first accessing the application, or the application might assign a dynamic customer ID, for example,

client.custID = assignID(client.ip) 
Once the customer ID has been established, it would be inconvenient to require the user to re-enter the ID. However, without a facility like the client object, there would be no way to associate the correct customer ID with subsequent requests from a client.

Client object lifetime

The client object has a built-in expiration mechanism, because once a client accesses an application, there is no guarantee that it will request further processing or will continue to a logical end point. This mechanism allows LiveWire to occasionally "clean up" old client objects that are no longer necessary.

The client object can be maintained either by the server or by the client. By default, client objects stored in the client software by cookies expire when the user exits the client software. Client objects stored in the server expire after the associated client has been inactive for ten minutes. For more information on ways of maintaining the client object, see "Techniques for maintaining the client object" on page 73.

An application can control the expiration of a client object to make it longer or shorter than the default. An application can change the expiration of a client object with the expiration method, as follows:

client.expiration(seconds)
where seconds is the number of seconds until the client object expires.

An application can explicitly destroy a client object with the destroy method, as follows:

client.destroy()
When an application calls destroy, LiveWire removes all properties from the client object and then destroys the client object that sent the request.

Techniques for maintaining the client object

A LiveWire application can use several techniques to maintain the client object. You select the technique to use when you install or modify the application with the LiveWire Application Manager. For information on using Application Manager, see "Using Application Manager" on page 20.

There are two basic approaches for maintaing the client object: maintain it on the client or use an addressing scheme to maintain it on the server. The client-side techniques use either cookies or URL-encoding to maintain client property values. The server-side techniques use either cookies, URL-encoding, or IP address to refer to a data structure on the server that contains client property values.

Client-side techniques

There are two client-side maintenance techniques:

Netscape cookies are a mechanism by which the client stores information in small files, called cookie files. In the client cookie technique, the server transfers all object information as name/value pairs to the client using the Netscape cookie protocol. This approach is most suitable for high-volume consumer applications. It works only with clients that support the Netscape cookie protocol. One of the advantages of this technique is that you can use it for client-server communication. For more information, see "Using cookies for client-server communication" on page 89.

Each client object property is encoded in the cookie file as follows:

NETSCAPE_LIVEWIRE.propName=propValue;
where propName is the name of the property and propValue is its value.

The Netscape cookie protocol limits the number of property values that can be stored in the cookie file to twenty per directory. Every page in a directory will share the same cookie file. Each entry in the file is limited to 4096 characters.

In the client URL encoding technique, the server transfers all object information to the client as name/value pairs appended to URLs that reference other portions of the application. This scheme requires that all URLs be dynamically generated by the server. The object information must be transmitted multiple times for pages that refer to multiple URLs.

When using client URL encoding, be sure to use the writeURL function if you need to generate URLs dynamically. For more information on writeURL, see "The writeURL function" on page 84.

Preserving client properties

When using client-side maintenance techniques, properties of client are encoded into the server's response to a client request: either in the HEAD of the document (for client-cookies) or in server-generated URLs (for client URL encoding). Therefore, you cannot change client object properties after performing a flush. LiveWire performs an automatic flush after generating 64Kbytes of data. For more information on flush, see "The flush function" on page 85.

Important: To prevent losing any information, you should assign all client property values early in the scripts on each page. In general, you should ensure that client properties are set before the application generates 64 Kbytes of content.

Server-side techniques

There are three server-side maintenance techniques:

The IP address technique uses a data structure on the server based on the client's IP address. This approach works well for internal applications that run on a single server when all clients have fixed IP addresses. This technique will not work reliably if the client is not guaranteed to have a fixed IP address (for example, if using DHCP or an Internet service provider that dynamically allocates IP addresses). This technique will also not work for clients that use a proxy server, since all users of the proxy will report the same IP address.

The short cookies technique uses a data structure on the server based on a generated name. The first time the client accesses the application, it stores the generated name in the cookie file. The client then uses the Netscape cookie protocol to store and return this name in subsequent requests.

The short URL encoding technique uses a data structure on the server based on a generated name. The server appends the name to URLs that reference the application. In this scheme, LiveWire dyntamically generates all URLs used in the application.

Advantages and disadvantages of techniques

Each of the different techniques has various advantages and disadvantages, as summarized in Table 4.2. You should select the technique that is most appropriate for your application.

Table 4.2 Client Object Maintenance Techniques
Technique

Location

Advantages

Disadvantages

client cookies

client

Works with server farms

Works across server restarts

Navigator has a maximum of twenty cookies per directory.

Modest increase in network traffic

client URL encoding

client

Works with all clients

Works with server farms

Works across server restarts

Requires dynamically generated URLs

Largest increase in network traffic

IP address

server

Works with all clients

No increase in network traffic

Does not support dynamic IP access providers, multiuser systems, or users behind proxy servers

short cookies

server

Little increase in network traffic

short URL encoding

server

Works with all browsers

Little increase in network traffic

Requires dynamically generated URLs

The project object

The project object contains global data for an application and provides a method for sharing information among the clients accessing the application. LiveWire creates a new project object when an application is started, and each client accessing the application shares the same project object. LiveWire automatically destroys the project object when the application is stopped. A typical project object lifetime is days or weeks.

LiveWire creates a set of project objects for each distinct Netscape HTTPD process running on the server. LiveWire creates a project object for each application running on each distinct server. For example, there may be a server running on port 80 and a server running on port 142 on the same machine; LiveWire will create a distinct set of project objects for each of these processes.

Properties

There are no predefined properties for the project object, since it is intended to contain application-specific data accessible by multiple clients. A good example of a project object property is the next available customer ID. An application could use this property to track sequentially assigned customer IDs. Any client that accesses the application without a customer ID would be assigned an ID, and the value would be incremented for each initial access.

Locking the project object

When an application reads or sets a project property, LiveWire implicitly locks the property being accessed, during the brief instant that the application is reading or setting the value. This ensures that if an application is just reading or setting the value of the property, there will be no conflicts with other users. However, if an application wants to read a property value, then assign a new value to it based on that value (for example, incrementing it), implicit locking is not sufficient.

LiveWire provides a locking facility to ensure that different clients do not change project object properties simultaneously. Use the lock method to lock project, preventing any other clients from modifying it, and then use unlock to remove the lock.

When an application locks the project object, other users accessing the application must wait until the application is unlocked before they can get or set any project properties or lock project themselves. Client requests to access a locked project object will wait until it is unlocked or until the request times out, whichever comes first.

Note Since locking the project object blocks other users from accessing it, potentially delaying execution of their tasks, it is good practice to lock project only as much as neccessary.

The following script shows how to use lock and unlock to lock the project object while the application is modifying the customer ID property.

project.lock()
	project.next_id = 1 + project.next_id
	client.id = project.next_id
project.unlock() 
In general, the lock and unlock methods should be balanced. However, LiveWire automatically unlocks the project object after the completion of each client request to prevent an accidental deadlock situation.

server object

The server object contains global data for the entire server and provides a method for sharing information between several applications running on a server. The server object is also automatically initialized with information about the server.

LiveWire creates a new server object when the server is started and destroys the server object when the server is stopped. Every application that runs on the server shares the same server object.

LiveWire creates a server object for each distinct Netscape HTTPD process (server) running on a machine. For example, there might be a server process running for port 80 and another for port 8080; These are entirely distinct server processes, and LiveWire creates a server object for each.

Properties

The Table 4.2 describes the properties of the server object. In addition to these automatically initialized properties, you can create properties to store data to be shared among multiple applications.

Table 4.3 Server object properties
Property

Description

Example

hostname

The full hostname of the server, including the port number.

www.acme.com:85

host

The server name, subdomain, and domain name.

www.acme.com

protocol

The communications protocol being used.

http:

port

The server port number being used; default is 80 for http.

85

Locking the server object

To ensure different users or applications do not change server object properties simultaneously, there are lock and unlock methods that work exactly the same as the methods of project, described in "Locking the project object" on page 77. When an application has locked the server object, other applications (or instances of the same application) cannot get or set server object properties or lock the server object.