JavaScript SE: Chapter 17 Copyright ©1996, Que Corporation. All rights reserved. No part of this book may be used or reproduced in any form or by any means, or stored in a database or retrieval system without prior written permission of the publisher except in the case of brief quotations embodied in critical articles and reviews. Making copies of any part of this book for any purpose other than your own personal use is a violation of United States copyright laws. For information, address Que Corporation, 201 West 103rd Street, Indianapolis, IN 46290 or at support@mcp.com.

Notice: This material is excerpted from Special Edition Using JavaScript, ISBN: 0-7897-0789-6. The electronic version of this material has not been through the final proof reading stage that the book goes through before being published in printed form. Some errors may exist here that are corrected before the book is published. This material is provided "as is" without any warranty of any kind.


CHAPTER 17 - JavaScript on the Server

So far in this book the focus has been on using JavaScript on the client side. This chapter looks at how JavaScript is becoming an integral part of the other side-the server.

JavaScript extends the capabilities of the server. By providing a scripting language the software can do more without calling an external program. This makes it easier for Webmasters to add features to their sites that browsers can take advantage of. And it can reduce the load on the server by keeping the processing within the server software.

This chapter looks at the LiveWire environment from Netscape. LiveWire itself is not a server, but works with Netscape servers to create applications that make pages come alive.

An Overview of LiveWire

See Chapter 19, "Tools for JavaScript Development," for further discussion on LiveWire.

LiveWire from Netscape is an integrated, visual environment for building client-server applications for Internet or enterprise networks. These applications can be for the public to access or limited to a specific audience such as an intranet.

LiveWire is actually a suite. It consists of the Netscape Navigator Gold, LiveWire Site Manager, LiveWire Server Extensions, LiveWire Server Front Panel, and JavaScript. LiveWire runs on the UNIX and Windows NT operating systems.

This chapter details the use of JavaScript in LiveWire. Given the nature of JavaScript, it is believed that other servers that incorporate JavaScript will work similarly.

JavaScript on the server is nearly identical to JavaScript on the browser including the syntax and the statements. There are also several shared objects: string, math, and date objects. However, most objects are specific to the application. This chapter covers the objects unique to LiveWire.

Live Objects and Properties

LiveWire has four built-in objects: request, client, project, and server. Obviously these are related. Each server can run multiple projects. Any project can have multiple simultaneous clients using it. And most clients request more than one page. A graphical depiction of this relationship is shown in figure 17.1.

FIG. 17.1

While there can be only one server object, there can be several project objects, more client objects, and many more request objects. However, this picture is not static since request and client objects only exist for short periods of time.  

Request Object

Each time a browser wants more information it sends a request to a server. Data about these requests are available on the server from the request object in JavaScript. If you have written CGI scripts, you should be familiar with the properties that are built into the request object.

The Built-In Properties

The request object is initialized with four properties: agent, ip, method, and protocol. A JavaScript function on the server can use this information to determine its response to the request. The following list provides details about each property:

Other Request Properties

A request may include additional information. Your browser's request may have resulted from submitting information from a HTML form. This information becomes a request property. It does not matter if the data is submitted with either the post or get method. The name of each element of the form becomes a property name.

For example, take a form with a text element with the name of answer. Complete the text box with a value of "59" and submit it to the server. The server receives the information in the form of "answer=59." The request object now has a property called "request.answer" which reflects the value of "59."

You can also store information in request properties. One property you might want to consider adding is a time and date stamp. Remember that the life of a request object is rather short, so values stored in these properties are not stored for long.

client.custNo = request.idnumber

Client Objects Expire

The server overflows with client objects unless they are properly deleted. Since client objects are automatically created for each and every client to access, then there must be a mechanism for deleting them.

LiveWire automatically deletes any client object with no property values. So if you don't use a client object, you don't have to worry about deleting it. In other words, you only have to clean up after yourself.

The default expiration is ten minutes of inactivity. If the client does not send another request to the server within ten minutes of the previous request, the object expires.

Obviously, in many cases ten minutes is insufficient time and you might want to manually control this. You can simply use the expiration statement

client.expiration(seconds)

where seconds is the number of seconds before the client expires.

Another manual control is destroy. If you no longer need the client object, simply use the statement

client.destroy()

