Previous Page TOC Next Page See Page



- 12 -
The LiveWire Object Tree


As in Navigator, LiveWire has a set of objects that are available for developing LiveWire-based applications. The LiveWire object tree consists of four objects:

These objects have associated methods and properties and can be extended with additional properties. Each object also has a lifetime, which varies based on the object.

The LiveWire Object Tree


The primary purpose underlying the LiveWire object tree is to provide mechanisms for maintaining state when using HTTP, a fundamentally stateless protocol. What this means is that you can track access to a server-based application by a single client across multiple pages. With the highly complex interactive applications being used on the Web, this ability is increasingly important when you're trying to maintain information about a user and his or her session.

To help you do this, LiveWire provides four objects:


Object Lifetimes


Before taking a detailed look at the properties and methods of each object, you need to understand the concept of object lifetimes. Each object in the LiveWire object tree comes into existence at a specified time and lasts until a specified time. Here is the object lifetime of LiveWire objects, in order from longest lifetime to shortest:

In addition, global variables declared in server JavaScript have the same lifetime as the request object.

Object Scope and Property Types


Another important concept in using LiveWire objects is that of scope. Unlike client JavaScript, LiveWire objects are not global in scope. Within a function, LiveWire objects are inaccessible, which means you must pass objects or their properties to a function as parameters.

Another unique aspect of server JavaScript as it's used in LiveWire is that all properties are stored as string. So, although you can assign a Boolean or numeric value to a property, once it's assigned, it's a string—it's no longer Boolean or numeric.

For instance, the following JavaScript code would have worked in client JavaScript, but because you're dealing with server JavaScript, it's incorrect:

client.property = true;
if (client.property) { JavaScript Code }

Because client.property is actually a string, the code would have to be this:

client.property = true;
if (client.property == "true") { JavaScript Code }

Similarly, numbers are also stored as a string, so if an integer were assigned to client.property and you wanted to increment it, we would have to use

client.property = parseInt(client.property)++

instead of client.property++ or client.property += 1.

The request Object


The request object supplies information about a specific client request. Client requests occur when the user manually opens a URL, selects a bookmark, or clicks on a hyperlink; when client JavaScript navigates to a page or server, JavaScript redirects the browser to a particular page.

The request object has four pre-defined properties, as listed in Table 12.1.

Table 12.1. Pre-defined properties of the request object.

Property Description
agent Name and version of the client. Provides the same information as navigator.userAgent in client JavaScript.
ip Supplies the IP address of the client.
method Specifies the method used by the client to make the request (that is, GET, POST, or HEAD for HTTP 1.0).
protocol Returns the protocol and level used by the client to make the request (such as HTTP/1.0).

Other properties of the request object are created in two ways:

For example, in this form,

<FORM METHOD="post" ACTION="URL">
Name: <INPUT TYPE="text" NAME="name">
<INPUT TYPE="submit">
</FORM>

a property called request.name is created when the form is submitted to the server.

Likewise, this hyperlink

<A HREF="URL?number=5">The Link</A>

would create a request property called number with the value 5 when the user clicks on the link.

The client Object


The client object helps to distinguish separate clients accessing an application. It can be used to track persistent state information across multiple pages of an application. A new object is created each time an unknown client accesses an application, and the same client object is provided each time the client reconnects to the application.

The client object contains no pre-defined properties. Instead, applications can create their own properties of the client object, which then persist across multiple accesses by a client.

For instance, an application could create a property called name:

client.name = "User's Name";

This property would then be available for the rest of the client's connections to the application.

Client objects can be stored in several different ways. The method used for a particular application is specified in the LiveWire Application Manager when you install or subsequently modify an application.

At the most basic level, the client object can be stored on the client using cookies or URL encoding or on the server using short cookies, URL encoding, or IP address references.

Client Cookies


If client cookies are used to store the client object, then each property is stored as a separate cookie with the name NETSCAPE_LIVEWIRE.propName=propValue.

The disadvantage of this technique is two-fold: Many clients don't support cookies, and the limitations on the number of cookies may mean that information is destroyed prematurely by other applications from the same server.

Client URL Encoding


In this technique, all the object information is transferred to the client as name-value pairs encoded into the URL with the syntax: URL?name1=value1&name2=value2&...

With client URL encoding, the server must dynamically generate URLs and object information must be transmitted each time a request made.

Server Short Cookies


The short cookie technique stores the client property data on the server under a name generated the first time a client accesses an application. This name is then stored on the client by using cookies and subsequently passed to the server with each client request. The short cookie technique helps overcome the size and number limitations of client cookies.

Server Short URL Encoding


The server-based short URL encoding uses the same generated name technique to store client objects on the server, but then passes the generated name from client to server by encoding it into URLs.