LiveWire looks at the client that sent the request and destroys its client object. This eliminates all of the client object's properties as well.

Cookies Store Information Between Sessions

Another technique for retaining client information is cookies. The browser must support the Netscape cookie protocol. If supported, the server sends the information to the client as name/value pairs. Obviously, this increases network traffic, but can offer substantial advantages to large access servers.

For more information about cookies see http://home.netscape.com/newsref/std/cookie_spec.html.

There are several other techniques for maintaining this information. However, they all have limited application. Client URL encoding causes a large increase in network traffic. Using IP addresses on the server only works for clients using fixed IP addresses. This might work for some intranet applications; for general use, it is worthless. For more details, refer to the LiveWire documentation.

Project Objects

Each application, when started, creates project objects. This is global data for the entire application. Every client that accesses the application shares these objects.

Properties for Project Objects

The project object has no pre-defined properties. If you need to hold information for your project, you create the objects you need in the application.

Many projects need to store values. For example, in billing a customer you might need the next invoice number. This number is incremented when another invoice is generated.

Lock Project Objects

In any multi-user environment you must deal with cases of simultaneous access. On file servers, you lock a file while you are using it. You unlock it when you are finished with the operation. The other user must wait for you to finish.

If you do not lock files, the data can be corrupted. A simple example is with two people editing a document. If both are editing at the same time, then one saves his changes before the other. The problem is that the first set of changes are over written by the second.

Project objects should also be locked when in use. In your task, simply start with the line

project.lock();

Next, include your statements. For example,

invoiceno = invoiceno + 1

Then unlock the object with

project.unlock();

Server Objects

Global data for the entire server are in the server objects. These objects can be share between applications. There are also a few objects that tell you about the server. Any request, client, or project can access these objects.

The Built-In Server Properties

The server object is initialized with the following two properties:

Adding Server Properties

As with most JavaScript objects, you can add properties to server objects. For example, you might want to add the time the server was last accessed. This might be read by a monitoring routine, as follows:

     today = new Date()
     server.accesstime = today.getTime()

As with project objects, server objects should be locked. Since you can have more than one process accessing the object at one time, you should use the same locking procedure as discussed for project objects.

External Process Communications: JavaScript and CGIs

Undoubtedly with your active interest in building Web sites you have dealt with Common Gateway Interface (CGI) scripts. Prior to JavaScript, this was the primary means of creating interactive applications. Libraries of CGI scripts include counters, emailers, message boards, and many other functions.

LiveWire can replace CGI programming. Instead of calling external programs, the server software runs applications that are closely integrated to it. JavaScript is the language of these applications.

Applications are developed with three tools. You build these applications using LiveWire's Site Manager. The source files for the applications are developed using the same HTML editors used to build browser JavaScript pages. The applications run in response to requests from Netscape Navigator.

Steps to Building a LiveWire Application

Building a LiveWire application is not unlike other development procedures. The process can be done using either a command line compiler or a graphic interface.

The following are the steps to create a LiveWire application:

  1. Create the source files (see the section, "LiveWire Source Files," later in this chapter).
  2. Using the graphic interface of Site Manager (see fig. 17.2), you must bring the files under site management. You do this by selecting the application directory on the screen and choosing Site, Manage. (For the command-line compiler, you can skip this step.)
FIG. 17.2 

LiveWire's Site Manager displays your site directory in a tree structure where 
you specify which part of the site you want to manage. The directories managed 
by LiveWire are highlighted with a red marker.
  1. Build the application by creating a compiled *.web file.
  2. Install the application using the LiveWire Application Manager (see fig. 17.3).

FIG. 17.3

LiveWire's Application Manager installs the applications you develop. The 
Application Manager itself is a LiveWire application and is listed on the 
first line.
  1. If you re-build the application, restart it using the Application Manager.
  2. Run the application by loading any of the pages with your browser.

Browsing into a LiveWire Application

Like any other Web site, a browser requests a Web page to access a LiveWire application. The browser can request any of the pages within an application. The server sees the request like any other request, though it is handled differently. In turn, the browser is not concerned if the HTML is a static page or from a dynamic LiveWire application. The form of the URL is as follows:

http://server.domain/application/page.html

In this case the domain is the Internet domain and the server is the name of the HTTP server. The next element, application, is the name you define when the application is installed with the Application Manager. The final part, page.html, is simply the name of any page in the application. Each application has a default page. So if page.html is the default for this application, the page.html at the end of the URL would be optional.

In the following example,

http://home.myserver.com/callhome/phonebook.html

the page phonebook.html is severed from an application named callhome. This application resides on the server called home at the domain of myserver.com.

LiveWire Source Files

To build a LiveWire application, you construct one or more source files. The following are three types of files you can build:

Using the SERVER Tag

The SERVER tag contains JavaScript that either executes a statement or produces HTML with the write function. A JavaScript statement can be a rather simple routine or a more complex set of functions.

Using the SERVER tag with JavaScript to produce HTML is very common. As a very simple example, you might create a document that returns the IP address to the browser, as follows:

<P>Your request came from ip address: 
<SERVER> write(request.ip) </SERVER>

When using the SERVER tag, the result is sent in response to the request. The source code that contains the SERVER tag and your logic stays secure on the server. This is different than HTML pages that contain JavaScript where the browser gets all of the source code.

Using the Backquote

A shorthand method of putting JavaScript into the HTML document is to use the backquote ('). Using the backquote, the HTML is automatically generated without having to use the write statement.

Our preceding example would simply become

<P>Your request came from ip address:  'request.ip' </P>

The backquote is especially useful when the JavaScript produces an attribute value. Generally, HTML tags have the form of

<TAG ATTRIB="value" [...ATTRIB=VAL]>

where ATTRIB is the attribute and value is its value. Backquoted JavaScript can substitute for any attribute or value in this syntax.

Consider adding hidden files to your forms. Then, prior to submitting the data, have a JavaScript routine that processes the user input and puts the result into the hidden field's value property. Practical uses are totals, averages, word counts, and other mathematical results. This takes some of the load off the server.

From Server to Client

Usually a server only returns a static page in response to a browser request. In LiveWire, the response is still a page, but the contents of the page vary. User input can result in changes to default form values, new values of hidden form elements, or direct substitutions.

A server side JavaScript can dynamically build in the HTML code for a form element that is part of the page. As an example, you can have the following statement in a source document:

<INPUT TYPE="text"  NAME="example" VALUE='request.agent'>

In this case the default value of the text is the browser agent information.

You use an identical procedure for hidden form elements. The only difference is that the type is "hidden" instead of "text". Your client side JavaScript can then use this value as part of any function.

Another means of making your pages come alive is to change part of the JavaScript code. When you send a page to the browser it can contain JavaScript code for the browser to execute as part of the page. There is no reason that this code has to be static.

The server can modify the page being sent to change the JavaScript code embedded in the page. The page on the server side might include

<SERVER>
write ("<SCRIPT>var luck = " + client.winnings + "</SCRIPT>")
</SERVER>

Assuming the value of client.winnings is 1000, the browser sees a line of

<SCRIPT>var luck =  1000 </SCRIPT>.

Eternal Files and Databases with JavaScript

In building a non-trivial application, you need to be able to read and write data from a file. It can be customer information, data about merchandise, or student grades. This is a basic procedure in almost every application.

LiveWire provides a file object. This allows your application to write to the server's file system. As a security measure, JavaScript on the browser does not permit saving data to the file system.

LiveWire Pro adds support for Structured Query Language (SQL) databases. It supports Informix, Oracle, Sybase, and Microsoft databases.
fileObjectName = new File("path")

In this case "path" is the file path relative to the application directory. This in not a URL, but uses the server's file system format-for example, /mydirectory/sample.txt.

Each file object has numerous methods that you can use. However, you must first open the file.

Open the File

After you create the file object, you then need to open the file before you can do anything else with it. To open the file, you use the open method, as follows:

result=fileObjectName.open ("mode")

The result is true if the file was opened successfully; otherwise it is false.

Forgot the filename? Simply use the write method to display it. For example,
     write ( fileObjectName )
results in the display of the filename.

File Positioning

When dealing with data stored in a file, you must consider where in the file the desired data is stored or where you intend to store it. You may not want to read the first three items but you do want the next two items. The file object allows you to read the current position, change the position, or check if you are at the end of the file.

When you open a file, the current position depends on the mode you use to open it. Generally it starts at the beginning of a file, except for modes "a+" and "a" where data is appended at the end of an existing file. For empty or new files, the end of file and the beginning of the file are the same.

The current position in the file is available using the getPosition method. The first byte in a file is 0 and any other position is a positive number. An error is indicated by returning a -1. The syntax is

x =  fileObj.getPosition()

The setPosition method changes or sets the current position. You can change the position relative to the beginning of the file, relative to the end of the file, or relative to the current position. This is called the reference, and is an optional parameter. The default reference is the beginning of the file.

The syntax for the setPosition method is

fileObj.setPostion(position [,reference])

where reference is a numeric value-0 relative to the beginning of the file, 1 relative to the current position, and 2 relative to the end of the file. This method returns true if successful; otherwise false.

For example, if the current position was 10 with the end file at 20, the following would be the results:

fileObject.setPosition ( 3)     /...new position is 3
fileObject.setPosition(2,0)     /...new position is 2
fileObject.setPositon(-2,1)     /...new position is 8
fileObject.setPosition(-2,2)     /...new position is 18

In reading a file you often want to read through the entire thing, but to do so you need to know when you have reached the end; so you test for the end of the file (eof). The file object has the eof method that returns a true after the first read operation that attempts to read past the end of the file.

fileObj.eof()

Writing with the File Object

The file object provides three methods of writing data to a file. These methods allow you to write a string, write a string followed by a "\n" (see the following note), or write a single byte to a file. Each method returns true if successful; otherwise it returns false.

The syntax is

fileObj.write(string)
fileObj.writeln(string)
fileObj.writeByte(number)

Like most languages, when data is sent to a file it is stored in a buffer to increase efficiencies. This internal buffer stores this data until the buffer is full, until the file is closed, or when flushed. (Flushed means the code forces the data in the buffer to write to the file.) Then it physically writes the data into the file.

To ensure that your data is properly saved, you can force a flush with the flush method. The syntax is

fileObj.flush()

Reading with the File Object

Just as there are three methods of writing to a file, so there are three methods to reading a file. You can read a specific number of bytes, read in the entire next line, or read in a single byte. Each method returns true if successful, otherwise it returns false. The syntax is

fileObj.read(count)
fileObj.readln()
fileObj.readByte()

On Windows systems, text files typically end a line of text with a carriage return and an end of line character (\r\n). On UNIX systems, the line ends with a single end of line character. To accommodate both formats, when using the writeln method, JavaScript adds one or both characters at the end of the line depending on the server platform. When reading a file, the line separator characters are not included when using the readln method.

Converting Data

The data in any of your files is stored in either ASCII text format or binary. The file object has two methods for converting from one format to the other. Both methods are static, so no object is required.

The syntax of these methods is

File.byteToSring(number)
File.STringToByte(string)

Error Checking and Getting Information

Often you just want basic information about a file: Does the file exist? How long is the file?

The exists method returns a simple true if the file exists, otherwise it returns false. For example,

fileObj.exists()

The getLength method returns the number of bytes in a file. For a text file, it returns the number of characters. In case of an error, it returns a -1. For example,

fileObj.getLength()

LiveWire also allows you to check on the error status of a file or clear the error status. Since error status codes are platform dependent, you must check your operating system documentation for the actual codes. The syntax for these methods is

fileObj.error()
fileObj.clearError()

Example Using the File Object

Let's do a very simple example. Let's take an existing text file and copy it into a new file. The example in Listing 17.1 does not include error checking. In a real application you would want to add this to the code. For example, you might want to check if anyone else is already using the file.

Listing 17.1 Copying a File on LiveWire
oldFile = new File ("oldtext.txt")     /...create object for existing text file
newFile = new File ("newtext.txt")     /...create object for new file

result1 = oldFile.open("r")          /...open file for reading only
result2 = newFile.open("w")
     /...open file, initially empty, for writing

until oldFile.eof() {          
     /...until the end of the file is reached
     result3 = newFile.writeln(oldFile.readln())
     /...read a line from the old file and write it to the new file
}
result4 = oldFile.close()     /...close each file
result5 = newFile.close()

Internet & New Technologies Home Page - Que Home Page
For technical support for our books and software contact support@mcp.com
© 1996, Que Corporation