Like client-based URL encoding, this technique requires dynamically generated URLs.

Server IP Addresses


The IP address technique stores client object data on the server based on the client's IP address. This works well when each client has a fixed IP address, as in an intranet. However, on the Internet, where many users get dynamically assigned IP addresses each time they connect to their Internet Service Provider, this technique isn't reliable because it's simply not possible to track a single client using IP addresses. Proxy servers also mask the real client IP address, which hinders this technique.

client Object Lifetime and Maintenance


The lifetime of the client object has a default expiry time that allows LiveWire to clean up old client objects that aren't necessary anymore. This is done because once a client accesses an application, there is no guarantee that the user will do so again in the future.

By default, if the client object is stored in a cookie on the client, it expires when the user exits the client browser. Server-based storage expires the client object by default after 10 minutes of inactivity.

The client object provides two methods that allow an application to override these defaults:


The project Object


The project object offers a way to share data between all clients accessing an application. The data will persist from the time the application is started to the time it's stopped.

Like the client object, the project object offers no pre-defined properties. Rather, the application can use the object to define its own properties. For instance, this statement

project.nextWord = "value";

would define a project property called nextWord that would be available to all clients accessing the application.

Object Locking


Because it's possible for several clients to simultaneously access the project object, you need to use locking to prevent conflicts occurring—such as when two clients try to assign values to the same property at the same time.

By default, the project object implicitly locks a property when it's being read or set, then unlocks as soon as the action is finished. This works fine if an application wants to either read or set the property. However, if multiple steps are required, such as reading and then setting the same property in sequence, another client could possibly access the property between the reading and setting steps and change its value.

To prevent this, the project object provides the lock() and unlock() methods, which can be used to lock the object, perform several actions, then unlock it again. These methods would be used like this:

project.lock()
   Multiple JavaScript Statements
project.unlock()


Note:

It's important to remember that although one client locks the project object by using lock(), all other clients are prevented from accessing the entire object. For this reason, the object should be locked for the minimum time possible. In addition, all lock() calls should be balanced by an unlock() call.



The server Object


The server object gives you a way to share information among all applications on a server; it also provides several pre-defined properties, outlined in Table 12.2.

Table 12.2. Pre-defined properties of the server object.

Property Description
hostname The full host name of the server (including port

number)
host The host name of the server without the port number
protocol The protocol being used (such as http:)
port The port number of the server

Locking the server Object


Like the project object, locking needs to be used with the server object to ensure that two applications don't try to change or access values of the server object at the same time.

The server object includes the lock() and unlock() methods—which are used the same way as the lock() and unlock() methods of the project object—as a means to perform locking. The same caveats about length of locking and balancing lock() and unlock() calls applies to both the server and project objects.

Other LiveWire Objects


In addition to the LiveWire object tree described previously, which is associated with requests, clients, applications, and the server itself, there are two other main objects available in server JavaScript: File and database.

The File Object


The File object supplies a way to store and retrieve data from files on the server. This is useful when a database server isn't being used and there's a need to store persistent files on the server that last beyond a server shutdown.

The LiveWire File object is used strictly to create files on the server. For security reasons, it can't be used to create files on the client.

To work with a file, you create an instance of the File object in the same way you create an array:

filePointer = new File("file_path");

filePointer will be used to refer to the specific instance of the File object and file_path is the path on the server of the file to work with (this path corresponds to the application directory).

Methods of the File Object


The File object offers several methods, outlined in Table 12.3, for working with files.

Table 12.3. Methods of the File object.

Method Description
open() Opens a file. Takes a single argument specifying the mode to open the file with (see Table 12.4. for a list of file modes for the open() method). Returns true if successful; false if unsuccessful.
close() Closes a file. Returns true if successful; false if the file is not open.
lock() Locks a file from access by other users.
unlock() Unlocks a file.
setPosition() Positions the pointer in a file. Accepts two arguments: the first, an integer indicating the position in bytes, and the second, a reference that's optional. The values for the reference argument are specified in Table 12.5. Returns true if successful; false if unsuccessful.
getPosition() Returns the current position in bytes. Returns -1 if there's an error.
eof() Returns true if the pointer is at the end of the file; otherwise, it returns false.
read() Reads from the file. Takes one argument—an integer specifying the number of bytes to read. Returns a string.
readln() Reads and returns the next line from the file. The line separator is not included in the returned string.
readByte() Reads and returns the next byte in the file. Returns -1 if there are no further bytes to read.
write() Writes a string to the file. Takes a single string argument indicating the data to write to the file. Returns true if successful, and false if not.
writeln() Writes a string to the file followed by a new line. Takes a single string argument and returns true or false, indicating the success of the operation.
writeByte() Writes a byte to the file. Takes a single integer argument (the value of the byte to write to the file) and returns true or false.
flush() Writes the buffer to the disk. Returns true if successful and false if it fails.
byteToString() Converts a number into a one-character string. No object is required—can use File.byteToString(). Takes a single integer argument. The empty string is returned if the argument is invalid.
stringToByte() Converts the first character of a string argument into a number. No object is required—can use File.stringToByte(). Returns zero if the argument is invalid.
getLength() Returns the number of bytes in a file or -1 if there are problems performing the action.
exists() Returns true if the file exists; false otherwise.
error() Returns the error status or -1 if the file isn't open or can't be opened.
clearError() Clears the error status and the value of eof().

Table 12.4. Mode arguments for the open() method.

Mode Description
r Opens the file for reading. If the file exists, returns true; otherwise returns false.
w Opens the file for writing. Creates new file if the file doesn't exist.
a Opens the file for appending. Creates a new file if the file doesn't exist.
r+ Opens the file for reading and writing from the beginning of the file. If the file exists, returns true; otherwise returns false.
w+ Opens the file for reading and writing. Creates a new file if the file doesn't exist.
a+ Opens a file for reading and writing from the end of the file. Creates a new file if the file doesn't exist.
b Opens a file as a binary file (as opposed to a text file). Append this mode to any of the other modes in the open() method (for example, rb or a+b). Relevant only on Windows systems.

Table 12.5. References for the setPosition() method.

Reference Description
0 Sets the position in relation to the beginning of the file.
1 Sets the position in relation to the current position.
2 Sets the position in relation to the end of the file.
Other value Sets the position in relation to the beginning of the file.
Unspecified Sets the position in relation to the beginning of the file.

For instance, to open a new file in the /tmp directory called test, then write a line of text to it and close it, you could use:

newFile = new File("/tmp/test");
isOpen = newFile.open("w");
if (isOpen) { newFile.write("Some Text") }

Then the file could be opened and the value of the first line written out to the current HTML stream by using this:

theFile = new File("/tmp/test");
isOpen = theFile.open("r");
if (isOpen) { write(theFile.readln()) }

The database Object


LiveWire Pro gives you the ability to work with a database server and generate SQL queries; it presumes knowledge of, and access to, a database server and is beyond the scope of this book.

Briefly, though, LiveWire gives the database object methods for working with relational databases. The database object is created when an application connects to a database server.

Table 12.6. briefly outlines the methods of the database object. More details are available in the LiveWire Developer's Guide available on Netscape's Web site..

Table 12.6. Methods of the database object.

Method Description
beginTransaction() Begins an SQL transaction with the database server.
commitTransaction() Commits the transaction.
connect() Connects to a database server.
connected() Returns the status of a connection.
cursor() Creates a cursor for a specified SELECT statement.
disconnect() Disconnects from a database server.
execute() Performs a specified SQL statement.
rollbackTransaction() Rolls back the transaction.
SQLTable() Displays query results.
majorErrorCode() Returns the major error code.
minorErrorCode() Returns the minor error code.
majorErrorMessage() Returns the major error message.
minorErrorMessage() Returns the minor error message.

Server JavaScript Functions


LiveWire provides several built-in JavaScript functions that aren't methods of any of the LiveWire objects:


The write() Function


Like the document.write() method in client JavaScript, the server-side write() function is used to display the results of JavaScript expressions into the HTML stream. The function takes a single expression, which evaluates to a string: write(expression).

The source code received at the client end is the actual text or HTML generated by the write() call and is treated as static HTML by the client.

The writeURL() Function


The writeURL() function is used to generate dynamic URLs when either of the URL encoding methods of maintaining the client object is being used.

The writeURL() function accepts one argument: an expression evaluating to a string that specifies the URL of a page to link to. The result returned by writeURL() is the full URL, including all necessary encoded information. For instance, to create a link to the URL http://some.domain/some/path.html, you could use

write('<A HREF="');
writeURL("http://some.domain/some/path.html");
write('">');

or simply

<A HREF=`writeURL("http://some.domain/some/path.html")`>

The redirect() Function


This function redirects clients to the URL specified as the argument to the function.

The debug() Function


The debug() function redirects its output to the trace utility's display. This function has been discussed in the previous chapter.

The flush() Function


In general, LiveWire sends output from the write() function to the client in 64K blocks of data. Until 64K are available to be sent, the data is stored in a buffer.

The flush() function enables you to send the content of the current buffer to the client before it reaches 64K.

Summary


In this chapter, you reviewed the objects and major functions available in LiveWire-based server JavaScript. They give you the means to develop sophisticated applications that, among other things, work with relational databases, maintain persistent state information, and track information about clients using an application.

In the next chapter, you'll see some small examples that demonstrate the applications of LiveWire-based programming.

Previous Page Page Top TOC Next Page See Page