19.06.2013 Views

HAHTsite IDE Programming Guide - Product Documentation

HAHTsite IDE Programming Guide - Product Documentation

HAHTsite IDE Programming Guide - Product Documentation

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>HAHTsite</strong> <strong>IDE</strong><br />

<strong>Programming</strong> <strong>Guide</strong>


<strong>IDE</strong><br />

<strong>Programming</strong><br />

<strong>Guide</strong><br />

release 4.0


Notice<br />

© Copyright 1999 HAHT Software, Inc.<br />

All Rights Reserved<br />

May 1999<br />

MN07-C-00-400-00<br />

No part of this publication may be copied, photocopied, reproduced, transmitted, transcribed, or reduced to<br />

any electronic medium or machine-readable form without the prior written consent of HAHT Software, Inc.<br />

Information in this document is subject to change without notice. Names and information used in examples<br />

are fictitious.<br />

U.S. GOVERNMENT RESTRICTED RIGHTS. It is acknowledged that the Software and the <strong>Documentation</strong> were<br />

developed at private expense, that no part is in the public domain, and that the Software and <strong>Documentation</strong><br />

are Commercial Computer Software provided with RESTRICTED RIGHTS under Federal Acquisition<br />

Regulations and agency supplements to them. Use, duplication, or disclosure by the U.S. Government is<br />

subject to restrictions as set forth in subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer<br />

Software clause at DFAR 252.227-7013 et. seq. or subparagraph (c)(1) and (2) of the Commercial Computer<br />

Software—96 Restricted Rights at FAR 52.227-19, as applicable. Contractor is HAHT Software, Inc., 4200 Six<br />

Forks Road, Raleigh, NC 27609. Rights are reserved under copyright laws of the United States with respect to<br />

unpublished portions of the Software.<br />

Trademarks<br />

HAHT, HAHT Software, <strong>HAHTsite</strong>, e-Scenario, and “e-nable your enterprise” are trademarks or U.S. registered<br />

trademarks of HAHT Software, Inc.<br />

Portions Copyright© 1992-1996 Summit Software Company.<br />

This product includes software developed by the Apache Group for use in the Apache HTTP server project<br />

(http://www.apache.org/).<br />

Any other corporate names, product names, tradenames, trademarks, service marks, or service names owned<br />

or registered by any other company and mentioned herein are the property of their respective companies.<br />

Specifications subject to change without notice.<br />

HAHT Software, Inc.<br />

4200 Six Forks Road<br />

Raleigh, NC 27609 USA<br />

(919) 786-5100<br />

(888) 438-4248 (in the USA)<br />

(919) 786-5200 (Technical Support)


Contents<br />

About This Book<br />

Who is this book for? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii<br />

Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii<br />

Other <strong>HAHTsite</strong> documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xviii<br />

Other <strong>HAHTsite</strong> products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix<br />

HAHT Software’s commitment to you . . . . . . . . . . . . . . . . . . . . . . . . . . xix<br />

1 Introduction<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

<strong>HAHTsite</strong> Server Object Model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

The project package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3<br />

The datamanager package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4<br />

The form package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4<br />

The access package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5<br />

The corba package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5<br />

Data-management API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

ActiveX Data Objects classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6<br />

Relationship between ADO and SOM classes . . . . . . . . . . . . . . . . . . .6<br />

Data management in HAHTtalk Basic projects . . . . . . . . . . . . . . . . . .7<br />

Client-side scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

CORBA capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

Access to COM/DCOM objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

Remote debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

2 Working with Java Projects<br />

What’s in this chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

Adding server-side code to a Java project. . . . . . . . . . . . . . . . . . . . . . . . 12<br />

iii


Contents<br />

iv<br />

<strong>HAHTsite</strong> Server Object Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13<br />

External logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13<br />

In-line code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13<br />

Invoking an expression or a method from a dialog box . . . . . . . . .15<br />

Adding code in Server-side Code view . . . . . . . . . . . . . . . . . . . . . . .17<br />

What’s in a Java page? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18<br />

Editing HahtApplication.java and HahtSession.java . . . . . . . . . . . .25<br />

Adding Java files to a project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26<br />

Naming conventions for Java projects . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

Naming conventions for dynamic pages . . . . . . . . . . . . . . . . . . . . .30<br />

Calling a dynamic page from Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

Event handling in a Java project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

Editing and compiling Java code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

Using the code editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37<br />

Compiling a Java application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38<br />

Finding compile-time errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .39<br />

Debugging a Java application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .39<br />

Working with application directories . . . . . . . . . . . . . . . . . . . . . . . .39<br />

Java options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41<br />

Changing the Java file type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .41<br />

Overriding Java compiler options . . . . . . . . . . . . . . . . . . . . . . . . . . .42<br />

Overriding options for JAR, CAB, and ZIP files . . . . . . . . . . . . . . . . .43<br />

3 Working with HAHTtalk Basic Projects<br />

What’s in this chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

Adding server-side code to a HAHTtalk Basic project . . . . . . . . . . . . . . 46<br />

<strong>HAHTsite</strong> Server Object Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47<br />

External logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47<br />

In-line code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .48<br />

Invoking an expression or a subroutine from a dialog box . . . . . . .50<br />

Adding code in Server-side Code view . . . . . . . . . . . . . . . . . . . . . . .52<br />

What’s in a HAHTtalk Basic page? . . . . . . . . . . . . . . . . . . . . . . . . . .53<br />

Adding HAHTtalk Basic files to a project . . . . . . . . . . . . . . . . . . . . .60<br />

Naming conventions for HAHTtalk Basic projects . . . . . . . . . . . . . . . . 62<br />

Include files and Globals.hbs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63


Contents<br />

Project and external includes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63<br />

Declaring public variables with Globals.hbs . . . . . . . . . . . . . . . . . . .64<br />

Precompiler directives . . . . . . . . . . . . . . . . .64<br />

Calling dynamic pages from HAHTtalk Basic . . . . . . . . . . . . . . . . . . . . 65<br />

Event handling in a HAHTtalk Basic project . . . . . . . . . . . . . . . . . . . . . 66<br />

Editing and compiling HAHTtalk Basic code . . . . . . . . . . . . . . . . . . . . . 67<br />

Using the code editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67<br />

Compiling a HAHTtalk Basic application . . . . . . . . . . . . . . . . . . . . .69<br />

Finding compile-time errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69<br />

Debugging a HAHTtalk Basic application . . . . . . . . . . . . . . . . . . . . .70<br />

Working with application directories . . . . . . . . . . . . . . . . . . . . . . . .70<br />

Comparing HAHTtalk Basic and Visual Basic . . . . . . . . . . . . . . . . . . . . 72<br />

HAHTtalk Basic data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72<br />

Subroutines and functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73<br />

File I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73<br />

Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73<br />

Code page properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

4 Calling Server-side Java from HAHTtalk Basic<br />

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />

Using Java objects with HAHTtalk Basic . . . . . . . . . . . . . . . . . . . . . . . . 76<br />

CreateJavaObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .77<br />

GetJavaClass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .78<br />

CreateTypedJavaNull . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .78<br />

Differences between HAHTtalk Basic and Java . . . . . . . . . . . . . . . . . . . 79<br />

Java is strongly typed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79<br />

Parameter passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80<br />

Java is case sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80<br />

Locating objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80<br />

Mapping HAHTtalk Basic types to Java parameter types . . . . . . . . . . . . 81<br />

Mapping Java types to HAHTtalk Basic types . . . . . . . . . . . . . . . . . . . . 83<br />

Troubleshooting: Java runtime errors . . . . . . . . . . . . . . . . . . . . . . . . . . 84<br />

v


Contents<br />

5 <strong>HAHTsite</strong> Server Object Model<br />

vi<br />

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />

Built-in objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .90<br />

Getting references to the built-in objects. . . . . . . . . . . . . . . . . . . . . . . . 91<br />

From a Java project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .91<br />

From a HAHTtalk Basic project . . . . . . . . . . . . . . . . . . . . . . . . . . . . .96<br />

The Application object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />

Application object methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97<br />

Application object variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98<br />

Multiple processes and application-level variables . . . . . . . . . . . . . .99<br />

Retrieving Application object properties . . . . . . . . . . . . . . . . . . . .100<br />

Summary of Application object methods . . . . . . . . . . . . . . . . . . . .102<br />

The Session object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107<br />

Session state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107<br />

Session timeout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108<br />

Event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108<br />

Creating a dynamic URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109<br />

Creating a static URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113<br />

Identification methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113<br />

Summary of Session object methods . . . . . . . . . . . . . . . . . . . . . . .114<br />

The Request object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117<br />

Retrieving field values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117<br />

Retrieving cookie values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .121<br />

Retrieving attachments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122<br />

Retrieving environment variables . . . . . . . . . . . . . . . . . . . . . . . . . .122<br />

Summary of Request object methods . . . . . . . . . . . . . . . . . . . . . . .123<br />

The Response object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />

Writing headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126<br />

Setting cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127<br />

Writing the HTML output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .129<br />

Summary of Response object methods . . . . . . . . . . . . . . . . . . . . . .130<br />

6 Forms-Related <strong>Programming</strong><br />

What’s in this chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />

Calling a subroutine from a form. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134


Contents<br />

Writing the subroutine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .138<br />

Associating the subroutine with a form . . . . . . . . . . . . . . . . . . . . .139<br />

Attaching a file to a form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

Adding a File Upload control to a page . . . . . . . . . . . . . . . . . . . . .141<br />

Working with a file attachment . . . . . . . . . . . . . . . . . . . . . . . . . . .142<br />

Custom Form Handler widgets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />

Writing the form-handler function . . . . . . . . . . . . . . . . . . . . . . . .145<br />

Creating the custom form-handler widget . . . . . . . . . . . . . . . . . . .152<br />

7 Form Fields <strong>Programming</strong><br />

What’s in this chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

Setting form-field properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

Examples of setting form-field properties . . . . . . . . . . . . . . . . . . . .156<br />

Setting and getting form-field properties . . . . . . . . . . . . . . . . . . . .161<br />

FormField properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .163<br />

Button properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165<br />

Checkbox properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167<br />

Combo properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168<br />

FileUpload properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168<br />

ListElement and Listbox classes . . . . . . . . . . . . . . . . . . . . . . . . . . .169<br />

Radiobutton properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .175<br />

StaticText properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .176<br />

TextArea properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178<br />

Textbox properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178<br />

Calculating form-field values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180<br />

Calling user code from a button. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183<br />

Code associated with a button versus code associated with a form<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183<br />

Configuring a button to call user code . . . . . . . . . . . . . . . . . . . . . .184<br />

8 Data-Agent <strong>Programming</strong><br />

Data agents and command handlers . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />

Calling data-agent methods at runtime . . . . . . . . . . . . . . . . . . . . . . . . 190<br />

Setting a data agent’s command . . . . . . . . . . . . . . . . . . . . . . . . . . .190<br />

Performing a data-agent action . . . . . . . . . . . . . . . . . . . . . . . . . . . .192<br />

Getting and setting the values of a data agent’s fields . . . . . . . . . .196<br />

vii


Contents<br />

viii<br />

Getting a reference to a data agent’s connection . . . . . . . . . . . . . .198<br />

Dealing with recordsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .198<br />

Getting parameters to stored procedures . . . . . . . . . . . . . . . . . . . .202<br />

Refreshing a data agent’s data . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203<br />

Sorting records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204<br />

Filtering records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205<br />

Handling errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .210<br />

Enabling tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .210<br />

The structure of a command handler. . . . . . . . . . . . . . . . . . . . . . . . . . 212<br />

Modifying a command handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216<br />

Where to add code to a command handler . . . . . . . . . . . . . . . . . .216<br />

Examples of adding code to a command handler . . . . . . . . . . . . .217<br />

Changing the flow of control in a command handler . . . . . . . . . .225<br />

Example of changing the flow of control . . . . . . . . . . . . . . . . . . . .227<br />

9 <strong>Programming</strong> with the Connection Manager<br />

The DMConnectionManager class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230<br />

Opening a connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230<br />

Opening a shared connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . .231<br />

Opening a private connection . . . . . . . . . . . . . . . . . . . . . . . . . . . .232<br />

Closing a connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232<br />

Connections in HAHTtalk Basic projects . . . . . . . . . . . . . . . . . . . . . . . 233<br />

10 Working with Client-side Scripts<br />

Introduction to client-side scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236<br />

Types of client-side scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />

Choosing a scripting language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />

Client-side scripts and the HTML editor . . . . . . . . . . . . . . . . . . . . . . . 240<br />

Browsing the object model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .241<br />

Configuring the Client Scripts view . . . . . . . . . . . . . . . . . . . . . . . .242<br />

Writing in-line scripts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243<br />

Writing script functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244<br />

HTML tags for client-side scripts . . . . . . . . . . . . . . . . . . . . . . . . . . .246


Contents<br />

About event handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247<br />

Scripting event handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .247<br />

Browser compatibility issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249<br />

The browser object model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250<br />

Strategies for handling browser incompatibilities . . . . . . . . . . . . .250<br />

About Dynamic HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252<br />

Moving objects using DTHML . . . . . . . . . . . . . . . . . . . . . . . . . . . .252<br />

Why use Netscape Layers for positioning? . . . . . . . . . . . . . . . . . . .253<br />

JavaScript example for browser-independent DHTML . . . . . . . . . .255<br />

Scripts with server-side expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . 257<br />

11 Using HtmlOut Routines or the HtmlOut Class<br />

Creating HTML at runtime. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260<br />

The HAHTtalk Basic HtmlOut library. . . . . . . . . . . . . . . . . . . . . . . . . . 260<br />

Using the HAHTtalk Basic HtmlOut library . . . . . . . . . . . . . . . . . .261<br />

HAHTtalk Basic example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262<br />

The HtmlOut Java class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264<br />

Java example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .265<br />

12 Access Control<br />

What is access control?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270<br />

Granting privileges: the basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271<br />

Controlling access to a page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .271<br />

Controlling access to part of a page . . . . . . . . . . . . . . . . . . . . . . . .274<br />

Displaying a custom error page . . . . . . . . . . . . . . . . . . . . . . . . . . . .275<br />

Granting privileges to logged-in users . . . . . . . . . . . . . . . . . . . . . . . . . 276<br />

Authenticating users with the Login widget . . . . . . . . . . . . . . . . . .277<br />

Authenticating users with the Authentication interface . . . . . . . .286<br />

Letting the Web server authenticate users . . . . . . . . . . . . . . . . . . .288<br />

Granting privileges on a user-name basis . . . . . . . . . . . . . . . . . . . . . . 289<br />

Using a Login widget and a database privilege repository . . . . . . .290<br />

Using a Login widget and a nondatabase privilege repository . . . .291<br />

Using the Server Object Model . . . . . . . . . . . . . . . . . . . . . . . . . . . .293<br />

ix


Contents<br />

x<br />

Server Object Model methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296<br />

Session class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .297<br />

Privileges class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .298<br />

Application class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .298<br />

Authentication interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .299<br />

UserProfile interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .299<br />

13 Connecting to COM Objects<br />

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302<br />

Calling DLLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302<br />

Declaring a DLL in HAHTtalk Basic . . . . . . . . . . . . . . . . . . . . . . . .302<br />

Example DLL declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .303<br />

Mapping HAHTtalk Basic types to DLL data types . . . . . . . . . . . . .304<br />

Using COM objects with HAHTtalk Basic . . . . . . . . . . . . . . . . . . . . . . 305<br />

The CreateObject function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .305<br />

A COM Server example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306<br />

Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307<br />

HAHTMem methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307<br />

14 <strong>HAHTsite</strong> CORBA Capabilities<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310<br />

What is CORBA? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .310<br />

What does <strong>HAHTsite</strong>/CORBA interoperation mean? . . . . . . . . . . .310<br />

Using CORBA with the <strong>HAHTsite</strong> <strong>IDE</strong> . . . . . . . . . . . . . . . . . . . . . . . . . 311<br />

Handling CORBA projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .311<br />

Setting options for CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312<br />

<strong>HAHTsite</strong> as a CORBA client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315<br />

Example: Building a <strong>HAHTsite</strong> CORBA client . . . . . . . . . . . . . . . . .316<br />

<strong>HAHTsite</strong> as a traditional CORBA server . . . . . . . . . . . . . . . . . . . . . . . 318<br />

Example: Using CORBA to hold <strong>HAHTsite</strong> global state . . . . . . . . .319<br />

CORBA and the <strong>HAHTsite</strong> Server Object Model . . . . . . . . . . . . . . . . . 321<br />

Using the <strong>HAHTsite</strong> Server Object Model in a <strong>HAHTsite</strong> CORBA server<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .321


Contents<br />

Accessing the <strong>HAHTsite</strong> Server Object Model from a CORBA client<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .322<br />

Client/server communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . .325<br />

Example: Using CORBA in a session initiated via HTTP . . . . . . . .325<br />

Example: Initiating a <strong>HAHTsite</strong> application session with CORBA .327<br />

Other Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328<br />

Interoperability with other ORBS . . . . . . . . . . . . . . . . . . . . . . . . . .328<br />

Using CORBA with HAHTtalk Basic . . . . . . . . . . . . . . . . . . . . . . . .329<br />

VisiBroker installation and configuration . . . . . . . . . . . . . . . . . . . .329<br />

VisiBroker SmartAgent and the CORBA Naming Service . . . . . . . .329<br />

VisiBroker GateKeeper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .329<br />

References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330<br />

15 Debugging Server-side Code<br />

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332<br />

Requirements for debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332<br />

A special case: debugging HAHTtalk Basic stand-alone programs .333<br />

Starting a debugging session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333<br />

Debugging a code page. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336<br />

Executing code in the debugger . . . . . . . . . . . . . . . . . . . . . . . . . . .336<br />

Single-stepping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .337<br />

Procedure-stepping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338<br />

Using breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338<br />

The debug windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340<br />

Debug output panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .341<br />

Variable window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .341<br />

Watch window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .343<br />

Call Stack window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .344<br />

Threads window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .345<br />

A <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348<br />

WebApp properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348<br />

WebApp methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350<br />

xi


Contents<br />

xii<br />

Pseudo-methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .352<br />

B <strong>HAHTsite</strong> 3.x Data Management<br />

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356<br />

DataSets and data agents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356<br />

Accessing and changing DataSet properties at runtime . . . . . . . . .356<br />

DataSet control functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357<br />

Writing user-defined DataSet functions . . . . . . . . . . . . . . . . . . . . .358<br />

Accessing and changing form-control properties at runtime . . . . . . . 358<br />

Connection-manager functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359<br />

C Code Examples<br />

Calling a subroutine as a form action . . . . . . . . . . . . . . . . . . . . . . . . . 362<br />

Modifying a command handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370<br />

Writing a custom authentication class. . . . . . . . . . . . . . . . . . . . . . . . . 373<br />

D ADO Primer<br />

What’s in this appendix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376<br />

Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376<br />

Opening a connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .376<br />

Executing a command against a connection . . . . . . . . . . . . . . . . .378<br />

Closing a connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .379<br />

Recordsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380<br />

Creating a recordset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .380<br />

Iterating through the records in a recordset . . . . . . . . . . . . . . . . . .381<br />

Finding a specific record in a recordset . . . . . . . . . . . . . . . . . . . . . .382<br />

Reading a record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .382<br />

Updating a record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .383<br />

Inserting a record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .383<br />

Deleting a record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .384<br />

Closing a recordset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .385<br />

E ADO Extensions<br />

What’s in this appendix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388


Contents<br />

Extensions to the Java interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388<br />

ADO tracing in Java projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .388<br />

Additional appendChunk methods . . . . . . . . . . . . . . . . . . . . . . . .390<br />

The Variant data type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .390<br />

Extensions to the HAHTtalk Basic interface. . . . . . . . . . . . . . . . . . . . . 391<br />

ADO tracing in HAHTtalk Basic projects . . . . . . . . . . . . . . . . . . . .391<br />

Functions for managing connections . . . . . . . . . . . . . . . . . . . . . . .391<br />

xiii


Contents<br />

xiv


About This Book<br />

The <strong>HAHTsite</strong> <strong>IDE</strong> <strong>Programming</strong> <strong>Guide</strong> explains how to extend your <strong>HAHTsite</strong> ®<br />

applications programmatically. Chapter 1, “Introduction,” gives you an<br />

overview of the programming capabilities available within <strong>HAHTsite</strong>. If you’re<br />

developing a Java application, continue with Chapter 2, “Working with Java<br />

Projects.” If you’re developing a HAHTtalk Basic application, look at the<br />

corresponding chapter, Chapter 3, “Working with HAHTtalk Basic Projects.”<br />

Then read Chapter 5, “<strong>HAHTsite</strong> Server Object Model,” which describes the<br />

programming model that underlies a <strong>HAHTsite</strong> application, including the<br />

Application, Session, Page, Request, and Response objects. This chapter, and<br />

all the chapters that follow, contain both HAHTtalk Basic and Java examples.<br />

However, the functionality is the same, regardless of which language you use.<br />

The table below lists each chapter in the <strong>HAHTsite</strong> <strong>IDE</strong> <strong>Programming</strong> <strong>Guide</strong>,<br />

along with its contents.<br />

Chapter/Appendix Contents<br />

Chapter 1, “Introduction” A high-level introduction to the <strong>IDE</strong>’s Server<br />

Object Model, data management model, and<br />

COM, CORBA, and client-scripting capabilities.<br />

Chapter 2, “Working with Java<br />

Projects”<br />

Chapter 3, “Working with<br />

HAHTtalk Basic Projects”<br />

Chapter 4, “Calling Server-side<br />

Java from HAHTtalk Basic”<br />

Chapter 5, “<strong>HAHTsite</strong> Server<br />

Object Model”<br />

Chapter 6, “Forms-Related<br />

<strong>Programming</strong>”<br />

Chapter 7, “Form Fields<br />

<strong>Programming</strong>”<br />

Information for developers who are adding<br />

server-side code to a Java project.<br />

Information for developers who are adding<br />

server-side code to a HAHTtalk Basic project.<br />

How to call Java from a HAHTtalk Basic project.<br />

Explanation of the built-in objects in <strong>HAHTsite</strong>’s<br />

Server Object Model.<br />

Customizing your application’s form-handling<br />

capabilities. For HAHTtalk Basic projects, adding<br />

a custom form handler.<br />

Writing code that affects form fields and using a<br />

button to call user-written code.<br />

xv


About This Book<br />

Chapter/Appendix Contents<br />

Chapter 8, “Data-Agent<br />

<strong>Programming</strong>”<br />

Chapter 9, “<strong>Programming</strong> with<br />

the Connection Manager”<br />

Chapter 10, “Working with<br />

Client-side Scripts”<br />

Chapter 11, “Using HtmlOut<br />

Routines or the HtmlOut<br />

Class”<br />

xvi<br />

Calling data-agent methods at runtime;<br />

customizing <strong>HAHTsite</strong>’s command handlers.<br />

Opening and closing shared and private<br />

connections using the DMConnectionManager<br />

class.<br />

Adding JavaScript or VBScript to your<br />

application.<br />

Using <strong>HAHTsite</strong> functions/methods to create<br />

HTML at runtime.<br />

Chapter 12, “Access Control” Controlling access to <strong>HAHTsite</strong> project items by<br />

assigning a set of required privileges to the<br />

items.<br />

Chapter 13, “Connecting to<br />

COM Objects”<br />

Chapter 14, “<strong>HAHTsite</strong> CORBA<br />

Capabilities”<br />

Chapter 15, “Debugging<br />

Server-side Code”<br />

Appendix A, “<strong>HAHTsite</strong> 3.x<br />

WebApp Methods and<br />

Properties”<br />

Appendix B, “<strong>HAHTsite</strong> 3.x<br />

Data Management”<br />

Accessing DLLs and COM/DCOM objects from<br />

<strong>HAHTsite</strong> applications.<br />

Building <strong>HAHTsite</strong> applications that are CORBA<br />

clients or servers.<br />

Using <strong>HAHTsite</strong>’s remote debugger to inspect<br />

code running on the Application Server.<br />

How WebApp properties and methods (from<br />

<strong>HAHTsite</strong> 3.x) relate to objects in the Server<br />

Object Model.<br />

How programming database applications differs<br />

between <strong>HAHTsite</strong> 3.x and <strong>HAHTsite</strong> 4.0.<br />

Appendix C, “Code Examples” A set of sample functions/methods that<br />

supplement those in the text.<br />

Appendix D, “ADO Primer” How to perform basic operations using ADO<br />

connections and recordsets.<br />

Appendix E, “ADO Extensions” The few ways in which <strong>HAHTsite</strong>’s ADO<br />

implementation differs from the standard.


Who is this book for?<br />

About This Book<br />

This book is written for use by <strong>HAHTsite</strong> programmers. It assumes that you:<br />

know how to use the <strong>HAHTsite</strong> <strong>IDE</strong> to create Web applications.<br />

have an understanding of how the <strong>HAHTsite</strong> <strong>IDE</strong> creates Web<br />

applications, how <strong>HAHTsite</strong> applications are structured, and how<br />

applications interact with the <strong>HAHTsite</strong> Application Server.<br />

know how to use either the Visual Basic or Java programming language.<br />

are familiar with HTML.<br />

Prerequisites<br />

In order to build a Java project that contains dynamic pages, or a HAHTtalk<br />

Basic project that calls server-side Java, you must have a Java compiler<br />

installed (not included with the <strong>HAHTsite</strong> software). See the ReadMe file for<br />

information on downloading a Java compiler.<br />

Conventions<br />

This book uses several conventions, which are described here.<br />

<strong>HAHTsite</strong> installation directory<br />

The directory into which you install the <strong>HAHTsite</strong> <strong>IDE</strong> is called the <strong>HAHTsite</strong><br />

installation directory. This book uses the variable <strong>HAHTsite</strong>InstallDir as a<br />

placeholder for the <strong>HAHTsite</strong> installation directory — for example,<br />

C:\<strong>HAHTsite</strong>. When you see this variable, you should replace it with the name<br />

of the <strong>HAHTsite</strong> installation directory on your system.<br />

Continuation characters in sample code<br />

Some lines of sample code are too long to fit on one line. For HAHTtalk Basic<br />

code, this book uses the line-continuation character (“_”) at the end of a line.<br />

For example:<br />

Function Create (instanceHandle As Long, createTime As Integer, _<br />

scopeCount As Long) As Integer<br />

xvii


About This Book<br />

Screen images<br />

The <strong>HAHTsite</strong> <strong>IDE</strong>/IP runs on Windows 95, Windows 98, and Windows NT.<br />

Depending on which operating system you are using, the “look” of the screens<br />

might be slightly different from what you see in this book. However, the<br />

screens’ contents are the same.<br />

Other <strong>HAHTsite</strong> documentation<br />

The <strong>HAHTsite</strong> <strong>IDE</strong> includes this additional documentation:<br />

xviii<br />

<strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong><br />

<strong>HAHTsite</strong> <strong>IDE</strong> and IP Installation <strong>Guide</strong><br />

<strong>HAHTsite</strong> Widget <strong>Programming</strong> <strong>Guide</strong><br />

“Getting Started”<br />

The <strong>HAHTsite</strong> <strong>IDE</strong>/IP also includes an introduction to <strong>HAHTsite</strong>, lessons in<br />

using <strong>HAHTsite</strong>, and sample (HAHT_Intro) projects in Java and HAHTtalk<br />

Basic. Choose Getting Started from the Help menu.<br />

Online documentation<br />

In addition to the printed books, you can use the <strong>IDE</strong>/IP’s online help system.<br />

As well as context-sensitive help for each of the dialogs, the online help system<br />

includes:<br />

Overview information about the <strong>IDE</strong>/IP.<br />

Step-by-step instructions on how to use the <strong>IDE</strong>/IP’s features.<br />

Reference pages for the HAHTtalk Basic language, <strong>HAHTsite</strong>’s Server<br />

Object Model, and the SQL Assistant.<br />

Information about using HAHTtalk Basic’s Dialog Editor (used in<br />

building widgets).<br />

To open the help system, choose Contents and Index from the Help menu.


<strong>HAHTsite</strong> OLE Interface <strong>Guide</strong><br />

About This Book<br />

The <strong>HAHTsite</strong> <strong>IDE</strong> provides an OLE interface that you can access from your<br />

custom widgets. The OLE objects and methods are described in the <strong>HAHTsite</strong><br />

OLE Interface <strong>Guide</strong>, which you can access from the <strong>IDE</strong>’s Help menu. The<br />

<strong>HAHTsite</strong> OLE Interface <strong>Guide</strong> is an HTML document.<br />

The <strong>HAHTsite</strong> OLE Interface <strong>Guide</strong> is also installed as a <strong>HAHTsite</strong> project (in<br />

<strong>HAHTsite</strong>InstallDir\sdk\oleapi). This enables you to add comments to the<br />

guide or to copy the guide’s examples into the <strong>HAHTsite</strong> <strong>IDE</strong> and test them.<br />

Other <strong>HAHTsite</strong> products<br />

In addition to the <strong>IDE</strong> and the IP, the <strong>HAHTsite</strong> family of products includes the<br />

<strong>HAHTsite</strong> Application Server, which works with any Web server to execute<br />

<strong>HAHTsite</strong> applications. The Application Server runs on the Windows NT,<br />

HP/UX, Solaris, and AIX operating systems. It executes application logic,<br />

enables complete access to multiple data sources, maintains session<br />

information, and dynamically generates HTML pages.<br />

HAHT Software’s commitment to you<br />

We want you to be completely satisfied with your HAHT Software products.<br />

If you have questions about <strong>HAHTsite</strong>, the <strong>HAHTsite</strong> <strong>IDE</strong>, the <strong>HAHTsite</strong> IP, or<br />

the <strong>HAHTsite</strong> Application Server, you can contact HAHT Software in the<br />

following ways:<br />

Telephone<br />

(919) 786-5200 Technical Support (Voice)<br />

(919) 786-5252 Technical Support (FAX)<br />

(888) 438-4248 Sales (Voice—in the USA)<br />

(919) 786-5100 Office (Voice)<br />

(919) 786-5250 Office (FAX)<br />

xix


About This Book<br />

Email<br />

xx<br />

info@haht.com General Information<br />

sales@haht.com Sales<br />

support@haht.com Support<br />

World Wide Web<br />

• www.haht.com


Introduction<br />

1<br />

Overview ...........................................................................................................2<br />

<strong>HAHTsite</strong> Server Object Model.........................................................................3<br />

The project package.....................................................................................3<br />

The datamanager package ...........................................................................4<br />

The form package ........................................................................................4<br />

The access package ......................................................................................5<br />

The corba package .......................................................................................5<br />

Data-management API......................................................................................5<br />

ActiveX Data Objects classes .......................................................................6<br />

Relationship between ADO and SOM classes .............................................6<br />

Data management in HAHTtalk Basic projects ..........................................7<br />

Client-side scripting..........................................................................................8<br />

CORBA capabilities ...........................................................................................9<br />

Access to COM/DCOM objects ........................................................................9<br />

Remote debugging ..........................................................................................10<br />

1


Chapter 1: Introduction<br />

Overview<br />

Using <strong>HAHTsite</strong>’s Integrated Development Environment (<strong>IDE</strong>), you can create<br />

many Web applications without writing any code. You describe your<br />

application’s requirements using the <strong>IDE</strong>’s graphical user interface, and<br />

<strong>HAHTsite</strong>’s code generator creates the code for your application.<br />

Of course, code generators can’t account for every contingency. Therefore,<br />

<strong>HAHTsite</strong> makes it easy for you to add your own code to this generated code<br />

as needed. In <strong>HAHTsite</strong>, you can add such code using either Java or HAHTtalk<br />

Basic (which is syntax compatible with Visual Basic). A Java virtual machine<br />

(either Microsoft or Sun) and a Basic virtual machine are embedded in the<br />

Application Server for the execution of code written in these languages.<br />

Being able to add Java or HAHTtalk Basic code to <strong>HAHTsite</strong> pages is useful in<br />

itself, but the real power of this language support lies in the fact that you can<br />

use these languages to call a tremendous amount of existing code. For<br />

instance, from either Java or HAHTtalk Basic, your Web application can call<br />

other code in DLLs, UNIX shared libraries, Java classes, or practically anything<br />

else that has a callable API. Of particular importance are the Java packages and<br />

Basic libraries supplied with <strong>HAHTsite</strong>.<br />

First, <strong>HAHTsite</strong> includes a set of Java packages that make up what is called its<br />

Server Object Model. The classes in these packages can be called from both<br />

Java and HAHTtalk Basic projects and enable you to:<br />

2<br />

obtain information about the Application Server, about your application<br />

and individual user sessions, and about the data being passed back and<br />

forth between the Application Server and the Web server<br />

establish connections with relational and nonrelational data sources and<br />

to manage the ActiveX Data Objects (ADO) recordsets obtained via those<br />

connections<br />

control the form fields in your application’s forms<br />

provide access control for the pages in your application<br />

make your application a CORBA server<br />

<strong>HAHTsite</strong> also includes a Java package and a Basic library that enable you to<br />

use the ActiveX Data Objects API for data management.


<strong>HAHTsite</strong> Server Object Model<br />

Chapter 1: Introduction<br />

The classes in the <strong>HAHTsite</strong> Server Object Model (SOM) are implemented in<br />

Java. At runtime, Java projects access SOM objects as real Java objects, and can<br />

subclass SOM classes and override SOM methods. You can also access the SOM<br />

from HAHTtalk Basic projects using HAHTtalk Basic syntax. However, some<br />

limitations apply; for example, SOM objects cannot be subclassed in a<br />

HAHTtalk Basic project. The classes in the SOM give you many capabilities,<br />

including the ability to examine requests sent from a Web browser, to manage<br />

data sources, and to protect information from unauthorized access.<br />

The principal packages in the SOM are:<br />

com.haht.project<br />

com.haht.project.datamanager<br />

com.haht.project.form<br />

com.haht.access<br />

com.haht.corba<br />

The project package<br />

The project package contains a number of built-in objects, which are<br />

available in every <strong>HAHTsite</strong> application. These objects are similar to the<br />

built-in objects in Microsoft’s Active Server Pages. They let you control the<br />

data passed to and from a Web browser client and to get information about the<br />

application, the Web server, and the Application Server.<br />

When you run a <strong>HAHTsite</strong> application, each instance of a dynamic page is a<br />

Page object. You can also create dynamic pages programmatically, by<br />

implementing the HAHTPage interface in a Java project, or by implementing a<br />

Basic subroutine that generates HTML in a HAHTtalk Basic project. In addition<br />

to Page objects, each <strong>HAHTsite</strong> application contains these built-in objects:<br />

The Server object contains methods for storing variables that may be<br />

shared among multiple applications (as long as they are running in the<br />

same process on the Application Server).<br />

The Application object has information about the current application, as<br />

well as event handlers that are triggered when an application or session<br />

starts or ends.<br />

The Session object has information about the current session, which is<br />

defined as a browser client using the application. There is a separate<br />

Session object for each client. It also has two event handlers, called<br />

when a session is created and just before it’s destroyed.<br />

3


Chapter 1: Introduction<br />

4<br />

The Request object’s methods retrieve data the client browser sends to<br />

the Web server — for example, form data or cookies.<br />

The Response object’s methods generate HTML that the Web server sends<br />

to the browser.<br />

For further information about the project package, see Chapter 5, “<strong>HAHTsite</strong><br />

Server Object Model.”<br />

The datamanager package<br />

The most important classes in the datamanager package are:<br />

DataAgent<br />

DMConnectionManager<br />

The DataAgent class represents an ADO recordset and enables you perform a<br />

variety of actions against that recordset. For example, you can use this class’s<br />

methods to set the command that returns the recordset, to perform an action<br />

such as updating a record, or to get or set the value of a field in the recordset’s<br />

current record.<br />

The DMConnectionManager class includes methods for opening ADO<br />

connections to relational or nonrelational data sources. These connections<br />

can be shared by two or more data agents within a session to lessen the<br />

amount of time your application spends establishing connections. Or they can<br />

be private so that you can perform transactions on the connection.<br />

The DataAgent and DMConnectionManager classes are discussed in detail in<br />

Chapter 8, “Data-Agent <strong>Programming</strong>” and Chapter 9, “<strong>Programming</strong> with<br />

the Connection Manager,” respectively.<br />

The form package<br />

The form package contains classes that represent the different types of form<br />

fields that you can place in a form, such as text boxes, combo boxes, and<br />

submit buttons. The methods of these classes enable you to perform tasks such<br />

as:<br />

setting a form field’s value<br />

setting a text box’s width<br />

setting the selected status of a list-box element<br />

Basically, all the form-field attributes that you can set in the <strong>IDE</strong>, you can also<br />

set at runtime.


Chapter 1: Introduction<br />

For further information about the form package, see Chapter 7, “Form Fields<br />

<strong>Programming</strong>.”<br />

The access package<br />

The access package includes classes that enable you to control access to<br />

<strong>HAHTsite</strong> pages. A Privileges class provides a container for a set of<br />

user-defined privileges, and each session contains a Privileges object. In<br />

addition, <strong>HAHTsite</strong> pages have associated with them a set of privileges. At<br />

runtime, the Application Server determines whether a session has access to a<br />

particular page in an application by comparing the privileges in the session’s<br />

Privileges object with the page’s privileges. The session can access a page<br />

only if all of that page’s required privileges are contained in its Privileges<br />

object.<br />

This package also contains classes that enable you to:<br />

authenticate a user login<br />

retrieve a set of privileges from a repository by user name<br />

Chapter 12, “Access Control,” provides a complete explanation of how to use<br />

the classes in this package.<br />

The corba package<br />

The corba package enables you to create a <strong>HAHTsite</strong> application that plays the<br />

role of a CORBA server. Using the CORBA interface, clients can create sessions<br />

and invoke Java object methods. This CORBA interface enables applets<br />

running in a browser to communicate directly with the Application Server,<br />

bypassing the Web server. It also enables other CORBA applications in the<br />

corporate IT infrastructure to invoke services from the <strong>HAHTsite</strong> Application<br />

Server.<br />

A <strong>HAHTsite</strong> application can also function as a CORBA client. For further<br />

information about creating CORBA clients and servers, see Chapter 14,<br />

“<strong>HAHTsite</strong> CORBA Capabilities.”<br />

Data-management API<br />

In addition to the Server Object Model, <strong>HAHTsite</strong> includes both a Java package<br />

and a Basic library that provide a data-management API based on Microsoft’s<br />

ActiveX Data Objects (ADO) 2.0. Java projects use the Java classes, and<br />

5


Chapter 1: Introduction<br />

HAHTtalk Basic projects use the Basic classes. You can find documentation for<br />

both interfaces on Microsoft’s Web site (http://msdn.microsoft.com/isapi/<br />

msdnlib.idc?theURL=/library/sdkdoc/dasdk/mdwe7i0f.htm).<br />

The ADO interface has the benefit of being well known and widely used by<br />

developers and, thus, is preferable to yet another proprietary data-access<br />

model. In addition, ADO is not tied to SQL, but allows access to both relational<br />

and nonrelational data sources.<br />

ActiveX Data Objects classes<br />

As mentioned earlier, <strong>HAHTsite</strong>’s ADO interfaces are based on those of<br />

Microsoft ADO 2.0. If you’re familiar with ADO programming, you know that<br />

the principal classes in the ADO object model are:<br />

6<br />

Connection<br />

Command<br />

Recordset<br />

The Connection class represents a connection to a data source. An object of<br />

this type enables you to open and close a connection to a data source, to<br />

execute a command that returns a recordset from the data source, and to<br />

manage transactions on the connection.<br />

A Command object represents a command that queries a data source and returns<br />

a recordset. This command may be a SQL statement or some other textual<br />

command, the name of a database table, or the name of a stored procedure.<br />

A Recordset object contains the records returned over a connection following<br />

the execution of a query. Using a Recordset’s methods, you can navigate the<br />

records in the recordset, add a new row to the recordset or delete an existing<br />

record, update a record, and so on.<br />

For information on how these ADO classes relate to the Server Object Model’s<br />

DataAgent and DMConnectionManager classes, see “Relationship between ADO<br />

and SOM classes” on page 6.<br />

Relationship between ADO and SOM classes<br />

As you’ve probably noticed, there’s some overlap between the ADO object<br />

model and the Server Object Model’s DMConnectionManager and DataAgent<br />

classes. You can use either — or a combination of both — for your<br />

data-management programming.<br />

Basically, the classes in the Server Object Model (SOM) provide a layer on top<br />

of the ADO classes that makes programming easier. The DMConnectionManager


Chapter 1: Introduction<br />

class enables you to create an ADO connection, and the DataAgent class not<br />

only represents an ADO recordset, but knows about the connection and the<br />

command used to retrieve that recordset. If you use the <strong>IDE</strong> to create<br />

connections to data sources and to create data agents, <strong>HAHTsite</strong> calls methods<br />

of the DMConnectionManager class and the DataAgent class in its generated<br />

code. So some of your data-management programming can be as simple as<br />

describing your requirements in the <strong>IDE</strong>.<br />

For situations where you need to perform tasks that aren’t supported by the<br />

<strong>IDE</strong>, you can supplement the <strong>IDE</strong>’s generated code with your own code that<br />

uses the DMConnectionManager and DataAgent classes, or you can use the ADO<br />

interface directly.<br />

Data management in HAHTtalk Basic projects<br />

In HAHTtalk Basic projects, you have two options when it comes to ADO<br />

programming. You can create Basic objects by making calls like this:<br />

Dim myConn As New ADODB.Connection<br />

myConn.open "..."<br />

Or you can create Java objects by using the classes defined in the package<br />

com.haht.ado, like this:<br />

Dim myConn As Object<br />

myConn = CreateJavaObject("com.haht.ado.Connection" ...)<br />

myConn.open "..."<br />

Although both approaches are perfectly acceptable, the assumption is that<br />

Basic programmers will prefer to use Basic objects (the first approach).<br />

If you do use the Basic library for your ADO programming, make sure you<br />

understand that a Basic object and its Java counterpart are not type<br />

compatible. That is, a Basic recordset and a Java recordset do not have the<br />

same data type. Therefore, the following code will result in a type-mismatch<br />

error:<br />

Dim myRS As ADODB.Recordset<br />

.<br />

.<br />

.<br />

Set myRS = dataAgent.getRecordset()<br />

The DataAgent class is a Java class, and the getRecordset method returns a<br />

Java object. A reference to this object cannot be assigned to myRS.<br />

One other note. The Java classes DMConnectionManager and DataAgent —<br />

which are not part of the ADO object model, but define methods that return<br />

ADO objects — do not have Basic counterparts. <strong>HAHTsite</strong> does include Basic<br />

7


Chapter 1: Introduction<br />

functions that give you much of the functionality of the<br />

DMConnectionManager class. (These functions are discussed in Appendix E,<br />

“ADO Extensions.”) However, to work with data agents, you must work with<br />

Java objects.<br />

Client-side scripting<br />

Most code in a <strong>HAHTsite</strong> application is executed by the Application Server;<br />

however, <strong>HAHTsite</strong> also provides support for writing client-side scripts to be<br />

executed in the user’s browser. You can write these scripts in either JavaScript<br />

or VBScript.<br />

To help you develop scripts more easily, the <strong>HAHTsite</strong> <strong>IDE</strong> provides a Client<br />

Scripts view of each HTML page. In this view, you see a tree representation of<br />

the Document Object Model for the page. By navigating this tree, you can<br />

select specific objects that you want to associate event handlers with. For<br />

instance, you can navigate to a text box in a form and select the text box’s<br />

onChange event. You can then use a script editor window to write a script that<br />

will be executed when this event occurs.<br />

The Document Object Model window also displays properties of the currently<br />

selected object and methods that may be applied to that object. If you drag<br />

one of these properties from the Document Object Model window to the<br />

editing window, <strong>HAHTsite</strong> constructs the appropriate reference, including<br />

correct capitalization and syntax. This drag-and-drop feature makes it easier to<br />

write client scripts.<br />

One other point. The task of writing client scripts and Dynamic HTML is<br />

complicated by variations in the Document Object Models in different<br />

browsers and different browser revisions. In general, the Document Object<br />

Model has become much more sophisticated and robust in later browser<br />

revisions, but pages that use the new browser features do not work in older<br />

browsers. The <strong>HAHTsite</strong> client-script editor enables you to view a particular<br />

Document Object Model. Thus, if you select the Internet Explorer 3.0<br />

Document Object Model, <strong>HAHTsite</strong> will not display the new events and<br />

scriptable objects introduced in later versions of Internet Explorer and<br />

Netscape Navigator. This feature makes it easy to write scripts that work when<br />

the browser revision of your end users varies.<br />

For additional information about using JavaScript and VBScript in your<br />

applications, see Chapter 10, “Working with Client-side Scripts.”<br />

8


CORBA capabilities<br />

Chapter 1: Introduction<br />

The software bundled with <strong>HAHTsite</strong> includes Inprise (formerly Visigenic)<br />

VisiBroker for Java, a suite of tools for building distributed-object applications.<br />

<strong>HAHTsite</strong> applications written using the <strong>HAHTsite</strong> Server Object Model can<br />

incorporate calls to the VisiBroker interfaces and thereby act as standard<br />

CORBA objects. Using CORBA’s built-in capabilities, they can communicate<br />

with and become part of an enterprise built of distributed CORBA objects.<br />

Information from remote CORBA systems, such as mainframes, can be<br />

obtained by these CORBA-enhanced <strong>HAHTsite</strong> applications. This data can<br />

then be used in any manner within the <strong>HAHTsite</strong> application, providing a<br />

flexible, complete method to present enterprise information on the Web.<br />

In addition, there are several extensions to the <strong>HAHTsite</strong> Server Object Model<br />

that provide CORBA interfaces, allowing CORBA systems to operate directly<br />

on some <strong>HAHTsite</strong> server objects. This level of integration allows an external,<br />

non-<strong>HAHTsite</strong> application to connect as a CORBA client to a CORBA-enabled<br />

<strong>HAHTsite</strong> application acting as a CORBA server. Such a client can initiate and<br />

control a <strong>HAHTsite</strong> session, making use of session capabilities such as<br />

automatic timeout.<br />

CORBA can also provide a Java applet running in a browser the ability to<br />

communicate with a <strong>HAHTsite</strong> application without the overhead of the HTTP<br />

protocol. For applets requiring substantial or very dynamic data from the<br />

server, this can be very beneficial.<br />

Access to COM/DCOM objects<br />

In a Microsoft environment, <strong>HAHTsite</strong> also provides full access to<br />

COM/DCOM objects. This access is native and does not depend on bridges<br />

from CORBA or other distributed object systems. From HAHTtalk Basic code,<br />

COM/DCOM servers are instantiated using the standard CreateObject call.<br />

Both in-process and out-of-process servers are supported. From Java code,<br />

COM/DCOM objects can be accessed via Java wrapper classes created using<br />

tools provided with the Microsoft SDK for Java. <strong>HAHTsite</strong>’s ability to naturally<br />

and directly access COM/DCOM objects makes it easy to interface your<br />

<strong>HAHTsite</strong> application to other software products or custom code written for<br />

the Microsoft environment.<br />

For additional information, see Chapter 13, “Connecting to COM Objects.”<br />

9


Chapter 1: Introduction<br />

Remote debugging<br />

<strong>HAHTsite</strong> supports remote debugging of both Java and HAHTtalk Basic code<br />

running in the Application Server (but not both in the same debug session).<br />

The Java and HAHTtalk Basic debuggers share the same <strong>IDE</strong> interface and have<br />

equivalent function except that Java code must be published with the debug<br />

option so that debug symbols are included. (HAHTtalk Basic code can be<br />

debugged without the debug option.)<br />

Debugging <strong>HAHTsite</strong> applications is discussed in detail in Chapter 15,<br />

“Debugging Server-side Code.”<br />

10


Working with Java<br />

Projects<br />

2<br />

What’s in this chapter ....................................................................................12<br />

Adding server-side code to a Java project......................................................12<br />

In-line code ................................................................................................13<br />

Invoking an expression or a method from a dialog box .........................15<br />

Adding code in Server-side Code view .....................................................17<br />

What’s in a Java page?...............................................................................18<br />

Editing HahtApplication.java and HahtSession.java ................................25<br />

Adding Java files to a project ....................................................................26<br />

Naming conventions for Java projects ..........................................................30<br />

Calling a dynamic page from Java.................................................................30<br />

Event handling in a Java project ...................................................................31<br />

Editing and compiling Java code ...................................................................37<br />

Using the code editor ................................................................................37<br />

Compiling a Java application....................................................................38<br />

Finding compile-time errors......................................................................39<br />

Debugging a Java application....................................................................39<br />

Working with application directories .......................................................39<br />

Java options ....................................................................................................41<br />

Changing the Java file type.......................................................................41<br />

Overriding Java compiler options.............................................................42<br />

Overriding options for JAR, CAB, and ZIP files........................................43<br />

11


Chapter 2: Working with Java Projects<br />

What’s in this chapter<br />

The first half of this chapter explains how to add server-side code — that is,<br />

code that runs on the Application Server — to a Java project. The second half<br />

of the chapter explains the mechanics of working with the code editor and<br />

compiling the code.<br />

Later chapters in this book give detailed explanations, with examples, of ways<br />

you can extend your <strong>HAHTsite</strong> application programmatically. For complete<br />

information about specific Java classes and methods, refer to the online help<br />

for the Server Object Model.<br />

In addition, if you are interested in further customizing your application with<br />

client-side scripts and applets, then be sure to look at Chapter 10, “Working<br />

with Client-side Scripts,” and the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 20,<br />

“Applets and Multimedia Objects.”<br />

12<br />

Note - The examples throughout this book assume the<br />

appropriate import statements and invoke Java methods<br />

without qualifying them with the full package name — for<br />

example, they call Haht.getRequest() instead of<br />

com.haht.Haht.getRequest(). <strong>HAHTsite</strong>’s generated code<br />

uses the full qualification, to eliminate the possibility that a<br />

<strong>HAHTsite</strong> class might have the same name as another (non-<br />

<strong>HAHTsite</strong>) package you have imported. You may wish to do the<br />

same.<br />

Adding server-side code to a Java project<br />

With Java, you can easily extend the functionality of your <strong>HAHTsite</strong> Web<br />

applications beyond what you can do with HTML or CGI programs. In a<br />

<strong>HAHTsite</strong> Java project, you can use Java in these ways:<br />

1 You can add in-line code to a page, intermixed with other <strong>HAHTsite</strong><br />

elements such as text, pictures, and forms. The code can be a simple<br />

expression, a single line, or a complete block of code. See “In-line code”<br />

on page 13.<br />

2 You can insert expressions and method calls in many of the dialogs in the<br />

<strong>IDE</strong> — for example, a text box can be initialized with the value of an<br />

expression, and a form’s action can be a call to a Java method. See<br />

“Invoking an expression or a method from a dialog box” on page 15.


Chapter 2: Working with Java Projects<br />

3 You can insert code in predefined places within the Java source for a page,<br />

using the HTML editor’s Server-side Code view. See “Adding code in<br />

Server-side Code view” on page 17.<br />

4 You can modify or add to the source code for the HahtApplication and<br />

HahtSession classes. See “Editing HahtApplication.java and<br />

HahtSession.java” on page 25.<br />

5 You can create or import separate Java source files, with classes and<br />

methods that can be shared by all of the pages in an project and that can<br />

be reused in other projects. In addition, you can import Java class files as<br />

well as JAR, CAB, and ZIP files. See “Adding Java files to a project” on page<br />

26.<br />

<strong>HAHTsite</strong> Server Object Model<br />

Much of this book describes classes and methods in <strong>HAHTsite</strong>’s Server Object<br />

Model, which controls the structure of a <strong>HAHTsite</strong> Web application. With the<br />

Server Object Model, you can perform tasks such as reading data passed on the<br />

URL, writing HTML data, and controlling session timeout, as well as managing<br />

data source connections, setting form field values, and controlling access to<br />

dynamic pages.<br />

The Server Object Model is implemented in Java. However, it is equally<br />

accessible from HAHTtalk Basic projects, and the online help for the Server<br />

Object Model shows both the Java and HAHTtalk Basic syntax to call each<br />

method.<br />

External logic<br />

From your Java code, you also have access to Java classes outside the project<br />

and to capabilities such as CORBA, COM objects, and native methods. For<br />

more information, see Chapter 13, “Connecting to COM Objects” and<br />

Chapter 14, “<strong>HAHTsite</strong> CORBA Capabilities.”<br />

In-line code<br />

The ability to intermix Java code with other elements (such as text, pictures,<br />

widgets, and form elements) gives you a powerful tool for dynamically<br />

changing the content of Web pages. You can use this technique for many<br />

purposes — for example:<br />

to control the flow of logic on the page<br />

13


Chapter 2: Working with Java Projects<br />

14<br />

to create “internationalized” pages that contain text in different<br />

languages from which a user can select<br />

to retrieve values passed on the URL from a calling page<br />

to override the value of a form field at runtime<br />

In-line code is typically used for short expressions and statements. To<br />

maintain the WYSIWYG look of your pages, you’ll probably want to minimize<br />

the amount of code that you place directly onto a page. You can do this by<br />

creating classes and methods in a project’s source pages and calling them from<br />

your Web pages. With this approach, you can also share classes and methods<br />

among the project’s Web pages.<br />

In this example, a data agent (represented by the icon at the top of the page)<br />

populates a form with fields from a database. However, between the data agent<br />

and the form, note the code that disables the Next button if we’ve reached end<br />

of file.<br />

Besides adding entire lines of code, you can also add expressions. An expression<br />

can include variables, constants, operators, and methods, as long as it resolves<br />

to a single value. Here are two examples:<br />

a * b / c<br />

aRequest.getURLField("txtCity")<br />

In the Java source, the <strong>IDE</strong> includes the expression in an out.print statement.


To add a Java expression to an HTML page<br />

Chapter 2: Working with Java Projects<br />

1 On the page, click where you want the expression to appear.<br />

2 Click the Server-side Expression button .<br />

3 Type the expression.<br />

4 By default, expressions are displayed in red in the editor, although you can<br />

change this setting using Tools > Options.<br />

To add a statement to an HTML page<br />

1 On the page, click where you want the statement to appear.<br />

2 Click the Server-side Statement button .<br />

3 Type one or more statements.<br />

4 By default, statements are displayed in blue in the HTML editor.<br />

To convert existing text to an expression or statement<br />

1 Select the text you want to convert.<br />

2 Click either the Server-side Expression button or the Server-side<br />

Statement button . Or choose Edit > Character, click the Script tab, and<br />

then select the type of expression or statement you want to create.<br />

To format the output of an expression or statement<br />

You can format the output of a Java expression or statement, just as you can<br />

format text that you type directly on the page.<br />

1 Select the paragraph or characters you want to affect.<br />

2 To modify the paragraph properties, choose Edit > Paragraph... or make a<br />

selection from the Paragraph Styles toolbar.<br />

3 To modify the character properties, choose Edit > Character.... or make a<br />

selection from the Character Styles toolbar. (If you modify the font color,<br />

the new color will be displayed in the browser, but not in the <strong>IDE</strong>.)<br />

Invoking an expression or a method from a dialog box<br />

The second way you can customize your project is through dialog boxes. From<br />

the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, you’re probably aware of the many places<br />

that allow you to set project item properties using an expression rather than a<br />

field name or a constant, or that allow you to call a method instead of a<br />

dynamic page as a link or form action.<br />

15


Chapter 2: Working with Java Projects<br />

Dialog box expressions<br />

To substitute an expression for a field name or constant, prefix the expression<br />

with “==”. For example, in the properties for a link, you could define the query<br />

string to contain the entry point name of the current page:<br />

callingPage=/*==getName()*/<br />

On the destination page, you could retrieve the information this way:<br />

aRequest.getURLField("callingPage")<br />

which would return packagename.class.method, like this:<br />

JavaExample.HsLinkStart.run<br />

Notice in the example the use of "/*" and "*/" bracketing the expression. You<br />

must use this construction when you want to use an expression in a<br />

name/value attribute pair, or when it appears in the middle of a script.<br />

However, if you simply want to set an attribute to the value of an expression,<br />

you can use ==expression.<br />

The expression must evaluate to a character string.<br />

16


Dialog box method calls<br />

Chapter 2: Working with Java Projects<br />

In addition to using expressions, you can call user-defined methods from<br />

several property sheets in the <strong>IDE</strong>, such as the Form Properties dialog and the<br />

Link Properties dialog. For example:<br />

A Java method can generate the binary data to display a picture, an<br />

image map, or a multimedia object.<br />

It can be the destination for a dynamic link (the value of an HREF<br />

attribute tag).<br />

It can be the default action that takes place when the user submits a<br />

form, or the action tied to one of the form’s buttons.<br />

Obviously, the content of your Java method will be determined primarily by<br />

what you want it to do, and the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong> explains any<br />

restrictions on calling a method or subroutine in the documentation for each<br />

set of properties. However, if the effect is to display a page, the class should<br />

implement the HAHTPage interface, including the run method:<br />

void run (Request aRequest, Response aResponse)<br />

The run method and its arguments are described later in this chapter; see<br />

“What’s in a Java page?” on page 18.<br />

Adding code in Server-side Code view<br />

The third way to customize your project is to add code directly to the serverside<br />

code for a page. When you include a dynamic page in a build or publish<br />

operation, the <strong>IDE</strong> generates a new Java source file for that page, extending the<br />

com.haht.project.Page class. When you add in-line code to the page, it’s<br />

inserted in the Java source, in the run method for that page. However, you may<br />

want to make other additions to the code for a page — for example, you might<br />

want to add an import statement, add some initialization code to the run<br />

method, or call your own exception handler. The HTML editor’s Server-side<br />

Code view lets you view the source code for a page, and lets you make<br />

additions, in predefined places, that will be preserved when the page is<br />

regenerated. (Note - you cannot change the generated source code; you can<br />

only add to it.)<br />

To view and add to the server-side code for a page<br />

1 Open the page in the HTML editor.<br />

2 Select View > Server-side Code, or click the Server-side Code view button<br />

.<br />

17


Chapter 2: Working with Java Projects<br />

3 Here are some points to note:<br />

18<br />

The white areas mark places where you can insert code.<br />

The grayed-out areas mark generated source code, which is read-only.<br />

If you make changes in Server-side Code view, and then return to<br />

Normal view or HTML tags view, you will see your changes reflected.<br />

If the Server-side Code view button is disabled, be sure that you have<br />

saved the page.<br />

For more information on this process, see the note that follows.<br />

Behind the scenes: How does Server-side Code view work?<br />

To keep from overwriting your additions, the <strong>IDE</strong> must keep your code<br />

separate from the code it generates. When you add code in Server-side Code<br />

view, your code is translated into HTML tags and kept in the project’s HTML<br />

file for this page. If you look at the page in HTML tags view, you will see<br />

sections like this:<br />

<br />

When you build or publish the project, the code for the dynamic page is<br />

generated from the HTML file.<br />

What’s in a Java page?<br />

For each dynamic page, the <strong>IDE</strong> generates a file (Hspagename.java) that<br />

defines a class Hspagename as a subclass of Page. The source code for each<br />

dynamic page has these contents:<br />

A package statement<br />

Import statements<br />

Class declaration and constructor<br />

A run method<br />

An exception handler<br />

A form handler<br />

Places to add classes and methods<br />

The following sections explain each of these topics, using as an example the<br />

Java source for a page that simply displays the current date.


A package statement<br />

The package name is the name of the project.<br />

package ExamplProj;<br />

Chapter 2: Working with Java Projects<br />

For more information about package names, see “Naming conventions for<br />

Java projects” on page 30.<br />

Import statements<br />

Each page source file imports several packages, including the <strong>HAHTsite</strong><br />

packages for the Server Object Model and for data management. You can add<br />

your own import statements using the HTML editor’s Server-side Code view.<br />

////////////////////////////////////////////////////////////////<br />

// IMPORTS<br />

////////////////////////////////////////////////////////////////<br />

import com.haht.*;<br />

import com.haht.project.*;<br />

import com.haht.io.*;<br />

import com.haht.project.form.*;<br />

import com.haht.project.datamanager.*;<br />

import com.haht.ado.Abstract.*;<br />

import java.io.*;<br />

import java.util.*;<br />

// custom imports<br />

import com.haht.access.*;<br />

import java.text.*;<br />

Class declaration and constructor<br />

Each page has a constructor, called once per page per session to create the page<br />

object. If the page contains form fields, they are initialized here. You can also<br />

add custom code to the constructor.<br />

Notice the class declaration: the page name, which is simply ShowDate.html<br />

in the <strong>IDE</strong>, has become the class HsShowDate in the Java source for the page.<br />

For more information on dynamic page names, see “Naming conventions for<br />

Java projects” on page 30. You can add “implements” clauses if the class<br />

implements any additional interfaces.<br />

19


Chapter 2: Working with Java Projects<br />

The constructor also gets references to both the Application object and the<br />

Session object — references you can use anywhere in a dynamic page. These<br />

references are very useful in accessing application-level and session-level<br />

variables.<br />

A run method<br />

Each page has a run method, with two arguments: the Request object and the<br />

Response object. The run method emits any header lines — for example,<br />

20<br />

public class HsShowDate extends com.haht.project.Page<br />

// Specify implements declarations here.<br />

{<br />

/**<br />

* Default constructor for HsShowDate<br />

*<br />

**/<br />

public HsShowDate ()<br />

{<br />

hahtApplication = (HahtApplication) Haht.getApplication();<br />

hahtSession = (HahtSession) Haht.getSession();<br />

}<br />

...<br />

// Custom constructor code.<br />

Content-type: text/html<br />

Note that you can override the content-type header by another call to the<br />

Response object’s setContentType method. See “Adding content information<br />

to a header line” on page 127.<br />

After emitting header lines, the run method then sets up the basic structure of<br />

the page, which would look like this in HTML:<br />

<br />

...<br />

...<br />


Chapter 2: Working with Java Projects<br />

When you add in-line code to a page, it’s normally added here, between the<br />

and tags. (Some code — such as setting a cookie — must be<br />

output with the HTTP headers. <strong>HAHTsite</strong> automatically handles this code<br />

correctly. See “Writing headers” on page 126.)<br />

Notice the marked sections where you can add local variables, initialization<br />

code, and custom HTTP response headers (two places). You can also edit any<br />

in-line code. In this example, the page contains two lines of in-line code, to<br />

set the date.<br />

/**<br />

* Runs the page, producing HTML.<br />

*<br />

* @param aRequest - HTTP request for this page<br />

* @param aResponse - HTTP response for this page<br />

*<br />

**/<br />

public void run(com.haht.project.Request aRequest,<br />

com.haht.project.Response aResponse)<br />

{<br />

HtmlWriter out;<br />

// user-defined run() local variables<br />

try<br />

{<br />

// Initialize variables.<br />

out = aResponse.getWriter();<br />

// Custom initialization code executes before HTML<br />

// tags are generated.<br />

// Output HTTP response headers.<br />

// Custom HTTP Response Headers.<br />

aResponse.setContentType("text/html");<br />

out.print("\r\n");<br />

// More Custom HTTP Response Headers.<br />

21


Chapter 2: Working with Java Projects<br />

References to the Request and Response objects<br />

The run method, seen in the example above, has two arguments:<br />

22<br />

// Generate HTML.<br />

out.print("\r\n");<br />

out.print("\r\n");<br />

out.print(" \r\n");<br />

out.print(" ShowDate\r\n");<br />

out.print("\r\n");<br />

out.print("\r\n");<br />

out.print(" ");<br />

Date d = new Date();<br />

out.print(d);<br />

out.print("\r\n");<br />

out.print(" &nbsp;\r\n");<br />

out.print("\r\n");<br />

out.print("");<br />

// All HTML has been generated. Put cleanup code here.<br />

} // try<br />

catch (java.lang.Throwable t)<br />

{<br />

handleException(t, "HsShowDate", aRequest, aResponse);<br />

} // catch<br />

} // End of run method<br />

the Request object (aRequest), whose methods get information from the<br />

Web browser — for example, methods to read data passed in a form field<br />

or on the URL.<br />

the Response object (aResponse), whose methods send information to<br />

the Web server — for example, HTML output and cookies.<br />

The Request and Response objects are built in to your <strong>HAHTsite</strong> application,<br />

along with the Application and Session objects. Both these object references<br />

(aRequest and aResponse) will be useful in your in-line code. For example, to<br />

read a value passed in a form or on the URL, you would call<br />

aRequest.getURLField.


Chapter 2: Working with Java Projects<br />

Note - For information about using the variables and methods<br />

of the Application and Session objects, see “Calling a<br />

dynamic page from Java” on page 30. For general information<br />

on the <strong>HAHTsite</strong> Server Object Model’s built-in objects, see<br />

“Built-in objects” on page 90.<br />

A reference for writing HTML output<br />

The run method also gets a reference to the default HtmlWriter. To write HTML<br />

output programmatically, you can use statements like this:<br />

out.print(d);<br />

Of course, you can also intermix text and in-line code on a page. In the Java<br />

source, the text turns into out.print statements.<br />

An exception handler<br />

The run method of every dynamic page calls a general-purpose exception<br />

handler, handleException, to catch runtime errors and print an error message<br />

similar to this.<br />

You can override this method or add other exception handlers to your code.<br />

A form handler<br />

The Java source for each dynamic page contains a form handler that adapts to<br />

the contents of the page. At runtime, when a user submits a form, the form<br />

handler determines which button was clicked and calls the appropriate<br />

command handler.<br />

Because this page doesn’t contain a form, it has no command handlers. If it<br />

did, you would see additional places in which you can customize the<br />

command handlers by writing your own event-handling code. For more<br />

information, see Chapter 8, “Data-Agent <strong>Programming</strong>.”<br />

23


Chapter 2: Working with Java Projects<br />

Places to add classes and methods<br />

In Server-side Code view, you will see a number of marked sections where you<br />

can add classes, methods, and variables:<br />

24<br />

/**<br />

* Entry point that is called via URL when a form is<br />

* submitted from this page.<br />

*<br />

* @param aRequest - HTTP request for this page<br />

* @param aResponse - HTTP response for this page<br />

*<br />

**/<br />

public void mapFormToCmd<br />

(com.haht.project.Request aRequest,<br />

com.haht.project.Response aResponse)<br />

{<br />

boolean bCmdHandlerCalled = false;<br />

if (! bCmdHandlerCalled)<br />

{<br />

getErrors().add("Received form command did not<br />

invoke a command-handler", "form-handler");<br />

run (aRequest, aResponse);<br />

}<br />

}<br />

public, protected, and private methods<br />

static initializer code<br />

nested classes<br />

public, protected, and private member variables<br />

// user-defined public methods<br />

// protected methods<br />

// user-defined protected methods


private methods<br />

// user-defined private methods<br />

// static initializer code<br />

Chapter 2: Working with Java Projects<br />

static<br />

{<br />

// Initialization code for user-defined static variables.<br />

}<br />

// nested classes<br />

// user-defined nested classes<br />

// public member variables<br />

// user-defined public variables<br />

// protected member variables<br />

protected HahtApplication hahtApplication;<br />

protected HahtSession hahtSession;<br />

// user-defined protected variables<br />

// private member variables<br />

// user-defined private variables<br />

Editing HahtApplication.java and HahtSession.java<br />

In addition to one or more Page subclasses, your <strong>HAHTsite</strong> application<br />

includes a HahtApplication class and a HahtSession class, which you can see<br />

in your project window.<br />

25


Chapter 2: Working with Java Projects<br />

You can open these files in the code editor and add variables and methods to<br />

these classes. You can use HahtApplication to cache variables that may be<br />

shared by multiple sessions. Use HahtSession to store variables that apply<br />

across page boundaries.<br />

A session recordset is a particularly powerful use of the HahtSession object.<br />

You can update a recordset on one page and use it to populate a form on<br />

another, without reaccessing the database.<br />

Both HahtApplication and HahtSession contain event handlers that you can<br />

edit; see “Event handling in a Java project” on page 31.<br />

For more information about these files, see “Built-in objects” on page 90.<br />

26<br />

Note - Do not call Server Object Model methods from the<br />

constructors in HahtApplication and HahtSession. The Server<br />

Object Model must be initialized first. Instead, edit the<br />

onStart and onEnd methods.<br />

Adding Java files to a project<br />

The final way to add server-side Java to your project is by creating a Java source<br />

file or by importing a Java source file, class file, or JAR, CAB, or ZIP file, to be<br />

used by any of a project’s dynamic pages.<br />

In a Java project, all Java files should be stored in the Packages folder. You can<br />

use the same package name as the page files (that is, the project name), or you<br />

can create additional packages and store the Java files in subfolders under<br />

Packages.


Chapter 2: Working with Java Projects<br />

Note - If you (1) omit the package statement in a Java source<br />

page and (2) reference one of its classes from an HTML page,<br />

some compilers will generate a “class not found” compiler<br />

error. To avoid this problem, put all your source code in<br />

packages and use the appropriate package import statements.<br />

To add a new Java source page<br />

1 Choose File > New > Java Source... The New Java Source dialog appears.<br />

2 Select the type of Java code you want to create:<br />

Type Description<br />

Applet Source for a Java applet<br />

Common Java source that may be used in both server-side code<br />

and applets<br />

Server-side Java Source for Java code that will run on the server<br />

Servlet Source for a Java servlet — a Web server plug-in that<br />

allows dynamic content to be created using Java on<br />

the server side<br />

3 Click OK to open the Java source file.<br />

27


Chapter 2: Working with Java Projects<br />

To import a Java source, class, JAR, CAB, or ZIP file<br />

In addition to creating new source files in your project, you can import<br />

existing Java files, including:<br />

1 In the project window, select the folder in which you want to store the<br />

imported file. For server-side Java, files must be stored in the Packages<br />

folder. (Applets, on the other hand, are stored in the Web folder.)<br />

2 Choose File > Import File.... The Import Files dialog appears.<br />

28<br />

Type Description Extension<br />

Java source Java source code .java<br />

Class file Compiled Java code .class<br />

JAR file Java archive file, which can contain multiple<br />

files (class files, images, etc.)<br />

Java CAB file Collection of Java class files in Microsoft’s Java<br />

Cabinet format<br />

Java ZIP file Collection of Java class files in ZIP format,<br />

typically uncompressed<br />

.jar<br />

.cab<br />

.zip


3 Type or browse for one or more filenames.<br />

Chapter 2: Working with Java Projects<br />

4 Choose Copy Files or Create Shortcuts. If you want to maintain one<br />

central version of a file but use it in several projects, you may want to<br />

create a shortcut.<br />

5 In the combo box marked Import Java files as, select the type of Java code<br />

you are importing — server-side, applet, servlet, or common.<br />

6 Click OK to complete the import.<br />

For more information about imported files, including information about<br />

source control, consult the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 3,<br />

“Managing Projects.”<br />

To save a source code page<br />

1 Select File > Save. The Save Code Page As dialog appears.<br />

2 Type in a page name, or accept the default name. The suffix must be<br />

“.java”.<br />

3 To save the code page inside the project, browse within the Project Items<br />

window for the folder name you want.<br />

4 If the project is in source control, you will see an additional checkbox: Add<br />

to source control. Check this box to add this file to the source control<br />

system.<br />

5 Click OK to save your changes.<br />

To save a source code page outside the project<br />

To be called from within the project, a source code page must be saved inside<br />

the project. However, you can also save it to a file outside the project.<br />

1 Select File > Save. The Save Code Page As dialog appears.<br />

2 Click the Save to File... button. The Save As dialog appears.<br />

3 Browse for a folder location and enter a filename.<br />

4 Click OK to save your changes.<br />

29


Chapter 2: Working with Java Projects<br />

Naming conventions for Java projects<br />

<strong>HAHTsite</strong> uses certain naming conventions for Java projects. In a <strong>HAHTsite</strong><br />

Java project, project names become package names.<br />

30<br />

Project names must be unique within a site.<br />

Any valid filename can be used as a project name, with one exception:<br />

Java keywords cannot be used as project names (you’ll get an error when<br />

you create the project).<br />

When the <strong>IDE</strong> generates the package name, it turns any nonalphanumeric<br />

characters (including spaces) to underscores (_).<br />

Naming conventions for dynamic pages<br />

When the <strong>IDE</strong> generates the Java code for a dynamic page, the page becomes<br />

a Java class.<br />

All the dynamic pages in a project are placed in the same package,<br />

regardless of the directory structure you may have set up within the<br />

project. This means that page names must be unique to the entire<br />

project, since class names must be unique within a package. (Note: you<br />

can have source pages in different packages; this rule applies only to<br />

dynamic pages.)<br />

The <strong>IDE</strong> prepends “Hs" to the page name, so that a page named Welcome<br />

would become the class HsWelcome.<br />

Any valid filename can be used as a page name. When it generates the<br />

class name, the <strong>IDE</strong> converts non-alphanumeric characters (anything<br />

other than A-Z, a-z, and 0-9) to underscores. For example, Page 1.html,<br />

Page_1.html, and Page$1.html would all resolve to the class HsPage_1.<br />

Calling a dynamic page from Java<br />

When a user browses a dynamic page for the first time, <strong>HAHTsite</strong> instantiates<br />

the page object and invokes its run method. If the user returns to the same<br />

page, rather than instantiating the page again, <strong>HAHTsite</strong> uses a reference to<br />

that page.<br />

You can do the same thing in your application, when you call a dynamic page<br />

programmatically. In a Java application, you instantiate a dynamic page by<br />

calling the Session object’s returnHAHTPageObject method and passing it the


Chapter 2: Working with Java Projects<br />

fully-qualified page name (that is, packagename.classname). If the page hasn’t<br />

already been instantiated, returnHAHTPageObject instantiates the page object<br />

and returns a reference to it; otherwise, it simply returns the object reference.<br />

(If for some reason, you want a new instance of the page, then you can use new<br />

rather than returnHAHTPageObject.) You call a dynamic page by invoking its<br />

run method.<br />

This code instantiates a dynamic page called MyNewPage, in a project called<br />

ExampleProj:<br />

HAHTPage MyNewPage = hahtSession.returnHAHTPageObject<br />

("ExampleProj.HsMyNewPage");<br />

To call its run method, you would use this code:<br />

MyNewPage.run(aRequest, aResponse);<br />

Event handling in a Java project<br />

If you look at the code for HahtApplication.java and HahtSession.java,<br />

you’ll see several methods that are triggered when an application or a session<br />

starts or ends. In a Java project, you can add your own code to these six<br />

methods:<br />

Application<br />

method<br />

Description<br />

onStart Called right after a new application is created, but before any<br />

pages are run.<br />

onEnd Called just before an application is destroyed.<br />

onSessionStart Called when a new session is created, but before any pages<br />

are run. (Called for each session. This method is called before<br />

the Session object’s onStart method.)<br />

onSessionEnd Called just before a session is destroyed. (Called for each<br />

session. This method is called after the Session object’s<br />

onEnd method.)<br />

31


Chapter 2: Working with Java Projects<br />

When are these methods useful? In the Session object’s onStart method, you<br />

could populate a session recordset for use by subsequent pages in the session<br />

— for example, you might want to read in the values of a database table (a<br />

catalog, say) that’s used by several different pages. In the onEnd method, you<br />

might want to save the session state, so that you can restore it later if the user<br />

returns to the application.<br />

If onStart fails, the Application Server calls onEnd and terminates the<br />

application or session without running any pages. There are two ways for<br />

onStart to fail:<br />

32<br />

Session method Description<br />

onStart Called when a new session is created, but before any pages<br />

are run. (Called once, for the current session.)<br />

onEnd Called just before a session is destroyed. (Called once, for the<br />

current session.) Note: onEnd is called even if onStart fails.<br />

You can throw a runtime exception, such as this:<br />

throw new RuntimeException("Failed in onStart");<br />

In this case, the Application Server calls onEnd, generates a runtime error<br />

message, and terminates the session.<br />

You can edit the onStart method to produce a custom diagnostic page.<br />

Generally, after producing a diagnostic page, you want to prevent any<br />

further running of the session and any further error output from the<br />

Application Server, so you should also call the Session object’s abandon<br />

method, which calls onEnd and terminates the session.<br />

Java<br />

Response aResponse = Haht.getResponse();<br />

aResponse.setContentType("text/html");<br />

aResponse.endHeaders();<br />

aResponse.write("Exiting the session ");<br />

aResponse.write("Failed in onStart ");<br />

// Abandon the session<br />

Haht.getSession().abandon();<br />

The onEnd methods are passed an ApplicationEvent or SessionEvent object.<br />

By calling this object’s getReason method, you can determine the reason for<br />

the event. For a session ending, the available reasons are:


Chapter 2: Working with Java Projects<br />

SessionEvent.SESSION_TIMEOUT -— session timed out normally<br />

SessionEvent.SESSION_STOP_END — session was stopped by a call to the<br />

abandon method<br />

SessionEvent.SESSION_TERMINATED — session was terminated by an<br />

administrator<br />

SessionEvent.SESSION_START_ERROR — the onStart method threw an<br />

exception<br />

The example that follows uses the Application object’s onSessionStart and<br />

onSessionEnd methods to update a variable that tracks active sessions.<br />

Example: onSessionStart, onSessionEnd<br />

Suppose you want to keep track of the number of currently-active sessions in<br />

an application. At any point in the application, you want to be able to print<br />

out this information.<br />

You might begin by creating a static variable, called nActiveSessions, in the<br />

HahtApplication class. Notice two particular methods in this class —<br />

onSessionStart, which is called each time a session is started, and<br />

onSessionEnd, which is called when a session times out. You can add code to<br />

those methods to increment and decrement nActiveSessions appropriately.<br />

You’ll also want to add a method to return the value of nActiveSessions. Here<br />

is the code in the HahtApplication class (ellipses mark “boilerplate” code that<br />

has been omitted).<br />

33


Chapter 2: Working with Java Projects<br />

34<br />

Java<br />

/**<br />

* ExamplProj.HahtApplication.java<br />

**/<br />

////////////////////////////////////////////////////////////////<br />

// PACKAGE<br />

////////////////////////////////////////////////////////////////<br />

package ExamplProj;<br />

///////////////////////////////////////////////////////////<br />

// IMPORTS<br />

///////////////////////////////////////////////////////////<br />

import com.haht.*;<br />

import com.haht.project.*;<br />

/**<br />

* HahtApplication class<br />

*<br />

* Represents a <strong>HAHTsite</strong> web application.<br />

* Put customizations for an application in this class.<br />

*<br />

* This class is derived from GeneratedApplication.<br />

* GeneratedApplication is built by the <strong>HAHTsite</strong> <strong>IDE</strong><br />

* according to your project configuration.<br />

*<br />

* @version<br />

* @author<br />

*<br />

* @see ExamplProj.GeneratedApplication<br />

* @see com.haht.project.Application<br />

*<br />

**/<br />

public class HahtApplication extends<br />

ExamplProj.GeneratedApplication<br />

{<br />

/**<br />

* Default constructor for HahtApplication<br />

**/<br />

public HahtApplication()<br />

{<br />

}


Java<br />

Chapter 2: Working with Java Projects<br />

/**<br />

* Called when a new session is being created.<br />

*<br />

* @param anEvent Describes details about the event.<br />

*<br />

**/<br />

public void onSessionStart<br />

(com.haht.project.SessionEvent anEvent)<br />

{<br />

// As each session starts, increment total count<br />

nActiveSessions++;<br />

}<br />

/**<br />

* Called right before a session is destroyed.<br />

*<br />

* @param anEvent Describes details about the event.<br />

*<br />

**/<br />

public void onSessionEnd<br />

(com.haht.project.SessionEvent anEvent)<br />

{<br />

// As each session ends, decrement total count<br />

nActiveSessions--;<br />

}<br />

/**<br />

* Called when a new application is being created.<br />

*<br />

* @param anEvent Describes details about the event.<br />

*<br />

**/<br />

public void onStart(com.haht.project.ApplicationEvent<br />

anEvent)<br />

{<br />

}<br />

35


Chapter 2: Working with Java Projects<br />

Java<br />

}<br />

Now you’re ready to add some in-line code to a dynamic page. The line shown<br />

below contains text and an expression calling the method you added to return<br />

the number of active sessions. It also prints the current date and time.<br />

36<br />

/**<br />

* Called right before a application is destroyed.<br />

*<br />

* @param anEvent Describes details about the event.<br />

*<br />

**/<br />

public void onEnd(com.haht.project.ApplicationEvent<br />

anEvent)<br />

{<br />

}<br />

/*<br />

* Keep track of number of currently-active sessions<br />

*/<br />

private static int nActiveSessions=0;<br />

public int getActiveSessionCount()<br />

{<br />

return nActiveSessions;<br />

}<br />

At [insert DateTime widget] there are<br />

hahtApplication.getActiveSessionCount() active sessions.<br />

The generated code for a dynamic page automatically defines<br />

hahtApplication and hahtSession to refer to the Application and Session<br />

objects, respectively, and casts them appropriately. You can use both these<br />

references anywhere in a dynamic page. For more information, see<br />

“Application and Session references in a dynamic page” on page 92.<br />

(By the way, if you try this example, at runtime you may notice a lag between<br />

the time a user leaves the application and the time the onSessionEnd method<br />

is called. This is due to the session timeout; see “Session timeout” on page<br />

108.)


Editing and compiling Java code<br />

Chapter 2: Working with Java Projects<br />

This section explains the mechanics of writing Java code in the <strong>IDE</strong>:<br />

Using the code editor<br />

Compiling a Java application<br />

Working with application directories<br />

Using the code editor<br />

When you open a source file into the <strong>IDE</strong>’s Code window, the Select<br />

Object/Select Event combo boxes contain the names of the file’s objects and<br />

methods.<br />

To jump to an object or method in the source code<br />

Select its name from the combo box.<br />

To move to the next or previous method on the page<br />

Click the up or down arrow.<br />

To jump to a specific line of code<br />

1 Click inside the source file (open in the code editor) and choose Edit > Go<br />

to.... The Go to line dialog appears.<br />

37


Chapter 2: Working with Java Projects<br />

2 In the Line number field, enter the line number from the compiler’s error<br />

message.<br />

3 Click OK. The cursor’s line number is displayed in the lower right-hand<br />

corner of the <strong>IDE</strong>’s window.<br />

To hide (or make visible) the code on a page<br />

38<br />

Select View > Code as Icon. All the code on the page is toggled between<br />

viewing as icon or viewing as text.<br />

To view more than one file in a split window<br />

Select Window > Tile.<br />

The files that are open in the workspace are tiled (to a maximum of four files),<br />

so that you can view one file while you’re editing another.<br />

Compiling a Java application<br />

When you publish a Java project, the <strong>IDE</strong> converts each dynamic page to a<br />

Java code (.java) file. Then it compiles all Java code, including source pages,<br />

generating class files that it publishes to the project’s application root<br />

directory (server-side code) or static root directory (applets).<br />

You can also compile a single file — for example, to check for syntax errors:<br />

With the file open in the code editor, select Java > Build. (This option is not<br />

available for dynamic pages.)<br />

Note - If a file is not compiled as you expected, be sure that you<br />

have identified it correctly to the project as server-side, applet,<br />

servlet, or common. To check (and optionally change) this<br />

identification, see “Changing the Java file type” on page 41.<br />

A Java application is compiled using the options set in the <strong>IDE</strong>, using the Tools<br />

> Options > Java Options dialog. For each type of Java source file — server-side,<br />

applet, servlet, or common — the <strong>IDE</strong> has a profile, specifying the path to the<br />

default compiler as well as the classpath and output directory. When you<br />

install the <strong>IDE</strong>, these profiles are created with default values, but you can


Chapter 2: Working with Java Projects<br />

modify the profiles, and you can override the defaults for a particular project<br />

and/or for any Java source file in the project. For more information, see<br />

“Overriding Java compiler options” on page 42.<br />

Again by default, server-side and common JAR files are automatically added to<br />

the compile-time and runtime classpath, but applet and servlet JARs are not.<br />

You can override this default behavior for any JAR file in your project. (This<br />

information applies to CAB and ZIP files as well.) For more information, see<br />

“Overriding options for JAR, CAB, and ZIP files” on page 43.<br />

Finding compile-time errors<br />

If the Java compiler finds a syntax error in your Java code, it sends an error<br />

message to the project’s Build/Publish window. In many cases, you can see<br />

what the problem is by looking at the error message. (Recall that the Java<br />

compiler options set the amount of parsing for error messages. Choose Tools<br />

> Options > Java, and edit your server-side Java compiler profile.)<br />

To navigate the compiler’s error messages<br />

You can scroll through the messages in the Build/Publish window,<br />

double-clicking on any message with a “+” to expand it. If you doubleclick<br />

the error message, the <strong>IDE</strong> opens the file if necessary and displays<br />

the relevant line.<br />

Or you can choose Edit > Find Error > [First, Next] to go to that particular<br />

error in the Build/Publish window. The <strong>IDE</strong> opens the file if necessary<br />

and displays the relevant line.<br />

Debugging a Java application<br />

<strong>HAHTsite</strong> includes a source-level debugger that lets you debug <strong>HAHTsite</strong> Java<br />

applications, even remotely. You must compile the Java application with the<br />

debug option set: from the Build Type combo box in the <strong>IDE</strong>’s toolbar, choose<br />

Debug. (This is the default.)<br />

For more information about running the debugger, see Chapter 15,<br />

“Debugging Server-side Code.”<br />

Working with application directories<br />

<strong>HAHTsite</strong> Java applications use three special directories: the static root<br />

directory, userroot, and approot. You set these directory locations when you<br />

install the <strong>IDE</strong> and Application Server or when you modify their<br />

configurations. These root directories are shared by all applications within a<br />

39


Chapter 2: Working with Java Projects<br />

particular server group, but you can differentiate between them by using the<br />

subdirectory macros %project% and/or %username%. (Otherwise, files from one<br />

project could overwrite files with the same name from another project.)<br />

Static root directory<br />

The static root directory is the directory where the Web server gets the<br />

application’s static pages (.htm and .html files), graphics files, and any other<br />

files not run by the <strong>HAHTsite</strong> Application Server.<br />

40<br />

Note - “Secure static” pages are stored in the project’s approot<br />

directory.<br />

To retrieve the directory pathname (in either NT or UNIX format, depending<br />

on the operating system), you could use code like this:<br />

String myStaticRoot = hahtApplication.getStaticRoot();<br />

To retrieve the URL for the static-page directory, you could use code like this:<br />

String myStaticURL = hahtSession.getStaticURL();<br />

Userroot and approot<br />

The userroot and approot directories are used by the <strong>HAHTsite</strong> Application<br />

Server.<br />

userroot is the application’s initial working directory. At runtime, a<br />

<strong>HAHTsite</strong> application has a current, or “initial working” directory on the<br />

server. In your Java code, if you read or write a file by specifying just the<br />

file’s name, the application looks for the file in the application’s initial<br />

working directory. To retrieve this pathname, you could use code like<br />

this:<br />

String myUserRoot = hahtApplication.getUserRoot();<br />

approot, the application root directory, is the directory in which a<br />

<strong>HAHTsite</strong> Application Server finds an application’s executable files<br />

(.class, .jar, .zip, and .cab files), as well as its “secure static” pages. To<br />

check where the project’s executable files were published, relative to the<br />

approot directory, you could use code like this:<br />

String myAppDir = hahtApplication.getDirName();<br />

If the method returns “\” or “/”, the files were published directly to the<br />

application root directory. Otherwise, the method returns the path to the<br />

subdirectory. (Note that this method does not return the full path to the<br />

application root directory.)<br />

You may also notice a javaroot directory, which holds Java class files for a<br />

HAHTtalk project, but which is not used by Java projects.


Java options<br />

Chapter 2: Working with Java Projects<br />

In the <strong>IDE</strong>, the Tools > Options > Java Options dialog defines the default<br />

compiler and compile-time options, such as classpath and output directory,<br />

that apply to your Java files. However, for any project, and for any Java source<br />

file within a project, you can override both the default compiler and the<br />

compile-time options. And for any JAR, CAB, and ZIP file, you can specify<br />

whether it should be included in the compile-time and/or runtime classpath.<br />

You can also view and change the Java file type.<br />

Changing the Java file type<br />

The General properties of a Java source file list its name and Java file type:<br />

server-side, applet, servlet, or common. If you create or import a file but<br />

specify the wrong type, you can change the type on this property sheet.<br />

1 In the project window, select the filename and choose Edit > Properties.<br />

2 From the drop-down list in the Type field, select a new type. For more<br />

information on the Java file types, see “Adding Java files to a project” on<br />

page 26.<br />

41


Chapter 2: Working with Java Projects<br />

Overriding Java compiler options<br />

If you override Java options at the project level, the new options will apply<br />

throughout your project. However, you can also specify overrides at the file<br />

level.<br />

1 To override Java options at the project level:<br />

42<br />

In the project window, select the project name and choose Edit ><br />

Properties.....<br />

Click the Java Compiler tab.<br />

You will see a list of Java file types, and the default compiler for each.<br />

To modify the default for a particular file type, select it and click<br />

Modify....<br />

2 To override source-file options:<br />

In the project window, select the filename and choose Edit ><br />

Properties.<br />

Click the Java Compiler tab.<br />

3 The Java Compiler dialog appears.


Chapter 2: Working with Java Projects<br />

4 To override the default compiler, uncheck the Use Default Compiler box,<br />

and select a compiler from the drop-down list. The compiler must have<br />

been previously defined in the Tools > Options > Java Options dialog.<br />

5 To override the compiler settings, check the Override Compiler Settings<br />

box. The boxes below will no longer be grayed out, and you can define a<br />

different classpath, output directory, or other compiler option. For details<br />

on setting these options, see the “Java Options” section of the <strong>HAHTsite</strong><br />

<strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 2, “Using the <strong>IDE</strong>/IP’s Windows and<br />

Toolbars.”<br />

Overriding options for JAR, CAB, and ZIP files<br />

JAR, CAB, and ZIP files are treated differently in a <strong>HAHTsite</strong> project, depending<br />

on whether you identify them as server-side, applet, servlet, or common files.<br />

(For brevity’s sake, this section refers only to JARs, but the information applies<br />

equally to JAR, CAB, and ZIP files.)<br />

Server-side and common JARs are automatically added to the project via the<br />

%(ProjectJars) macro in the compile-time classpath. When you publish your<br />

project, the Application Server also automatically adds the JAR file to the<br />

runtime classpath for the application.<br />

43


Chapter 2: Working with Java Projects<br />

By default, applet and servlet JARs are not automatically added to either the<br />

compile-time classpath or the application’s runtime classpath.<br />

You can change the compile-time or runtime defaults for a specific JAR file,<br />

using the Jar Properties dialog in the project window.<br />

1 In the project window, click on a JAR file to select it. The Jar Properties<br />

dialog appears.<br />

2 Respond to the prompts:<br />

44<br />

Item Description<br />

Type To change the type of JAR file (server-side, applet,<br />

servlet, or common), make another selection from<br />

the drop-down box.<br />

Add to compiler class<br />

path<br />

Add to project’s<br />

runtime class path in<br />

application server<br />

Check if you want this JAR added to the compiletime<br />

class path.<br />

Check if you want this JAR added to the runtime<br />

classpath.


Working with<br />

HAHTtalk Basic<br />

Projects<br />

3<br />

What’s in this chapter ....................................................................................46<br />

Adding server-side code to a HAHTtalk Basic project ...................................46<br />

In-line code ................................................................................................48<br />

Invoking an expression or a subroutine from a dialog box ....................50<br />

Adding code in Server-side Code view .....................................................52<br />

What’s in a HAHTtalk Basic page?............................................................53<br />

Adding HAHTtalk Basic files to a project .................................................60<br />

Naming conventions for HAHTtalk Basic projects........................................62<br />

Include files and Globals.hbs .........................................................................63<br />

Project and external includes....................................................................63<br />

Declaring public variables with Globals.hbs ............................................64<br />

Precompiler directives ...............................................................................64<br />

Calling dynamic pages from HAHTtalk Basic................................................65<br />

Event handling in a HAHTtalk Basic project.................................................66<br />

Editing and compiling HAHTtalk Basic code ................................................67<br />

Using the code editor ................................................................................67<br />

Compiling a HAHTtalk Basic application.................................................69<br />

Finding compile-time errors......................................................................69<br />

Debugging a HAHTtalk Basic application.................................................70<br />

Working with application directories .......................................................70<br />

Comparing HAHTtalk Basic and Visual Basic................................................72<br />

45


Chapter 3: Working with HAHTtalk Basic Projects<br />

What’s in this chapter<br />

The first half of this chapter explains how to add server-side code — that is,<br />

code that runs on the Application Server — to a HAHTtalk Basic project. The<br />

second half of the chapter explains the mechanics of working with the code<br />

editor and compiling the code.<br />

Later chapters in this book give detailed explanations, with examples, of ways<br />

you can extend your <strong>HAHTsite</strong> application programmatically. For complete<br />

information about specific classes and methods, refer to the <strong>HAHTsite</strong> Server<br />

Object Model and the HAHTtalk Reference in the online help.<br />

In addition, if you are interested in further customizing your application with<br />

client-side scripts and applets, then be sure to look at these chapters:<br />

46<br />

In this book: Chapter 10, “Working with Client-side Scripts”<br />

In the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>: Chapter 20, “Applets and<br />

Multimedia Objects”<br />

Adding server-side code to a HAHTtalk<br />

Basic project<br />

With HAHTtalk Basic, you can easily extend the functionality of your<br />

<strong>HAHTsite</strong> Web applications beyond what you can do with HTML or CGI<br />

programs. In a <strong>HAHTsite</strong> HAHTtalk Basic project, you can use HAHTtalk Basic<br />

in these ways:<br />

1 You can add in-line code to a page, intermixed with other <strong>HAHTsite</strong><br />

elements such as text, pictures, and forms. The code can be a simple<br />

expression, a single line, or a complete block of code. See “In-line code”<br />

on page 48.<br />

2 You can insert expressions and method calls in many of the dialogs in the<br />

<strong>IDE</strong> — for example, a text box can be initialized with the value of an<br />

expression, and a form’s action can be a call to a HAHTtalk Basic<br />

subroutine. See “Invoking an expression or a subroutine from a dialog<br />

box” on page 50.<br />

3 You can insert code in predefined places within the source code for a page,<br />

using the HTML editor’s Server-side Code view. See “Adding code in<br />

Server-side Code view” on page 52.


Chapter 3: Working with HAHTtalk Basic Projects<br />

4 You can create separate source files, with functions and subroutines that<br />

can be shared by all of the pages in an project and that can be reused in<br />

other projects. In addition to creating or importing HAHTtalk Basic source<br />

files, you can import compiled HAHTtalk Basic files as well. See “Adding<br />

HAHTtalk Basic files to a project” on page 60.<br />

<strong>HAHTsite</strong> Server Object Model<br />

Much of this book describes classes and methods in <strong>HAHTsite</strong>’s Server Object<br />

Model, which controls the structure of a <strong>HAHTsite</strong> Web application. With the<br />

Server Object Model, you can perform tasks such as reading data passed on the<br />

URL, writing HTML data, and controlling session timeout, as well as managing<br />

data source connections, setting form field values, and controlling access to<br />

dynamic pages.<br />

The Server Object Model is implemented in Java. However, it is equally<br />

accessible from HAHTtalk Basic projects, and the online help for the Server<br />

Object Model shows both the Java and HAHTtalk Basic syntax to call each<br />

method. A few methods are not meaningful in a HAHTtalk Basic project, and<br />

for those methods the syntax is shown as “n.a.”<br />

For more information about Java, you may wish to look at Chapter 4, “Calling<br />

Server-side Java from HAHTtalk Basic.” You may already be familiar with<br />

calling CreateObject or CreateJavaObject, to access COM objects or Java<br />

objects from Basic. However, <strong>HAHTsite</strong>’s Server Object Model has a set of builtin<br />

objects. You do not need to instantiate them in order to call their methods.<br />

External logic<br />

From your HAHTtalk Basic code you also have access to capabilities such as<br />

CORBA, COM/DCOM, and native methods. For more information, see the<br />

table below.<br />

External logic Where described<br />

Server-side Java Chapter 4, “Calling Server-side Java from<br />

HAHTtalk Basic”<br />

CORBA Chapter 14, “<strong>HAHTsite</strong> CORBA Capabilities”<br />

COM/DCOM Chapter 13, “Connecting to COM Objects”<br />

ActiveX object calls Online help<br />

Database Stored Procedure Calls Chapter 8, “Data-Agent <strong>Programming</strong>”<br />

47


Chapter 3: Working with HAHTtalk Basic Projects<br />

External logic Where described<br />

In-line code<br />

The ability to intermix HAHTtalk Basic code with other elements (such as text,<br />

pictures, Widgets, and form elements) gives you a powerful tool for<br />

dynamically changing the content of Web pages. You can use this technique<br />

for many purposes — for example:<br />

48<br />

Windows DDE calls Online help<br />

Sending SMTP email messages Online help<br />

FTP operations to a remote server Online help<br />

Using the shell command to<br />

create an external process<br />

Online help<br />

Socket operations Online help<br />

UNIX API system calls<br />

Windows API systems calls Online help<br />

to control the flow of logic on the page<br />

to create “internationalized” pages that contain text in different<br />

languages from which a user can select<br />

to modify values read in from a database or from the URL<br />

To maintain the WYSIWYG look of your pages, you’ll probably want to<br />

minimize the amount of code that you place directly onto a page. You can do<br />

this by creating functions and subroutines in a project’s source pages and<br />

calling them from your Web pages. With this approach, you can also share<br />

functions and subroutines among the project’s Web pages.<br />

This example shows a form whose first-name and last-name text box values are<br />

being overridden by global variables from in-line code at the top of the page.


Chapter 3: Working with HAHTtalk Basic Projects<br />

Besides adding entire lines of code, you can also add expressions. An expression<br />

can include variables, constants, operators, and functions, as long as it resolves<br />

to a single value. Here are two examples:<br />

Date$<br />

Haht.getRequest().getURLField("txtCity")<br />

In the HAHTtalk Basic source, the <strong>IDE</strong> includes the expression in a Print<br />

statement.<br />

To add a HAHTtalk Basic expression to an HTML page<br />

1 On the page, click where you want the expression to appear.<br />

2 Click the Server-side Expression button .<br />

3 Type the expression.<br />

4 By default, expressions are displayed in red in the HTML editor. However,<br />

you can override this setting in Tools > Options > Editor.<br />

To add a statement to an HTML page<br />

1 On the page, click where you want the statement to appear.<br />

2 Click the Server-side Statement button .<br />

3 Type one or more statements.<br />

4 By default, statements are displayed in blue in the HTML editor.<br />

49


Chapter 3: Working with HAHTtalk Basic Projects<br />

To convert existing text to an expression or statement<br />

1 Select the text you want to convert.<br />

2 Click either the Server-side Expression button or the Server-side<br />

Statement button .<br />

To format the output of an expression or statement<br />

You can format the output of a HAHTtalk Basic expression or statement, just<br />

as you can format text that you type directly on the page.<br />

1 Select the paragraph or characters you want to affect.<br />

2 To modify the paragraph properties, choose Edit > Paragraph... or make a<br />

selection from the Paragraph Styles toolbar.<br />

3 To modify the character properties, choose Edit > Character.... or make a<br />

selection from the Character Styles toolbar. (If you modify the font color,<br />

the new color will be displayed in the browser, but not in the <strong>IDE</strong>.)<br />

Invoking an expression or a subroutine from a dialog<br />

box<br />

The second way you can customize your project is by invoking expressions or<br />

subroutines inside a dialog box — for example, to set link properties or form<br />

properties. From the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, you’re probably aware<br />

of the many places in property-sheet dialog boxes that allow you to use an<br />

expression rather than a field name or a constant, or that allow you to call a<br />

subroutine instead of a dynamic page as a link or form action.<br />

Dialog box expressions<br />

To substitute an expression for a field name or constant, prefix the expression<br />

with "==". For example, in the link properties, you could set the query string<br />

to contain the value of the (String) variable "CityCode":<br />

Code=/*==CityCode*/<br />

50


Chapter 3: Working with HAHTtalk Basic Projects<br />

On the destination page, you could retrieve the information this way:<br />

Print aRequest.getURLField("Code")<br />

Notice in the example the use of "/*" and "*/" bracketing the expression. You<br />

must use this construction when you want to use an expression in a<br />

name/value attribute pair, or when it appears in the middle of a script.<br />

However, if you simply want to set an attribute to the value of an expression,<br />

you can use ==expression.<br />

The expression must evaluate to a character string.<br />

Dialog box subroutine calls<br />

In addition to using expressions, you can call user-defined subroutines (not<br />

functions) from several dialogs in the <strong>IDE</strong>, such as the Form Properties dialog<br />

and the Link Properties dialog. For example:<br />

A subroutine can generate the binary data to display a picture, an image<br />

map, or a multimedia object.<br />

It can be the destination for a dynamic link (the value of an HREF<br />

attribute tag).<br />

51


Chapter 3: Working with HAHTtalk Basic Projects<br />

52<br />

It can be the default action that takes place when the user submits a<br />

form, or the action tied to one of the form’s buttons.<br />

Obviously, the content of your subroutine will be determined primarily by<br />

what you want it to do. However, if its effect is to display a page, it should emit<br />

the ... and and HTML tags.<br />

For an annotated view of a typical page, see “What’s in a HAHTtalk Basic<br />

page?” on page 53.<br />

Adding code in Server-side Code view<br />

The third way to customize your project is to add directly to the server-side<br />

code for a page. When you build or publish your project, the <strong>IDE</strong> generates a<br />

pagename.hbs file for every dynamic page. (These generated files are stored in<br />

your project’s sites directory and don’t appear in the project window.) If you<br />

add in-line code to the page, it’s inserted in the HAHTtalk Basic source.<br />

However, you may want to make other additions to the code for a page — for<br />

example, you might want to add an include statement, add some initialization<br />

code, or add variables to the page. The HTML editor’s Server-side Code view<br />

lets you view the source code for a page, and lets you make additions, in<br />

predefined places, that will be preserved when the page is regenerated. (Note<br />

- you cannot change the generated source code; you can only add to it.)<br />

To view and add to the server-side code for a page<br />

1 Open the page in the HTML editor.<br />

2 Select View > Server-side Code, or click the Server-side Code view button<br />

. Here are some points to note:<br />

The white areas mark places where you can insert code.<br />

The grayed-out areas mark generated source code, which is read-only.<br />

If you make changes in Server-side Code view, and then return to<br />

Normal view or HTML Tags view, you will see your changes reflected.<br />

If the Server-side Code view button is disabled, be sure that you have<br />

saved the page (and that it is dynamic).<br />

For more information on this process, see the note that follows.<br />

Behind the scenes: How does Server-side Code view work?<br />

To keep from overwriting your additions, the <strong>IDE</strong> must keep your code<br />

separate from the code it generates. When you add code in Server-side Code<br />

view, your code is translated into HTML tags and kept in the project’s HTML


Chapter 3: Working with HAHTtalk Basic Projects<br />

file for this page. If you look at the page in HTML tags view, you will see<br />

sections like this:<br />

<br />

When you build or publish the project, the code for the dynamic page is<br />

generated from the HTML file.<br />

What’s in a HAHTtalk Basic page?<br />

When you publish a project, for each dynamic page, the <strong>IDE</strong> generates a file<br />

(pagename.hbs) that includes a constructor and an entry point for<br />

HS_pagename. The source code for each dynamic page has these contents.<br />

Note - Much of what you see in Server-side Code view for a<br />

HAHTtalk Basic page is generated for use by the <strong>IDE</strong>/IP’s dialog<br />

boxes and can be ignored. In the example that follows, ellipses<br />

mark code that has been omitted.<br />

A place for include files<br />

Type definitions<br />

A page "constructor"<br />

A form handler<br />

An entry point for the page<br />

An exit handler<br />

An error handler<br />

The following sections explain each of these topics, using as an example the<br />

HAHTtalk Basic source for a page that simply displays the current date.<br />

A place for include files<br />

You can use the HAHTtalk Basic #include directive to include in a page one or<br />

more files that contain HAHTtalk Basic declarations. <strong>HAHTsite</strong> also supports a<br />

per-project Globals.hbs code page, which you can use to declare session<br />

“global” variables that can be accessed by all of the HAHTtalk Basic code in a<br />

project. (If this file is present in your project, its contents are automatically<br />

prepended to each .hbs file.) For more information, see “Include files and<br />

Globals.hbs” on page 63.<br />

53


Chapter 3: Working with HAHTtalk Basic Projects<br />

' Generated by <strong>HAHTsite</strong><br />

' Includes. Includes can only be at the top of the file,<br />

' and should not have code in them.<br />

Type definitions<br />

The page defines two constants that can be useful in Print statements:<br />

Const HSQUOT = Chr$(34)<br />

Const HSCRLF = Chr$(13) & Chr$(10)<br />

HSQUOT produces quotation marks; use this constant when you want to embed<br />

quotation marks in a printed string. HSCRLF (carriage return/line feed) forces a<br />

line break in the HTML source file. (Remember that line breaks in HTML<br />

source files are ignored; if you want a line break in the displayed HTML, you<br />

will still need to add tags such as "" or "...".)<br />

You can add your own public or private variables, functions, or subroutines in<br />

the marked places of this section. For example, you might want to add a<br />

subroutine to be called as the “success” or “failure” page from a database<br />

action of a form button on this page.<br />

54<br />

' Imports and includes.<br />

' Type definitions.<br />

' Privates<br />

' Publish-code-generation helper variables - do not remove!<br />

Private Haht_TempJavaObj As Object<br />

' Used for static-finals from Java Classes, temp java objects<br />

Private Haht_Page as Object<br />

Private HS_ShowDate_Construct_Called As Boolean<br />

' User-defined private variables.<br />

' More user-defined private variables.<br />

' Private Functions and Subs<br />

' User-defined private functions and subs.


Chapter 3: Working with HAHTtalk Basic Projects<br />

' More user-defined private functions and subroutines.<br />

' Public variables<br />

Const HSCRLF = Chr$(13) & Chr$(10)<br />

Const HSQUOT = Chr$(34)<br />

' User-defined public variables.<br />

' Public Functions and Subs<br />

' User-defined public functions and subs.<br />

' User-defined functions and subroutines.<br />

A page "constructor"<br />

This code is called the first time this page is browsed in a session. You can add<br />

custom code to the constructor.<br />

' Constructor for page. Called once per page per state.<br />

Private Function HS_ShowDate_Construct() As Boolean<br />

On Error Goto HAHTErrorHandler_cons<br />

Dim aResponse As Object<br />

Set Haht_Page = Haht.getPage()<br />

HS_ShowDate_Construct = TRUE<br />

If (HS_ShowDate_Construct_Called) Then<br />

Exit Function<br />

Else<br />

HS_ShowDate_Construct_Called = TRUE<br />

End If<br />

...<br />

' Custom constructor code. This code executes<br />

' the first time a page is called.<br />

' Custom initialization code<br />

' for user-defined static variables.<br />

55


Chapter 3: Working with HAHTtalk Basic Projects<br />

A form handler<br />

If your page contains one or more forms with buttons, then the Type<br />

Definitions section of your code will contain this line:<br />

#CONST HAHT_FORM_HANDLER_DEFINED=1<br />

and the form handler code (enclosed by an #If statement) will execute.<br />

The generated code for a page’s form handler adapts to the contents of the<br />

page. At runtime, when a user submits a form, the form handler determines<br />

which button was clicked and calls the appropriate command handler. In a<br />

HAHTtalk Basic project, you can create a custom form handler. You can also<br />

add your own code to process a Submit button, via the “User Code” choice in<br />

the button’s Action field. For more information, see Chapter 8, “Data-Agent<br />

<strong>Programming</strong>.”<br />

56


Chapter 3: Working with HAHTtalk Basic Projects<br />

#If (HAHT_FORM_HANDLER_DEFINED=1) Then<br />

' Form handler<br />

Public Sub HS_ShowDate_fH<br />

Dim bCmdHandlerCalled As Boolean<br />

Dim thePage As Object, theErrors As Object<br />

Dim aResponse As Object<br />

Set aResponse = Haht.getResponse()<br />

On Error Goto HAHTErrorHandler_fH<br />

bCmdHandlerCalled = False<br />

If (Not bCmdHandlerCalled) Then<br />

Set thePage = Haht.getPage()<br />

Set theErrors = thePage.getErrors()<br />

theErrors.add "Received form command did not _<br />

invoke a command-handler", "form-handler"<br />

Set thePage = Nothing<br />

Set theErrors = Nothing<br />

HS_ShowDate<br />

End If<br />

HAHTExitHandler_fH:<br />

Exit Sub<br />

HAHTErrorHandler_fH:<br />

aResponse.addHeaderLine "Content-type: text/html"<br />

Print ""<br />

Print ""<br />

Print "The following error has occurred on page _<br />

HS_ShowDate on line " & Str$(erl);<br />

If (Err.Source "") Then<br />

Print " of script " & Err.Source;<br />

End If<br />

Print ": " & Str$(Err) & " - " & Error & "";<br />

Print ""<br />

Resume HAHTExitHandler_fH<br />

End Sub<br />

#End If<br />

An entry point for the page<br />

Each dynamic page has an entry point, named HS_pagename. This is the<br />

subroutine name you would use to call the page. The subroutine emits any<br />

header lines — for example,<br />

Content-type: text/html<br />

57


Chapter 3: Working with HAHTtalk Basic Projects<br />

Note that you can override the content-type header by another call to the<br />

Response object’s setContentType method. See “Adding content information<br />

to a header line” on page 127.<br />

After emitting header lines, the subroutine then sets up the basic structure of<br />

the page, which would look like this in HTML:<br />

<br />

...<br />

...<br />

<br />

When you add in-line code to a page, it’s added here, between the and<br />

tags. (However, for information about output that must go in the<br />

HTTP headers, see “Writing headers” on page 126.)<br />

' Entry point for page<br />

Sub HS_ShowDate()<br />

' Local variables<br />

Dim aResponse As Object<br />

Dim aRequest As Object<br />

Dim out As Object<br />

On Error Goto HAHTErrorHandler<br />

58<br />

' Custom local variables. These are instantiated<br />

' each time the page is run.<br />

' Initialize local variables.<br />

Set aResponse = Haht.getResponse()<br />

Set aRequest = Haht.getRequest()<br />

Set out = aResponse.getWriter()<br />

If (Not HS_ShowDate_Construct()) Then<br />

' Constructor failed - exit page<br />

Exit Sub<br />

End If<br />

' Custom initialization code. Executes before<br />

' HTML tags are generated.<br />

' Output HTTP response headers.<br />

' Custom HTTP response headers. Add HTTP headers here.


Chapter 3: Working with HAHTtalk Basic Projects<br />

aResponse.addHeaderLine "Content-type: text/html"<br />

Print HSCRLF<br />

' More custom HTTP response headers.<br />

' Add HTTP headers here.<br />

' Generate HTML for browser.<br />

print "" & HSCRLF _<br />

& "" & HSCRLF _<br />

& " " & HSCRLF _<br />

& " ShowDate" & HSCRLF _<br />

& "" & HSCRLF _<br />

& "" & HSCRLF _<br />

& " " ;<br />

Print date$<br />

Object references you can use<br />

The code shown above gets references to the Request and Response objects, as<br />

well as the default HtmlWriter. You can use aRequest and aResponse to read<br />

values sent by the Web server or to write HTML. For example, to read a value<br />

passed in a form or on the URL, you would call aRequest.getURLField.<br />

This code also gets a reference to the default HtmlWriter. To write HTML<br />

output programmatically, you simply call the Print statement. You can also<br />

intermix text and in-line code on a page. In the HAHTtalk Basic source, the<br />

text turns into Print statements.<br />

For more information about these objects, see Chapter 5, “<strong>HAHTsite</strong> Server<br />

Object Model.”<br />

An exit handler<br />

print "" & HSCRLF _<br />

& "" & HSCRLF _<br />

& "" ;<br />

' All HTML has been generated. Put cleanup code here.<br />

In addition to a default error handler, each page has an exit handler label<br />

called HAHTExitHandler, which simply exits the subroutine. If you want to exit<br />

a page, you can write a GoTo HAHTExitHandler statement.<br />

59


Chapter 3: Working with HAHTtalk Basic Projects<br />

HAHTExitHandler:<br />

Exit Sub<br />

An error handler<br />

Each dynamic page includes a default error handler and an On Error Goto<br />

statement that traps page-level errors. You can add code to the default error<br />

handler, and you can also include your own HAHTtalk Basic On Error<br />

construct in your subroutines. Your “On Error” construct will be nested inside<br />

the default error handler and will trap subroutine-level errors.<br />

HAHTErrorHandler:<br />

' Handle errors that occur on the page.<br />

Adding HAHTtalk Basic files to a project<br />

Another way to add server-side code to your project is to create a source file or<br />

import a source file or object file to be used by any of a project’s dynamic<br />

pages.<br />

Code pages are source code files containing subroutines or functions written<br />

in HAHTtalk Basic. These subroutines and functions must have unique<br />

(project-wide) names, and they can be called by any of a project’s dynamic<br />

pages. For example, the in-line code on an HTML page can call a subroutine to<br />

process some data. Or you can set a form’s action to call a subroutine which<br />

either creates or calls a dynamic page. A subroutine can generate the binary<br />

60<br />

If (aResponse.getContentType() = "") Then<br />

aResponse.addHeaderLine "Content-type: text/html"<br />

Print ""<br />

End If<br />

' Close any table tags that may be open.<br />

Print ""<br />

Print "The following error has occurred on page _<br />

HS_ShowDate on line " & Str$(erl);<br />

If (Err.Source "") Then<br />

Print " of script " & Err.Source;<br />

End If<br />

Print ": " & Str$(Err) & " - " & Error & "";<br />

' Handle errors that occur on the page.<br />

Resume HAHTExitHandler


Chapter 3: Working with HAHTtalk Basic Projects<br />

data to display a picture or create a dynamic link and then print the link in an<br />

HTML anchor tag on the page.<br />

In a HAHTtalk Basic project, code pages are stored in the Web folder, usually in<br />

a subfolder.<br />

To add a new code page<br />

1 Choose File > New > Code.<br />

2 A blank code page opens in the workspace.<br />

3 Enter HAHTtalk Basic subroutines or functions. For information about<br />

using the <strong>IDE</strong>’s code editor, see “Editing and compiling HAHTtalk Basic<br />

code” on page 67.<br />

To import a code page<br />

In addition to creating new code pages in your project, you can import<br />

existing source code files.<br />

1 In the project window, click on the folder in which you want to store the<br />

new file.<br />

2 Choose File > Import File.... The Import Files dialog appears.<br />

3 Type or browse for one or more filenames.<br />

4 Choose Copy Files or Create Shortcuts. If you want to maintain one<br />

central version of this file but use it in several projects, you may want to<br />

create a shortcut.<br />

5 Click OK to complete the import.<br />

For more information about importing files into the <strong>IDE</strong>, consult the <strong>HAHTsite</strong><br />

<strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 3, “Managing Projects.”<br />

To save a code page<br />

1 Select File > Save. The Save Code Page As dialog appears.<br />

2 Type in a page name, or accept the default name. The suffix must be<br />

".hbs".<br />

3 To save the code page within the project, browse within the Project Items<br />

window for the folder name you want.<br />

4 If the project is in source control, you will see an additional checkbox: Add<br />

to source control. Check this box to add this file to the source control<br />

system.<br />

5 Click OK to save your changes.<br />

61


Chapter 3: Working with HAHTtalk Basic Projects<br />

To save a code page outside the project<br />

To be called from within the project, a code page must be saved within the<br />

project. However, you can also save a code page to a file outside the project.<br />

1 Select File > Save. The Save Code Page As dialog appears.<br />

2 Click the Save to File... button. The Save As dialog appears.<br />

3 Browse for a folder location and enter a filename.<br />

4 Click OK to save your changes.<br />

Naming conventions for HAHTtalk Basic<br />

projects<br />

Code pages and dynamic pages represent entry points into the application’s<br />

symbol table (.htx) file that <strong>HAHTsite</strong> creates when you publish a project.<br />

During the publish operation, <strong>HAHTsite</strong> converts dynamic pages into<br />

HAHTtalk Basic subroutines and prepends the characters “HS_” to the<br />

resulting subroutine names. (Subroutine names in code pages are not<br />

changed.) The name assigned to a dynamic page’s subroutine is determined as<br />

follows:<br />

62<br />

The dynamic-page name is preceded with the characters HS_.<br />

Any illegal character — that is, anything other than an alphabetic or<br />

numeric character — is converted to the underscore (_) character.<br />

As a result of this conversion process, dynamic pages with similar names could<br />

be converted to subroutines with the same name. For example, the <strong>IDE</strong><br />

converts the names “2-Page” and “2 Page” to “HS_2_Page.” Creating multiple<br />

pages that result in HAHTtalk Basic subroutines with the same name causes an<br />

error at publish time.<br />

To prevent this type of error, you can accept the default page names that<br />

<strong>HAHTsite</strong> provides. Or you can establish a page naming convention such that<br />

all dynamic page names consist of letters and numbers only.


Include files and Globals.hbs<br />

Chapter 3: Working with HAHTtalk Basic Projects<br />

The HAHTtalk Basic #include directive is similar to the #include directive<br />

used in C and C++. Here is a summary of the rules for using the #include<br />

directive and creating an include file.<br />

Rules for using an include file<br />

A file can have multiple #include directives. However, the directives<br />

must be at the top of a page, before any executable HAHTtalk Basic code.<br />

The #include directives must appear on a code page, not an HTML page.<br />

You can add #includes to an HTML page in Server-side Code view. (You<br />

can then access their contents from in-line expressions and statements<br />

on the HTML page.)<br />

Pathnames in the #include directives use <strong>HAHTsite</strong> project-style (UNIXstyle)<br />

directory delimiters (“/”).<br />

You can indent the #include directive with spaces or tab characters.<br />

However, the <strong>HAHTsite</strong> compiler will not recognize the directive if it is<br />

preceded by any characters other than spaces or tabs.<br />

Rules for creating an include file<br />

Include files use the “.hbh” extension.<br />

Include files must contain only declarations — they cannot contain<br />

executable HAHTtalk Basic code.<br />

Include files can themselves contain #include directives (that is, nested<br />

includes are allowed).<br />

Project and external includes<br />

There are two versions of the HAHTtalk Basic #include directive: the project<br />

include and the external include.<br />

The project include<br />

The project include looks first for the included file in a project folder, then in<br />

an external (to the project) path. Its basic form is:<br />

#include "filename.hbh"<br />

which can include subfolder names. The compiler looks for the named file in<br />

these locations:<br />

1 First, in the project folder containing the code page.<br />

63


Chapter 3: Working with HAHTtalk Basic Projects<br />

2 In the search path that you specified in the <strong>IDE</strong>’s Tools > Options ><br />

General dialog. The path is a semi-colon separated directory list, which<br />

enables you to search several directories (in the order that the directories<br />

appear in the list). The default directory is <strong>HAHTsite</strong>InstallDir/include.<br />

The <strong>HAHTsite</strong> compiler generates an error if it cannot find the include file in<br />

the project or in the include-directory search path.<br />

The external include<br />

The external include looks for the included file in an external path. Its basic<br />

form is:<br />

#include <br />

which can include subfolder names as well. The compiler looks for the named<br />

file only using the include-file search path you specified the <strong>IDE</strong>’s Tools ><br />

Options > General dialog.<br />

You can also use fully-qualified external directives. For example:<br />

#include <br />

Declaring public variables with Globals.hbs<br />

You can declare a project’s public (global) variables in a code page named<br />

Globals.hbs. A project can contain only one Globals.hbs, which can reside<br />

in any project folder. Its contents are automatically prepended to every<br />

dynamic page in the project. This file can contain project-wide constants and<br />

declarations in addition to global variables. Globals.hbs can contain only<br />

constants and variable declarations, not subroutines or functions. Because its<br />

contents become part of every dynamic page, be careful not to make the<br />

Globals.hbs file too large. You can always use #include directives to include<br />

files on a page-by-page basis.<br />

It’s important to understand that each session gets its own copy of these global<br />

variables. They are not shared across sessions.<br />

Precompiler directives<br />

HAHTtalk code (whether on a code page or in the generated code for a<br />

dynamic page) can contain these standard precompiler directives:<br />

#Const<br />

#If...Then...#Else<br />

In addition, <strong>HAHTsite</strong> provides these predefined constants that can be used in<br />

an #If...Then...#Else directive:<br />

64


Constant Description<br />

Chapter 3: Working with HAHTtalk Basic Projects<br />

PUBLISH_OS The operating system to which this site is being<br />

published. Available only if this information has been<br />

entered in the Application Server administrator. If so,<br />

it appears in the site’s .hsg file, like this:<br />

OSType=Windows:NT<br />

PUBLISH_WEBSERVER The name of the Web server for this site, as defined<br />

during Application Server installation or by the Web<br />

Server Utility. This name appears in the site’s .hca file,<br />

like this:<br />

WebServerName=Netscape FastTrack 3.01<br />

PUBLISH_SITENAME The name of the site to which you are currently<br />

publishing (i.e., the current site). This name includes<br />

the hostname. Here is an example:<br />

FastTrack@caleb.haht.com<br />

PUBLISH_SERVERGROUP The name of the current server group, which appears<br />

in the Name field of the .hsg file, like this:<br />

Name=webapps<br />

Calling dynamic pages from HAHTtalk<br />

Basic<br />

When you build a <strong>HAHTsite</strong> project, the names of the project’s dynamic Web<br />

pages are included as subroutines in the project’s symbol table (.htx) file. The<br />

<strong>IDE</strong> automatically prepends “HS_” to each page name, so that Page1.html<br />

would be stored in the symbol table as HS_Page1. From HAHTtalk Basic code,<br />

you can call a dynamic page as you would any subroutine, as in this example:<br />

Call HS_Page1<br />

As with any subroutine, each dynamic page in a project must have a unique<br />

(project-wide) name.<br />

65


Chapter 3: Working with HAHTtalk Basic Projects<br />

Event handling in a HAHTtalk Basic project<br />

In a HAHTtalk Basic project, initialization or termination methods are<br />

triggered when a session starts and when it ends. By default, these methods do<br />

nothing, but you can override them using the pseudo-methods<br />

HahtSessionOnStart and HahtSessionOnEnd. Here are the pseudo-methods:<br />

HahtSessionOnStart<br />

In HahtSessionOnStart, you could populate a session recordset for use by<br />

subsequent pages in the session — for example, you might want to read in the<br />

values of a database table (such as a catalog) that’s used by several different<br />

pages.<br />

If HahtSessionOnStart fails, the Application Server terminates the session<br />

without running any pages. Note that HahtSessionOnEnd is not called if<br />

HahtSessionOnStart fails.<br />

There are two ways for HahtSessionOnStart to fail:<br />

66<br />

Method Description<br />

HahtSessionOnStart Called when a new session is created, but before any<br />

pages are run. Should be declared as a function<br />

returning a boolean value.<br />

HahtSessionOnEnd Called just before a session is destroyed. The system also<br />

calls this method after the application executes a<br />

HAHTtalk Basic STOP or END statement. Should be<br />

declared as a subroutine.<br />

It can return False, in which case the Application Server writes a runtime<br />

error message and terminates the session.<br />

You can edit HahtSessionOnStart to generate a page of diagnostic<br />

information if desired. Generally, after producing a diagnostic page, you<br />

want to prevent any further running of the session and any further error<br />

output from the Application Server, so you should also call End or Stop,<br />

which terminates the session. Here is an example:


HAHTtalk Basic<br />

HahtSessionOnEnd<br />

Chapter 3: Working with HAHTtalk Basic Projects<br />

Function HahtSessionOnStart As Boolean<br />

Dim aResponse As Object<br />

Set aResponse = Haht.getResponse()<br />

aResponse.setContentType "text/html"<br />

aResponse.endHeaders<br />

aResponse.write "Exiting the session "<br />

aResponse.write "Failed in HahtSessionOnStart "<br />

'Terminate the session<br />

End<br />

End Function<br />

Before terminating a session, the Application Server calls HahtSessionOnEnd<br />

(except in the case where HahtSessionOnStart has failed, as noted above). At<br />

this point, you might want to save the session state (for example), so that you<br />

can restore it later if the user returns to the application.<br />

Editing and compiling HAHTtalk Basic code<br />

This section explains the mechanics of writing HAHTtalk Basic code in the<br />

<strong>IDE</strong>:<br />

Using the code editor<br />

Compiling a HAHTtalk Basic application<br />

Working with application directories<br />

Using the code editor<br />

When you open a source file in the <strong>IDE</strong>’s Code window, the Select object/Select<br />

event combo boxes contain the names of the file’s objects and events.<br />

67


Chapter 3: Working with HAHTtalk Basic Projects<br />

To jump to an object or event in the source code<br />

68<br />

Select its name from the appropriate combo box.<br />

To move to the next or previous event on the page<br />

Click the up or down arrow.<br />

To jump to a specific line of code<br />

1 Click inside the source file (open in the code editor) and choose Edit > Go<br />

to.... The Go to line dialog appears.<br />

2 In the Line number field, enter the line number from the compiler’s error<br />

message.<br />

3 Click OK. The cursor’s line number is displayed in the lower right-hand<br />

corner of the <strong>IDE</strong>’s window.


To hide (or make visible) the code on a page<br />

Chapter 3: Working with HAHTtalk Basic Projects<br />

Select View > Code as Icon. All the code on the page is toggled between<br />

being shown as an icon and as text.<br />

To view more than one file in a split window<br />

Select Window > Tile.<br />

The files that are open in the workspace are tiled (to a maximum of four files),<br />

so that you can view one file while you’re editing another.<br />

To display help for a HAHTtalk Basic keyword<br />

On the code page, highlight a HAHTtalk Basic keyword and press F1.<br />

Anywhere on a code page, you can press F1 to invoke the online help, which<br />

includes information about HAHTtalk Basic and the <strong>HAHTsite</strong> Server Object<br />

Model.<br />

To check the syntax of HAHTtalk Basic code<br />

You can check the syntax of a code file without running the compiler:<br />

With a page open in the code editor, choose Script > Check Syntax.<br />

(This option does not apply to pages open in Server-side Code view.)<br />

Compiling a HAHTtalk Basic application<br />

When you publish a HAHTtalk project, the <strong>IDE</strong> converts each dynamic page<br />

to an intermediate HAHTtalk Basic code (.hbs) file. Then it compiles all<br />

HAHTtalk Basic code, including code pages, generating binary (.hbb) files that<br />

it publishes to the project’s application root directory.<br />

Note - If your project includes Java source files (for server-side<br />

Java that is called from HAHTtalk Basic), they are compiled at<br />

the same time.<br />

Finding compile-time errors<br />

If the HAHTtalk Basic compiler finds a syntax error in your code, it sends an<br />

error message to the project’s Build/Publish window. In many cases, you can<br />

see what the problem is by looking at the error message.<br />

To navigate the compiler’s error messages<br />

You can scroll through the messages in the Build/Publish window,<br />

double-clicking on any message with a “+” to expand it.<br />

69


Chapter 3: Working with HAHTtalk Basic Projects<br />

70<br />

Or you can choose Edit > Find Error > [First, Next, Previous, or Last] to go<br />

to that particular error in the Build/Publish window.<br />

To locate an error in your source code<br />

There are two ways to locate a particular compiler error:<br />

Double-click on the error message in the Build/Publish window. The <strong>IDE</strong><br />

opens the file, if it’s not open, and displays the relevant line.<br />

Click inside the source file (open in the code editor) and choose Edit ><br />

Go to.... The Go to line dialog appears. In the Line number field, enter<br />

the line number from the compiler’s error message. Then click OK.<br />

If the error is in your in-line code, rather than a HAHTtalk Basic code file, the<br />

<strong>IDE</strong> displays the source code for that page in Server-side Code view.<br />

Debugging a HAHTtalk Basic application<br />

<strong>HAHTsite</strong> includes a source-level debugger that lets you debug <strong>HAHTsite</strong><br />

HAHTtalk Basic applications, even remotely. No special flag needs to be set to<br />

compile for debugging. For more information, see Chapter 15, “Debugging<br />

Server-side Code.”<br />

Note - If your application calls server-side Java from HAHTtalk<br />

Basic, the Java code will be skipped over during a debugging<br />

session.<br />

Working with application directories<br />

<strong>HAHTsite</strong> applications use four special directories: the staticroot directory,<br />

userroot, approot, and javaroot. You set these directory locations when you<br />

install the Application Server or when you modify its configuration. These<br />

root directories are shared by all applications within a particular server group,<br />

but you can differentiate between them by using the subdirectory macros<br />

%project% and/or %username%. (Otherwise, files from one project could<br />

overwrite files with the same name from another project.)<br />

Static root directory<br />

The static root directory is the directory where the Web server gets the<br />

application’s static pages (.htm and .html files), graphics files, and any other<br />

files not run by the <strong>HAHTsite</strong> Application Server.<br />

Note - “Secure static” pages are stored in the approot directory.<br />

See “Userroot, approot, and javaroot” on page 71.


Chapter 3: Working with HAHTtalk Basic Projects<br />

To retrieve the directory pathnames (in either NT or UNIX format, depending<br />

on the operating system), you would use code like this:<br />

Dim MyStaticRoot As String<br />

MyStaticRoot = HahtApplication.getStaticRoot()<br />

To retrieve the URL for the static-page directory, you would use code like this:<br />

Dim MyStaticURL As String<br />

MyStaticURL = HahtSession.getStaticURL()<br />

For more information about these methods and their uses, see “Retrieving<br />

Application object properties” on page 100.<br />

Userroot, approot, and javaroot<br />

The userroot, approot, and javaroot directories are used by the <strong>HAHTsite</strong><br />

Application Server.<br />

userroot is the application’s initial working directory. At runtime, a<br />

<strong>HAHTsite</strong> application has a current, or “initial working,” directory on the<br />

server. In your HAHTtalk Basic code, if you read or write a file by<br />

specifying just the file’s name, the application looks for the file in the<br />

application’s initial working directory. To retrieve this pathname, you can<br />

use code like this:<br />

Dim MyUserRoot As String<br />

MyUserRoot = HahtApplication.getUserRoot()<br />

approot, the application root directory, is the directory in which a<br />

<strong>HAHTsite</strong> Application Server finds an application’s executable files (.htx,<br />

.hbb, and .hbx files). To check where the project’s executable files were<br />

published, relative to the approot directory, you can use code like this:<br />

Dim MyAppDir As String<br />

MyAppDir = HahtApplication.getDirName()<br />

If the method returns “\” or “/”, the files were published directly to the<br />

application root directory. Otherwise, the method returns the path to the<br />

subdirectory. (Note that this method does not return the full path to the<br />

application root directory.)<br />

javaroot, the Java class directory, specifies the location of any<br />

application-specific Java classes that you have developed. For more<br />

information about using server-side Java with your project, see Chapter 4,<br />

“Calling Server-side Java from HAHTtalk Basic.”<br />

71


Chapter 3: Working with HAHTtalk Basic Projects<br />

Comparing HAHTtalk Basic and Visual Basic<br />

HAHTtalk Basic is fully syntax-compatible with Visual Basic. It is based on<br />

Visual Basic 3 and incorporates some features of Visual Basic 4.<br />

HAHTtalk Basic data types<br />

Scalars<br />

HAHTtalk Basic supports the following scalar data types<br />

.<br />

Arrays<br />

Multidimensional arrays (of up to 60 dimensions) are supported. You can use<br />

REDIM to redimension arrays.<br />

Records<br />

Records in HAHTtalk Basic are declared using the TYPE statement.<br />

Names<br />

Variable names in HAHTtalk Basic:<br />

72<br />

Must begin with a lowercase or an uppercase letter. Names cannot start<br />

with numbers, spaces, or hyphens.<br />

Must contain only letters, numbers, and the underscore character.<br />

Must not be longer than 80 characters. In contrast, Visual Basic names<br />

must not be longer than 40 characters.<br />

Scope<br />

boolean (2 bytes) currency (8 bytes)<br />

integer (2 bytes) string (variable and fixed length)<br />

long (4 bytes) date (8-byte IEEE double)<br />

single (4 bytes) variant<br />

double (8 bytes) object<br />

HAHTtalk Basic variables follow the same scoping rules as Visual Basic<br />

variables and can be Public (global) or Private. Static variables are not<br />

supported.


Subroutines and functions<br />

Chapter 3: Working with HAHTtalk Basic Projects<br />

Subroutines and functions can be declared in the code blocks of any code<br />

pages. The scope of HAHTtalk Basic subroutines and functions is global by<br />

default. You can restrict the scope of a subroutine or function by using the<br />

Private keyword.<br />

A project’s HAHTtalk Basic Executable file (.htx file) contains a dictionary that<br />

maps entry-point names to the appropriate HAHTtalk Basic object file.<br />

File I/O<br />

The <strong>HAHTsite</strong> Application Server supports the I/O mechanisms built into<br />

HAHTtalk Basic. These mechanisms include:<br />

various forms of sequential and random access to flat files<br />

SQL statements for accessing databases through ODBC and native access<br />

support for file and directory information, such as FileAttr, FileDate,<br />

FileLen, ChDir, ChDrive, CurDir, MkDir, RmDir, GetAttr, and SetAttr<br />

The <strong>HAHTsite</strong> Server Object Model provides methods for getting the<br />

pathnames of an application’s static-page directory, dynamic-page directory,<br />

and initial working directory (see the section “Working with application<br />

directories” on page 70).<br />

Error handling<br />

HAHTtalk Basic supports the Visual Basic statements for error handling.<br />

Unhandled runtime errors will cause the <strong>HAHTsite</strong> Application Server to<br />

return an error page to the user. See the section “An error handler” on page 60<br />

for more about using the HAHTtalk Basic “On Error” construct.<br />

Code page properties<br />

In the project window, you can set the properties of a code page.<br />

The General tab shows the page name and path (read-only).<br />

The Privileges tab lets you set the privileges required to access this code<br />

page.<br />

73


Chapter 3: Working with HAHTtalk Basic Projects<br />

74<br />

The Publish tab lets you specify whether or not the page should be<br />

published, whether it should inherit its publish properties from the<br />

parent folder, and whether it is exportable.<br />

The File tab displays the filename and characteristics as well as the<br />

project ID for this code page.


Calling Server-side<br />

Java from HAHTtalk<br />

Basic<br />

4<br />

Introduction....................................................................................................76<br />

Using Java objects with HAHTtalk Basic .......................................................76<br />

CreateJavaObject........................................................................................77<br />

GetJavaClass...............................................................................................78<br />

CreateTypedJavaNull .................................................................................78<br />

Differences between HAHTtalk Basic and Java..............................................79<br />

Java is strongly typed ................................................................................79<br />

Parameter passing ......................................................................................80<br />

Java is case sensitive ..................................................................................80<br />

Locating objects.........................................................................................80<br />

Mapping HAHTtalk Basic types to Java parameter types..............................81<br />

Mapping Java types to HAHTtalk Basic types................................................83<br />

Troubleshooting: Java runtime errors ............................................................84<br />

75


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

Introduction<br />

In addition to support for client-side JavaScript, Java applets, Java servlets,<br />

VBScript, and ActiveX, <strong>HAHTsite</strong> supports calling server-side Java from<br />

HAHTtalk Basic code with the <strong>HAHTsite</strong> Application Server’s Java Virtual<br />

Machine. Server-side Java can be used on all the supported HAHTtalk Basic<br />

platforms.<br />

In addition to providing the inherent object-oriented benefits of<br />

encapsulation, inheritance, and polymorphism, Java integration lets you take<br />

advantage of JDBC, Java Beans, CORBA and the ever-growing supply of thirdparty<br />

class libraries.<br />

From your HAHTtalk Basic code, you can access Java classes as native objects<br />

— simply declare Java objects as a HAHTtalk Basic data type, using either the<br />

CreateJavaObject or GetJavaClass calls. You can then access a Java class’s<br />

methods and properties directly from your HAHTtalk Basic code.<br />

Java source files and class files are completely integrated into a <strong>HAHTsite</strong><br />

project’s hierarchy for easy editing, compiling, publishing, and integration<br />

with source control and configuration management systems. You can write<br />

the Java code for your Java source files (.java files) in the <strong>HAHTsite</strong> code editor,<br />

which provides syntax coloring for the Java language.<br />

For information about configuring Java compilers for your project, see the<br />

description of Tools > Options > Java Options in the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s<br />

<strong>Guide</strong>, Chapter 2, “Using the <strong>IDE</strong>/IP’s Windows and Toolbars.” For<br />

information about creating and compiling Java files, see “Editing and<br />

compiling Java code” on page 37.<br />

Using Java objects with HAHTtalk Basic<br />

Creating and using Java objects with HAHTtalk Basic works much like creating<br />

and using COM/ActiveX objects. To create a Java object, you use the<br />

CreateJavaObject function instead of CreateObject. If you want to access a<br />

static variable or method of a Java class, use the GetJavaClass function. You<br />

can also obtain a null reference to a particular type of object using the function<br />

CreateTypedJavaNull. Occasionally, you may need such a reference for use as<br />

a parameter.<br />

Once you have a Java object in a HAHTtalk Basic variable of type Object, you<br />

access the Java object’s properties and methods using the "." syntax.<br />

76


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

Here are descriptions of the two HAHTtalk Basic calls you use with Java.<br />

CreateJavaObject<br />

Syntax<br />

Function CreateJavaObject(className[, param1, param2, _<br />

...paramN]) As Object<br />

Description<br />

Creates an instance of the Java class specified in the className parameter by<br />

calling the Java class’s constructor and passing the additional parameters.<br />

Parameters<br />

Parameter Type Description<br />

className String The case-sensitive name of the Java<br />

class.<br />

param1...paramn Variant Parameters to pass to the constructor of<br />

the Java class specified in the<br />

className parameter.<br />

Example<br />

The following subroutine creates a Java object called MyCal from the class<br />

HTMLCalendar, which takes a month and a year as parameters. Then the<br />

calendar's GetMonthHTML method is called. This method returns an HTML<br />

string showing the days of the specified month.<br />

Sub printMonth(MyMonth As Long, MyYear as Long)<br />

Dim MyCal As Object<br />

Set MyCal = CreateJavaObject("HTMLCalendar", MyMonth, MyYear)<br />

print MyCal.GetMonthHTML()<br />

Set MyCal = Nothing<br />

End Sub<br />

77


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

GetJavaClass<br />

Syntax<br />

78<br />

Function GetJavaClass(className) As Object<br />

Description<br />

Returns a reference to a Java class without creating an instance of the class. Use<br />

this function to access the static properties and methods of a Java class.<br />

Parameters<br />

Parameter Type Description<br />

className String The case-sensitive name of the Java<br />

class.<br />

Example<br />

Static methods and properties in Java are methods and properties that can be<br />

called without actually creating an object. For example, in Java the Math class<br />

has a static property that holds the value of PI. In Java code, you do not need<br />

to create a new Math object to access PI. You simply use Math.PI.<br />

In HAHTtalk Basic, you first need to get the class. Then you can access all the<br />

static members of the class. Here is an example.<br />

Sub printPi()<br />

Dim J As Object<br />

Set J = GetJavaClass("java.lang.Math")<br />

print J.PI ’PI is a static property of the Math class<br />

End Sub<br />

CreateTypedJavaNull<br />

Syntax<br />

Function CreateTypedJavaNull(className) As Object<br />

Description<br />

Returns a reference to an object of the type you specify in the className<br />

argument. The reference will have been set to null. This reference is useful<br />

when you want to pass a value of null as a parameter to a method. The null<br />

must have a data type associated with it so that the Java Virtual Machine will<br />

recognize the method’s signature.


Parameters<br />

Parameter Type Description<br />

Example<br />

Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

className String The case sensitive name of the Java<br />

class to which you want a null<br />

reference.<br />

The following statements create a null reference to an object of type<br />

HTMLCalendar:<br />

Dim MyCal As Object<br />

Set MyCal = CreateTypedJavaNull("HTMLCalendar")<br />

These statements are the equivalent of the following statement in Java:<br />

HAHTCalendar MyCal = null;<br />

Differences between HAHTtalk Basic and<br />

Java<br />

The most important thing you should know when working with HAHTtalk<br />

Basic and Java is that there are important differences between the two<br />

languages’ data types, which are described later in this section. However, if you<br />

are an experienced HAHTtalk Basic programmer and are just starting to use<br />

Java, here are some other general things that are different in the two<br />

languages.<br />

Java is strongly typed<br />

In HAHTtalk Basic, many data types are automatically converted to the<br />

necessary type. For example:<br />

sub MyTest(Fred As String)<br />

print Fred<br />

End Sub<br />

sub YourTest<br />

MyTest 5<br />

End Sub<br />

79


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

This HAHTtalk Basic code compiles and runs correctly because HAHTtalk Basic<br />

automatically converts the number 5 to the string “5” before passing it to the<br />

subroutine MyTest.<br />

Java is a strongly typed language — it requires that data types match exactly.<br />

If a data type does not match, you will get compiler errors or runtime errors.<br />

Parameter passing<br />

In HAHTtalk Basic parameters are passed either by reference (ByRef) or by<br />

value (ByVal). Java has no equivalent specifier. Instead, Java determines how<br />

parameters are passed by examining their types: all primitive types (such as<br />

int and short) are passed by value; objects are passed by reference.<br />

Since Java is strongly typed, it is important that parameter and return-value<br />

types match.<br />

Java is case sensitive<br />

HAHTtalk Basic is case insensitive; the following subroutine calls are<br />

equivalent:<br />

Call YourTest<br />

Call yourtest<br />

Java is case sensitive. Method and property names must match case exactly.<br />

For example, if a Java class has a method called GetMyStuff, and you have a<br />

variable called J, J.getmystuff is not the same as J.GetMyStuff.<br />

Locating objects<br />

Java uses a class path to help find binaries (.class files) for a specific object.<br />

The class path is a semicolon (for Windows platforms) or colon (for Unix)<br />

separated list of directory names or zip file names. Java looks from left to right<br />

along the class path for a given class file name. For example, if the function<br />

CreateJavaObject("MyObject") is specified, then the Java VM does a casesensitive<br />

search for a file called MyObject.class along the path.<br />

All class names do not have to be immediately along the class path — they can<br />

also be in subdirectories. For example, suppose the Java class path was set to<br />

C:\Fred and you want to create an instance of class found in<br />

C:\Fred\sub\myclass.class. To create an instance of the class, you would use<br />

the syntax CreateJavaObject("sub.myclass").<br />

80


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

For information on setting the class path, see the “Java Options” section of the<br />

<strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 2, “Using the <strong>IDE</strong>/IP’s Windows and<br />

Toolbars.”<br />

Mapping HAHTtalk Basic types to Java<br />

parameter types<br />

The following table shows how HAHTtalk Basic types map to Java types when<br />

passed as parameters.<br />

HAHTtalk<br />

Basic Type<br />

Size<br />

(Bytes)<br />

Description Java Type<br />

Integer 2 Integer variables are used to hold<br />

numbers within the following range:<br />

–32768


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

HAHTtalk<br />

Basic Type<br />

82<br />

Double 8 (64-bit)<br />

IEEE<br />

values<br />

A data type used to declare variables<br />

capable of holding real numbers with<br />

15–16 digits of precision. Double<br />

variables are used to hold numbers<br />

within the following ranges:<br />

Negative:<br />

-1.797693134862315E308<br />


HAHTtalk<br />

Basic Type<br />

Size<br />

(Bytes)<br />

Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

Description Java Type<br />

Array Varies An array of one of the above types. Not currently<br />

supported in<br />

<strong>HAHTsite</strong><br />

Mapping Java types to HAHTtalk Basic<br />

types<br />

You can pass Java variables into your HAHTtalk Basic code. The following table<br />

shows how Java method and field (or property) types map into HAHTtalk Basic<br />

types.<br />

Java type Description HAHTtalk Basic type<br />

boolean unsigned 8 bits Boolean<br />

byte signed 8 bits Integer<br />

char unsigned 16 bits String of 1 character<br />

short signed 16 bits Integer<br />

int signed 32 bits Long<br />

long signed 64 bits No equivalent<br />

float 32 bits Single<br />

double 64 bits Double<br />

String String object String<br />

object Java object Object<br />

array of type T An array of some type Not currently supported in<br />

<strong>HAHTsite</strong>.<br />

83


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

Troubleshooting: Java runtime errors<br />

The table below lists Java runtime errors that are issued by the <strong>HAHTsite</strong><br />

Application Server. The most common errors are 844 and 845. Error 844 (class<br />

not found) is typically caused by publishing to the wrong directory. Error 845<br />

(method not found) is typically caused by a parameter mismatch.<br />

Error<br />

number<br />

84<br />

Error text Typical reason(s)<br />

844 Java class className not<br />

found.<br />

845 Method methodName not<br />

found or not public in<br />

Java class className.<br />

846 Field fieldName not<br />

found or not public in<br />

Java class className.<br />

Class file is not on the class path.<br />

Wrong path to class given.<br />

Misspelling of class name (check<br />

case).<br />

Misspelled method name.<br />

Method is not declared public, so you<br />

do not have access to it.<br />

Parameter types you passed in do not<br />

match those of the method you<br />

specified.<br />

You need to refresh classes by<br />

restarting the Application Server.<br />

Misspelled field name.<br />

Specified field is not declared public,<br />

so you do not have access to it.<br />

You need to refresh classes by<br />

restarting the Application Server.<br />

847 Cannot load the Java VM. Misconfiguration due to missing<br />

javai.dll (or javai.so),<br />

HSInspector.class, or<br />

classes.zip.<br />

848 Required HAHTtalk Basic<br />

Java class requiredClass<br />

not found.<br />

849 The Java VM failed to<br />

load.<br />

Class path on Application Server<br />

could also be set up improperly.<br />

Missing HSInspector.class file or class<br />

path does not specify the directory<br />

where HSInspector.class lives.<br />

Same reasons as 848.


Error<br />

number<br />

850 Cannot convert parameter<br />

parameterNumber from a<br />

HAHTtalk Basic<br />

HAHTtalkBasicType to a<br />

Java JavaType.<br />

Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

Error text Typical reason(s)<br />

851 Cannot convert a<br />

HAHTtalk Basic<br />

HAHTtalkBasicType to a<br />

Java JavaType.<br />

852 Cannot convert a Java<br />

JavaType to a HAHTtalk<br />

Basic<br />

HAHTtalkBasicType.<br />

853 Cannot convert return<br />

value from a Java<br />

JavaType to a HAHTtalk<br />

Basic<br />

HAHTtalkBasicType.<br />

854 Cannot convert a<br />

HAHTtalk Basic array to a<br />

Java array.<br />

855 No Java class path<br />

specified. Please specify<br />

one using the HAHTtalk<br />

Basic administrator.<br />

856 Cannot create Java object.<br />

Maximum number<br />

(10,000) of Java objects<br />

reached.<br />

857 The following Java<br />

exception was thrown:<br />

exceptionName&Descr<br />

There is no supported Java type for<br />

the specified HAHTtalk Basic type for<br />

the specified parameter.<br />

There is no supported Java type for<br />

the specified HAHTtalk Basic type.<br />

There is no equivalent HAHTtalk<br />

Basic type for the specified Java type.<br />

There is no equivalent HAHTtalk<br />

Basic type for the specified Java type.<br />

Cannot pass HAHTtalk Basic arrays to<br />

Java methods.<br />

There is no class path configured for<br />

the Application Server.<br />

Each user can have a maximum of<br />

10,000 Java objects in use at one<br />

time.<br />

A Java object threw the specified<br />

exception that was not handled in<br />

the Java code.<br />

85


Chapter 4: Calling Server-side Java from HAHTtalk Basic<br />

86


<strong>HAHTsite</strong> Server<br />

Object Model<br />

5<br />

Introduction....................................................................................................89<br />

Built-in objects...........................................................................................90<br />

Getting references to the built-in objects ......................................................91<br />

From a Java project....................................................................................91<br />

From a HAHTtalk Basic project.................................................................96<br />

The Application object ...................................................................................97<br />

Application object methods ......................................................................97<br />

Application object variables ......................................................................98<br />

Multiple processes and application-level variables...................................99<br />

Retrieving Application object properties ................................................100<br />

Summary of Application object methods...............................................102<br />

The Session object ........................................................................................107<br />

Session state .............................................................................................107<br />

Session timeout........................................................................................108<br />

Event handling ........................................................................................108<br />

Creating a dynamic URL .........................................................................109<br />

Creating a static URL...............................................................................113<br />

Identification methods ............................................................................113<br />

Summary of Session object methods ......................................................114<br />

The Request object........................................................................................117<br />

Retrieving field values .............................................................................117<br />

87


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Retrieving cookie values ..........................................................................121<br />

Retrieving attachments............................................................................122<br />

Retrieving environment variables ...........................................................122<br />

Summary of Request object methods .....................................................123<br />

The Response object .....................................................................................126<br />

Writing headers........................................................................................126<br />

Setting cookies .........................................................................................127<br />

Writing the HTML output .......................................................................129<br />

Summary of Response object methods...................................................130<br />

88


Introduction<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

<strong>HAHTsite</strong>’s Server Object Model serves as a framework for a <strong>HAHTsite</strong> Web<br />

application. Using its built-in objects and methods, you can control the data<br />

passed to and from a Web browser client and get information about the<br />

application, the Web server, and the Application Server.<br />

If you look at HAHT_Intro’s ShoppingCart.html page (part of which is shown<br />

above), you can see two common uses of the built-in objects: retrieving data<br />

passed in the URL field, and calling a subroutine to store data in variables, to<br />

be shared across pages in a session. With the Server Object Model you can also<br />

perform operations such as:<br />

sharing variables across sessions, as well as across pages.<br />

setting and retrieving the values of one or more cookies.<br />

enforcing page sequence in a session. If your application requires that a<br />

user visit pages in a particular order — for example, users must fill out a<br />

form on one page before they can view another page — you can check<br />

for and enforce this requirement.<br />

managing the lifetime of a session, by controlling session timeouts.<br />

This chapter describes the Server Object Model’s built-in objects, which<br />

provide most of the functionality described above, and more. For information<br />

about controlling access to secure-static and dynamic pages, by setting and<br />

89


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

checking page and session privileges, see Chapter 12, “Access Control.” For<br />

information about creating CORBA clients and servers, see Chapter 14,<br />

“<strong>HAHTsite</strong> CORBA Capabilities.”<br />

Built-in objects<br />

From “What’s in a Java page?” on page 18, and “What’s in a HAHTtalk Basic<br />

page?” on page 53, you should already be familiar with the Page object. In a<br />

Java project, every dynamic page created in the <strong>IDE</strong> is a subclass of Page, called<br />

Hspagename. In a HAHTtalk Basic project, each page is a subroutine, called<br />

HS_pagename. You can also create dynamic pages programmatically, by<br />

implementing the HAHTPage interface (in Java) or by creating a HAHTtalk Basic<br />

subroutine to display a page.<br />

In addition to Page objects, each <strong>HAHTsite</strong> application contains several builtin<br />

objects. You don’t need to (and should not!) create the Server,<br />

Application, and Session objects; all you need is references to them. Each<br />

application also has built-in Request and Response objects; however, for<br />

special purposes you may want to create your own Request and/or Response<br />

object.<br />

The com.haht.Haht class contains methods that will return a reference to your<br />

application’s built-in objects; see “Getting references to the built-in objects”<br />

on page 91.<br />

The built-in objects are derived from the com.haht.HahtObject class, as shown<br />

in the tree below:<br />

HahtObject<br />

(implements ApplicationListener)<br />

Application<br />

90<br />

GeneratedApplication<br />

HahtApplication<br />

HahtEvent<br />

(implements HAHTPage)<br />

Page<br />

Request<br />

Response<br />

Server<br />

(implements SessionListener)<br />

Session<br />

GeneratedSession<br />

HahtSession<br />

The Server object contains get and put methods for storing variables<br />

shared among applications, as well as event handling methods. There is a<br />

single Server object for each hsserver process in the Application Server.<br />

The Application object has information about the current application.<br />

There is only one Application object, which may be shared by many<br />

clients simultaneously.


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

The Application object contains methods that return information about<br />

the current application, as well as event handlers that are triggered when<br />

the application has just started or is about to end, or when a session is<br />

about to start or has just ended. Like the Server object, it has get and put<br />

methods for storing application-level variables.<br />

The Session object contains information about the current session,<br />

which is defined as a browser client using the application. There is a<br />

separate Session object for each client. It contains methods to retrieve<br />

information about the current session, such as session privileges;<br />

methods to create URLs; and methods to control the session timeout. It<br />

also has two event handlers, onStart and onEnd, that are called when a<br />

session is created and just before it’s destroyed. Like the Server and<br />

Application objects, it has get and put methods for storing<br />

application-level variables.<br />

You use the Request object’s methods to retrieve data the client browser<br />

sends to the Web server. For example, when a user completes a form and<br />

presses the submit button, the form data is sent to the Web server, either<br />

on the URL or in a separate packet. The Request object has getURLField<br />

methods to retrieve these values.<br />

You use the Response object’s methods to generate HTML that the Web<br />

server sends to the browser, including methods to write HTML output<br />

and set cookies.<br />

Note - The HahtEvent class is the parent class for application-<br />

and session-level event handlers. For more information, see<br />

“Event handling in a Java project” on page 31 and “Event<br />

handling in a HAHTtalk Basic project” on page 66.<br />

Getting references to the built-in objects<br />

Depending on whether you are developing a Java project or a HAHTtalk Basic<br />

project, you will use different methods to get references to the Server Object<br />

Model’s built-in objects.<br />

From a Java project<br />

When you create a new Java project, the <strong>IDE</strong> creates a HahtApplication class<br />

and a HahtSession class, as subclasses of GeneratedApplication and<br />

91


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

GeneratedSession, respectively. You can add variables and methods to these<br />

classes and reference them from each dynamic page.<br />

Application and Session references in a dynamic page<br />

In a Java project, the generated code for a dynamic page defines two variables,<br />

hahtApplication and hahtSession, to refer to the Application and Session<br />

objects:<br />

Both hahtApplication and hahtSession are set in the constructor for the<br />

page, so their values are accessible anywhere in the code for that page. For<br />

example, if you have declared a variable lastName in HahtSession.java, this<br />

is how you would refer to it on a dynamic page:<br />

hahtSession.lastName<br />

Application and Session references in other Java source files<br />

In a Java source file other than a dynamic page, there are two ways to get a<br />

reference to the Application or Session object. If you simply need to use a<br />

method defined for the Application or Session class, you can use this<br />

procedure:<br />

1 Get a reference to the current application or session, using<br />

Haht.getApplication() or Haht.getSession().<br />

2 Use that reference to access the variable or method. For example, you can<br />

get a URL string, given a project ID:<br />

However, you may also need to access variables and methods that you have<br />

added to HahtApplication.java or HahtSession.java. In that case, you<br />

must use the second procedure, which is actually a superset of the first. (This<br />

92<br />

Java<br />

protected HahtApplication hahtApplication;<br />

protected HahtSession hahtSession;<br />

...<br />

hahtApplication = (HahtApplication) Haht.getApplication();<br />

hahtSession = (HahtSession) Haht.getSession();<br />

Java<br />

String myURL = Haht.getSession().getURL<br />

("89392C87BB91D2119141A02550C10000");


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

is the procedure used to define hahtSession and hahtApplication on<br />

dynamic pages.)<br />

1 Get a reference to the current application or session, using<br />

Haht.getApplication() or Haht.getSession().<br />

2 Cast the return value to type HahtApplication or HahtSession.<br />

3 Use that reference to access the variable or method. For example, suppose<br />

that in the code for a dynamic page, you want to print the value of a<br />

variable you’ve stored in the Application object. Your code would look<br />

something like this:<br />

Java<br />

HahtApplication myApp =<br />

(HahtApplication)Haht.getApplication();<br />

out.print(myApp.myVar);<br />

Session references in master projects and referred projects<br />

Both master projects and referred projects contain GeneratedSession.java<br />

and HahtSession.java files; however, in a master project, the class<br />

GeneratedSession extends com.haht.project.Session, while in a referred<br />

project, the GeneratedSession class extends the class<br />

com.haht.project.UtilitySession (see the figure below). The important<br />

point to note here is that the UtilitySession class does not represent a user<br />

session, as Session does; UtilitySession is a very general class from which<br />

GeneratedSession inherits only a small amount of functionality.<br />

93


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

In a master project:<br />

94<br />

com.haht.project.Session<br />

GeneratedSession<br />

HahtSession<br />

A Session object represents an entire session.<br />

com.haht.project.<br />

UtilitySession<br />

GeneratedSession<br />

HahtSession<br />

Master Project Referred Project<br />

A GeneratedSession object contains master-project extensions to the<br />

Session class such as references to objects that have been dragged and<br />

dropped onto the project’s Session folder. For example, the<br />

GeneratedSession object might contain a reference to a data agent<br />

representing a session recordset created by dragging and dropping a table<br />

onto the Session folder.<br />

A HahtSession object contains user-defined variables and methods.<br />

A referred project’s GeneratedSession and HahtSession objects are analogous<br />

to those in a master project. However, a referred project has no Session object<br />

associated with it. There is only one Session object per user session.<br />

How do you get references to these objects? <strong>HAHTsite</strong> generates the code that<br />

obtains references to these objects and assigns those references to variables.<br />

The matrix below shows the names you use to access objects in either a master<br />

project or a referred project from either a master project or a referred project.


Name Use<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

hahtSession In a master project, you should use this<br />

name to refer to the session’s Session<br />

object. You can also use it in a master<br />

project to refer to the master project’s<br />

GeneratedSession and HahtSession<br />

objects, but you shouldn’t do this if your<br />

project is, or might later become, a referred<br />

project. <strong>HAHTsite</strong> provides another name to<br />

use in this situation.<br />

In a referred project, you can only use the<br />

name to refer to the session’s Session<br />

object.<br />

projectName_hahtSessionExt In a master project, you can use a name of<br />

this form to refer to the master project’s<br />

extended objects (its GeneratedSession<br />

and HahtSession objects) and to a referred<br />

project’s extended objects. (The<br />

projectName portion of the name will<br />

vary depending on the project.)<br />

In a referred project, you use a name of this<br />

form to refer to the referred project’s<br />

extended objects.<br />

Briefly, here’s how you might use these names. Suppose that from your master<br />

project, you want to refer to a session recordset (a data agent) defined in the<br />

referred project ReferredProject. For the purposes of this example, assume that<br />

the session recordset was created by dragging a shared query named<br />

SharedQuery to the project’s Session folder. You could refer to this data agent<br />

using the following code:<br />

protected com.haht.project.datamanager.DataAgent da1 =<br />

ReferredProject_hahtSessionExt.getSharedQuery();<br />

Request and Response objects<br />

The run method for each page takes two arguments: aRequest and aResponse,<br />

which refer to the Request and Response objects, respectively. You can use<br />

these references if you add code to a dynamic page — either by adding in-line<br />

code to the HTML page, or by adding to the generated code in Server-side Code<br />

view.<br />

You can also call the Haht object’s getRequest and getResponse methods:<br />

95


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Page object<br />

The Session object’s returnHAHTPageObject method instantiates a page<br />

object and returns a reference to it; if the page has already been instantiated,<br />

it simply returns the object reference. For details, see “Calling a dynamic page<br />

from Java” on page 30.<br />

From a HAHTtalk Basic project<br />

In a HAHTtalk Basic project, the Server Object Model contains three<br />

predefined constants:<br />

96<br />

Java<br />

Request myRequest = Haht.getRequest();<br />

Response myResponse = Haht.getResponse();<br />

haht — a reference to the com.haht.Haht object<br />

hahtApplication — a reference to the current Application object<br />

hahtSession — a reference to the current Session object<br />

(As with other HAHTtalk Basic identifiers, the names for these constants are<br />

case insensitive.)<br />

You can use these references anywhere in the code for a dynamic page. For<br />

example, to retrieve the state ID for the current session, you would use code<br />

like this:<br />

HAHTtalk Basic<br />

Dim sStateId as String<br />

Set sStateId = hahtSession.getStateId()<br />

On code pages, you can use the Haht object’s getApplication and getSession<br />

methods to get references to the Application and Session objects, like this:<br />

HAHTtalk Basic<br />

Dim MyApp As Object<br />

Set MyApp = Haht.getApplication()<br />

Dim MySession As Object<br />

Set MySession = Haht.getSession()


Request and Response objects<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

The generated code for a page gets references to the Request and Response<br />

objects in this way:<br />

HAHTtalk Basic<br />

Dim aRequest As Object<br />

Dim aResponse As Object<br />

Set aRequest = Haht.getRequest()<br />

Set aResponse = Haht.getResponse()<br />

You can use these references if you add in-line code to a page, or if you add<br />

code in Server-side Code view. On a separate code page, you can call the<br />

getRequest and getResponse methods.<br />

The Page object<br />

In a HAHTtalk Basic project, you refer to a page, or call a page, simply by its<br />

name (recall that dynamic pages in the <strong>IDE</strong> have the prefix “HS_”).<br />

The Application object<br />

The Application object contains information about the current application.<br />

There is only one Application object, which may be shared by many clients<br />

simultaneously. On the other hand, there is a separate Session object for each<br />

client using the same application.<br />

Note - If you have configured the Application Server to run<br />

multiple processes, there will actually be one Application<br />

object per process. See the technical note “Multiple processes<br />

and application-level variables” on page 99.<br />

Application object methods<br />

The most commonly-used Application object methods can be divided into<br />

these types:<br />

Type Refer to<br />

Methods dealing with application<br />

variables<br />

“Application object variables” on page<br />

98<br />

97


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Type Refer to<br />

Methods to get the properties of the<br />

Application object<br />

In addition, to read about access control methods, see Chapter 12, “Access<br />

Control.” For information about CORBA, see Chapter 14, “<strong>HAHTsite</strong> CORBA<br />

Capabilities.”<br />

Application object variables<br />

In a Java project, you can store application-level variables directly in the<br />

HahtApplication class. The Application class also has get and put methods<br />

that you can use to create variables on the fly.<br />

In a HAHTtalk Basic project, you can use the get and put methods for<br />

application-level variables; this can be particularly useful in HAHTtalk Basic<br />

applications that call server-side Java, as a way to share variables.<br />

Get, put, and remove<br />

The put method associates a name with an object and stores the name/value<br />

pair in the Application object. The get method retrieves the stored value.<br />

There is also a remove method, that removes the object reference. In a Java<br />

project, the value you put must be an object; when you call get, you must cast<br />

the return type appropriately. In a HAHTtalk Basic project, the value you put<br />

can be an object or a string; the type conversion is done automatically on a<br />

get.<br />

Calling get for a variable that doesn’t exist returns a null object.<br />

Examples:<br />

98<br />

Java<br />

String s = "Hello world";<br />

hahtApplication.put("myvar", s);<br />

// Get the value we just put<br />

String s2 = hahtApplication.get("myvar");<br />

“Retrieving Application object<br />

properties” on page 100


HAHTtalk Basic<br />

Dim O as Object<br />

hahtApplication.put "myvar", "Hello world"<br />

’Get the value we just put<br />

Set O = hahtApplication.get("myvar")<br />

If O is not Nothing Then<br />

Print O<br />

Else<br />

Print "Variable not set" & ""<br />

End If<br />

Variable locking<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

If you are updating a variable that belongs to the Application object, it’s a<br />

good idea to lock the application’s variables until the operation has<br />

completed. Suppose you are updating several related variables, such as<br />

database access information. Because they are related, you don’t want any<br />

other sessions to access them until they have all been updated. In your<br />

program, you would lock the Application object’s variables each time you<br />

access them. If another session has the variables locked, your session waits<br />

until the other session calls the unlock method. Note that these methods work<br />

only if every access to those variables calls lock and unlock. In pseudocode:<br />

Call lock (if the Application object’s variables are locked by another session,<br />

waits until they are unlocked)<br />

Update variables<br />

Call unlock<br />

If your program doesn’t explicitly call the unlock method, the Application<br />

Server will unlock the Application object’s variables when the page ends or<br />

times out.<br />

Multiple processes and application-level variables<br />

What is the scope of an Application object’s variables? You can use the<br />

Application object to share variables across multiple sessions. However, it’s<br />

important to understand that, depending on your Application Server<br />

configuration, an application may be running in several processes, each with<br />

its own Application object and set of Session objects. See the drawing below,<br />

showing four processes running on two Application Servers. Each session can<br />

access the variables stored in the Application object, but only for that<br />

particular process. There is no communication between processes.<br />

99


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

You can use the Application object to cache variables for use by multiple<br />

sessions — as you could see in the Java example that printed the current<br />

number of sessions (“Example: onSessionStart, onSessionEnd” on page 33). In<br />

that example, an application-level variable, nActiveSessions, kept count of<br />

the number of active sessions. But since variables cannot be shared across<br />

processes, each process would have its own copy of the nActiveSessions<br />

variable.<br />

Retrieving Application object properties<br />

The Application object provides a number of methods for retrieving<br />

properties such as its name, directory name, or initial working directory. One<br />

commonly-used method is getAppData, which returns the value of an<br />

application property. For example, to get the dynamic URL, you would use this<br />

code:<br />

Java<br />

String myURL = hahtApplication.getAppData(0, "DynamicURL");<br />

100


HAHTtalk Basic<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Dim MyURL As String<br />

MyURL = hahtApplication.getAppData(0, "DynamicURL")<br />

This URL is determined by a project’s site properties, where it appears as the<br />

Dynamic-hsrun URL (seen below). You can use it as the prefix for URLs to<br />

applications.<br />

The first argument to getAppData is a subsite index. Site definitions, which<br />

exist at the project level, can contain definitions of subsites which will apply<br />

to certain project items. For example, you might want to publish part of a<br />

project to a secure Web server (one that supports the HTTPS protocol). Or you<br />

might want to include Perl scripts in a <strong>HAHTsite</strong> project and publish them<br />

directly to the Web server’s cgibin directory. For more information about<br />

subsites, see the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 4, “Working with<br />

Sites.”<br />

In a project without subsites, the site definition becomes the default subsite<br />

definition. In this case, use zero as the subsite index.<br />

The second argument is the property whose value you want returned. It can<br />

be one of the following:<br />

101


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Field Description<br />

"AppendString" String (if any) this subsite’s Web server appends to<br />

the URL of a dynamic page.<br />

Example: ?<br />

"DynamicURL" URL for the directory defined by the Web server’s<br />

CGI alias.<br />

Example: http://www.haht.com/cgi-bin<br />

"HSrunAppendString" String (if any) this subsite’s Web server appends to<br />

the HSrun command.<br />

"HSrunExtension" String (if any) this subsite’s Web server expects the<br />

HSrun executable to have.<br />

Example: .hse<br />

"HSrunParamDelimiter" Character used as a delimiter between parameters<br />

passed on the URL.<br />

Example: &<br />

"StaticROOT" Path to subsite’s document root directory.<br />

Example: \\moe\D\Netscape\SuiteSpot\docs<br />

"StaticURL" URL to default subsite’s document root directory.<br />

Same as getStaticURL.<br />

Example: http://www.haht.com<br />

"ProjectSubDir" 1<br />

1. For compatibility with past releases, “SubDirURL” can be substituted for “ProjectSubDir.”<br />

Summary of Application object methods<br />

The following table lists the methods available with the Application object<br />

(with the exception of methods related to access control and CORBA, which<br />

are covered in later chapters). For a fuller description of each method, consult<br />

the on-line help for the Server Object Model.<br />

102<br />

Project subdirectory under application root<br />

directory.<br />

Example: %project%<br />

"SubSiteName" Subsite name associated with index (zero-based).<br />

Same as getSubSite.<br />

Example: default


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Note - When a file system pathname is returned (rather than a<br />

WWW URL), its format is operating system-dependent. For<br />

example, for an NT system, getDirname would return<br />

\subdirectory\, while for a UNIX system, it would return<br />

/subdirectory/.<br />

Method Description<br />

addApplicationListener (Java only). Adds an event listener to the<br />

Application Event Listener.<br />

get Retrieves the value of a name/value pair stored<br />

in the Application object (see put). The<br />

value is returned as an Object and, in Java,<br />

must be cast to the appropriate class.<br />

getAppData Depending on the fieldName argument,<br />

returns information about the application for<br />

the given subsite.<br />

getDirName Directory part of <strong>HAHTsite</strong> executable file<br />

pathname, relative to the application root<br />

directory.<br />

NT example: \JSimple\<br />

UNIX example: /Jsimple/<br />

This value is useful for accessing user data files<br />

that are organized in the same manner as the<br />

application; the data files will be in a parallel<br />

subdirectory with the same name under the<br />

Userroot directory. Note, however, that this<br />

directory is relative to the configured<br />

Application Root directory. Thus, what is<br />

returned as ‘/’ here may indeed be<br />

‘usr/local/WebApp/AppRoot’.<br />

getName Application name without extension or path.<br />

Example: Test<br />

getPathName Full pathname of <strong>HAHTsite</strong> executable file.<br />

NT example: \JSimple\Test.htx<br />

UNIX example: /JSimple/Test.htx<br />

103


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Method Description<br />

getStaticRoot Path to Web server’s document root directory<br />

for the default subsite. The document root<br />

directory is where the Web server stores its<br />

static pages.<br />

NT example: \\moe\d\hahtsite\doctree<br />

UNIX example:<br />

/usr/local/hahtsite/doctree<br />

getStaticURL URL to default subsite’s document root<br />

directory.<br />

Example: http://www.haht.com<br />

getString Retrieves the value of a name/value pair that<br />

is a string stored in the Application object.<br />

See putString.<br />

getSubSite Subsite name associated with index (zerobased).<br />

Example: default<br />

getSubSiteCount Number of subsites defined for the<br />

application, including the default subsite.<br />

104


Method Description<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

getUserRoot Path to application’s initial working directory<br />

(operating system dependent). If your code<br />

reads or writes a file without specifying an<br />

absolute path, the application looks for the<br />

file in the application’s userroot directory.<br />

Files that a user attaches to a form (using File<br />

Upload) are also placed in userroot.<br />

When you install the Application Server or<br />

modify its properties, you set the userroot<br />

Transfer URL (shown in a site definition<br />

below), which defaults to<br />

<strong>HAHTsite</strong>InstallDir\userroot. If you<br />

publish your project to a subdirectory, the<br />

subdirectory’s name is appended to the<br />

userroot path (for example,<br />

\\moe\WebDocs\userroot\MyProject).<br />

Dynamic - server group:<br />

Server Group Host: moe.haht.com<br />

Server Group: webapps<br />

File: d:\hahtsite\sites\cache\moe.haht.com<br />

\webapps.hsg<br />

Subdirectory: %project%<br />

State IDs in: Cookies<br />

Location: approot<br />

Transfer URL:<br />

\\moe\WebDocs\approot<br />

Location: userroot<br />

Transfer URL:<br />

\\moe\WebDocs\userroot<br />

Location: javaroot<br />

Transfer URL:<br />

\\moe\WebDocs\javaroot<br />

isBasicApp Returns true if this is a HAHTtalk Basic<br />

application.<br />

isJavaApp Returns true if this is a Java application.<br />

isRecordingPageVisits Returns true if sessions of this application are<br />

recording a history of pages visited.<br />

isUsingCookies Returns true if the application was published<br />

to use cookies (based on the site definition).<br />

For more information about setting the “use<br />

Cookies/use URL” property, see the <strong>HAHTsite</strong><br />

<strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 4, “Working<br />

with Sites.”<br />

105


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Method Description<br />

lock Acquires a lock for the Application object’s<br />

variables.<br />

onSessionStart,<br />

onSessionEnd<br />

106<br />

Event handler called when a new session is<br />

created, or right before a session is destroyed.<br />

In a Java project, can be customized in<br />

HahtApplication.java. (Not accessible in<br />

HAHTtalk Basic projects.)<br />

onStart, onEnd Event handler called when the application has<br />

just been created or just before it is<br />

terminated. In a Java project, can be<br />

customized in HahtApplication.java. (Not<br />

accessible in HAHTtalk Basic projects.)<br />

put Associates an object with a name and stores<br />

the name/value pair in the Application<br />

object. See get.<br />

putString Associates a string value with a name and<br />

stores the name/value pair in the<br />

Application object. See getString.<br />

remove Removes the association of the named<br />

variable with a value. Applies to name/value<br />

pairs created with put or putString.<br />

removeApplicationListener (Java projects only). Removes an event listener<br />

from the list of Application listeners.<br />

startRecordingPageVisits,<br />

stopRecordingPageVisits<br />

Tells the Application Server to begin/stop<br />

recording a history of pages visited.<br />

To retrieve this history, use the Session<br />

object’s getPagesVisited method.<br />

unlock Releases the lock for the Application<br />

object’s variables.<br />

writeLog Writes a string to the Application Server’s log<br />

file.


The Session object<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Unlike the Application object, a Session object applies to a single user. When<br />

a browser initially requests a Web page, the Application Server creates a<br />

Session object unless one has already been created for that user. A Session<br />

object continues to exist until it’s terminated by the Application Server (see<br />

“Session timeout” on page 108).<br />

Like the Application class, the Session class has get and put methods that<br />

you can use to create variables on the fly, and it has lock and unlock methods<br />

that let you serialize access to session-level variables (see “Variable locking” on<br />

page 99).<br />

In a Java project, you can also edit HahtSession.java directly, to declare and<br />

set variables as well as to add event handlers.<br />

In a HAHTtalk Basic project, you can use include files or store variables in the<br />

globals.hbs file. (Note that variables are not shared across sessions in a<br />

HAHTtalk Basic project.) For more information, see “Include files and<br />

Globals.hbs” on page 63.<br />

Session-related topics covered in this chapter include:<br />

Topic Reference<br />

Session state “Session state” on page 107<br />

Session timeout “Session timeout” on page 108<br />

Event handling at the session level “Event handling” on page 108<br />

Creating a URL for a project item or for<br />

a location outside the project<br />

Determining whether this is the first<br />

page of a session; identifying the<br />

current method/subroutine or the<br />

calling method/subroutine<br />

You may also be interested in the explanation of session privileges and access<br />

control in Chapter 12, “Access Control.”<br />

Session state<br />

“Creating a dynamic URL” on page 109<br />

“Identification methods” on page 113<br />

There are two important concepts to understand at the session level: state and<br />

timeout.<br />

107


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

State is the collection of information available to an application. Typical Web<br />

applications are inherently stateless, meaning that they don’t retain<br />

information between pages. In <strong>HAHTsite</strong>, Session objects maintain state even<br />

if the user moves to other Web pages, until the session times out. This means<br />

that you can store session-level variables in the Session object and access<br />

them from multiple pages.<br />

One use for session-level variables is to store information about user<br />

preferences. Another is to store a recordset returned by a database command.<br />

You can then access the recordset across page boundaries — a great efficiency.<br />

(For details, see the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>, Chapter 15, “Connecting<br />

to a Data Source.”)<br />

Session timeout<br />

When a user leaves a Web application, how does the application know? There<br />

is no quit or exit button, and in fact the user might return after browsing other<br />

pages. On the other hand, you wouldn’t want to keep a session alive<br />

indefinitely — it would eat up your resources. The answer lies in the<br />

Application Server, which controls the session timeout — that is, how many<br />

seconds must elapse, with the application idle, before the Application Server<br />

terminates the session. The default timeout value is 300 seconds, set in the<br />

Application Server configuration. However, you can override this default for<br />

the current session. Here are the applicable methods:<br />

108<br />

The setTimeout method sets the timeout value for the current session.<br />

The getTimeout method returns the number of seconds before timeout<br />

occurs.<br />

(There is also a keepAlive method, which resets the timeout value; this<br />

method is useful only when you are accessing CORBA objects.)<br />

In addition to these methods, in a HAHTtalk Basic project, you can call Stop<br />

or End to immediately stop execution of the application. In a Java project, you<br />

can call the Session object’s abandon method.<br />

Event handling<br />

When a session ends, <strong>HAHTsite</strong> automatically performs cleanup tasks such as<br />

closing any open data source connections, destroying OLE and Java objects,<br />

and freeing memory. However, you may want to save the session state, so that<br />

you can restore it if the user logs back in. Or you may want to perform certain<br />

initialization procedures when a session begins. The Session object includes<br />

onStart and onEnd event handlers that you can customize (in Java) or override


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

(in HAHTtalk Basic). Refer to “Event handling in a Java project” on page 31, or<br />

“Event handling in a HAHTtalk Basic project” on page 66.<br />

Creating a dynamic URL<br />

The Session object provides several methods for building a URL that you can<br />

use to link from a dynamic page to another page, to an image, or to an image<br />

map. These methods require either a project ID or a string representing the<br />

page, image, or image map.<br />

Building a URL from a project ID<br />

The getURL method locates a project item — a page, an image, or an image<br />

map — by means of its project ID and returns a string containing a URL for that<br />

item.<br />

The getURL method has a number of variations, with different parameters,<br />

including:<br />

project ID — a universally unique identifier that <strong>HAHTsite</strong> assigns to a<br />

project item. Within the <strong>IDE</strong>, you can view a project item’s ID by clicking<br />

on the item, choosing Edit > Properties and clicking the File tab.<br />

default string — a string that is to be returned if the method fails to<br />

locate the item. This can occur if a project item was deleted but is still<br />

referenced somewhere in the source code. If you don’t specify a default<br />

string and the method fails, it returns an empty string.<br />

append string — a bookmark or query string to be appended to the<br />

generated URL. A bookmark consists of the pound sign (#), followed by<br />

the string for a bookmark anchor. A query string should contain one or<br />

more name/value pairs, separated by ampersands — for example,<br />

“Name=Johnson&City=London”.<br />

method (Java only) — the method to be run on the destination page. The<br />

method defaults to run. This argument is disregarded in HAHTtalk Basic<br />

projects.<br />

wantFullURL — a boolean value; if true, the method returns a complete<br />

URL, rather than a relative URL. You might set this value to true to<br />

produce a string to redirect users to another dynamic page. Some<br />

browsers require full URLs in this case. A full URL would look something<br />

like this:<br />

http://www.haht.com/cgi-bin/hsrun/webapps40/PJ2/StateId/<br />

TbOIpYMPgKipKLh90G357_Ws_T/HAHTpage/PJ2.HsPageTwo.run<br />

109


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

110<br />

while a relative URL might look like this for the first dynamic page:<br />

StateId/TbOMAYMPp5MpKLxZ0G3xK_WCL1/HAHTpage/PJ2.HsPageTwo.run<br />

and like this for subsequent dynamic pages:<br />

../HAHTpage/PJ2.HsPageTwo.run<br />

Note that if state IDs are being passed in cookies, rather than on the URL,<br />

you will not see a state ID in the URL string returned.<br />

The default for this argument is false — that is, relative URLs.<br />

wantStartURL — a boolean value; if true, the method returns a URL for<br />

calling the page from a static page, including the .htx or .hjx file and the<br />

“start=” string. It does not include a state ID, and it does start another<br />

session instance. If you set wantStartURL to true, you will always get a<br />

full URL, regardless of the setting for wantFullURL. Here’s an example of<br />

the string returned:<br />

http://www.haht.com/cgi-bin/hsrun/webapps40/PJ2/<br />

PJ2.hjx;start=PJ2.HsPageTwo.run<br />

The default for this argument is false.<br />

Example: Building a URL<br />

This example programmatically builds an anchor tag and target URL for a<br />

dynamic page, using relative URLs (the default). The example calls getURL,<br />

passing it the project ID for the destination page. Then it inserts the return<br />

value in an anchor tag.<br />

Java<br />

String myURL = hahtSession.getURL<br />

("74FC8E62E969D2119141748209C10000");<br />

out.print(" Page2 ");<br />

HAHTtalk Basic<br />

Dim MyURL As String<br />

MyURL = hahtSession.getURL("74FC8E62E969D2119141748209C10000")<br />

Print " Page2 "<br />

At runtime, getURL adds the correct CGI delimiter (such as “?”), depending on<br />

the target Web server. If the call is being made from the first dynamic page of<br />

the application, then getURL returns a URL containing the state ID (if state IDs<br />

are being passed in URLs rather than cookies); the HTML for the anchor tag<br />

looks similar to this:


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

PageTwo <br />

If this isn’t the first dynamic page in the sequence, then getURL returns a<br />

relative URL, and the HTML looks like this.<br />

PageTwo <br />

(This is the output from a Java project; in a HAHTtalk Basic project, it would<br />

look the same, except that “HsPageTwo.run” would be replaced by<br />

“HS_PageTwo.”)<br />

If the Web server has been defined as storing state information in cookies, then<br />

the state ID is passed in a cookie instead of on the URL. For more information<br />

about cookies and Web browsers, see the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>,<br />

Chapter 4, “Working with Sites.”<br />

Creating a dynamic URL for an image map, page, or file<br />

In addition to the getURL method, there are three methods that return a<br />

dynamic URL for an image map, a dynamic page, or a file (for example, a<br />

secure static page), without requiring the project ID as an argument. Instead,<br />

you supply a string containing the name of the page, image map, or file.<br />

(There is a second, optional argument: the name of a subsite.)<br />

These URLs can refer to elements outside the project, or even to elements that<br />

don’t yet exist (for example, files you will later copy to the approot directory).<br />

<strong>HAHTsite</strong> doesn’t check on the validity of the URL it creates; it simply accepts<br />

the input you supply and creates a URL by adding the state ID and the CGI<br />

delimiter for the Web server you’re publishing to.<br />

createPageURL creates a URL for a dynamic page. In a Java project, its<br />

argument is the page’s fully-qualified run method — that is,<br />

packagename.classname.run. In a HAHTtalk Basic project, its argument is<br />

the name of the page subroutine (HS_pagename).<br />

This code returns a dynamic page URL.<br />

Java<br />

String myPageURL =<br />

hahtSession.createPageURL("MyProject.HsPageTwo.run");<br />

HAHTtalk Basic<br />

Dim MyPageURL As String<br />

MyPageURL = hahtSession.createPageURL("HS_PageTwo")<br />

111


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

112<br />

createMapURL creates a URL for an image map. Its argument is the<br />

filename for a dynamic server-side image map (.hmp).<br />

This example displays a dynamic image map (“MyMap.hmp,” based on an<br />

image “Globe.gif”). It calls two Session methods: one to create a dynamic<br />

map URL, and one to create a static URL (for more information on that<br />

method, see “Creating a static URL” on page 113).<br />

Java<br />

out.print("");<br />

HAHTtalk Basic<br />

Print "" & HSCRLF<br />

createFileURL creates a URL for a file stored in the approot directory,<br />

such as a secure static page.<br />

This code returns a URL for a secure static page.<br />

Java<br />

String myFileURL =<br />

hahtSession.createFileURL("MySecurePage.html");<br />

HAHTtalk Basic<br />

Dim MyFileURL As String<br />

MyFileURL = hahtSession.createFileURL("MySecurePage.html")


Creating a static URL<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

One additional method creates a URL for a static page; its arguments are the<br />

name of the page and, optionally, a subsite name. Given a null page name, it<br />

returns the URL for the staticroot directory.<br />

Suppose your site is called www.mysite.com, and you want to create an HTML<br />

anchor with the destination of<br />

http://www.mysite.com/MyProject/Static.html<br />

You would use code like this:<br />

Java<br />

String myStaticURL =<br />

hahtSession.createStaticURL("StaticPage.htm");<br />

out.print(" Static page ");<br />

HAHTtalk Basic<br />

Dim MyStaticURL As String<br />

MyStaticURL = hahtSession.createStaticURL("MyStaticPage.htm")<br />

Print " StaticPage<br />

"<br />

Identification methods<br />

The Session object has additional methods for purposes such as finding out if<br />

this is the first dynamic page of the session, and finding the name of the<br />

calling routine.<br />

isNewApp<br />

The isNewApp method returns true if this is the first dynamic page of a session.<br />

One simple use for this method is to conditionally display a welcome message<br />

when a user first invokes an application. It can also be used to control how a<br />

page generates URLs in a case where the user can return to the start page via a<br />

text anchor.<br />

113


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

whoAmI and whoCalledMe<br />

The whoAmI method returns the name of the current method or subroutine. If<br />

you were placing a clip on a number of different pages, you could call whoAmI<br />

within the clip to customize some part of the output, depending on the<br />

current page.<br />

The whoCalledMe method returns the name of the calling method or<br />

subroutine. You might invoke whoCalledMe in a general-purpose method or<br />

subroutine that might be called by several different pages.<br />

Summary of Session object methods<br />

This table summarizes the methods of the Session object. It does not include<br />

methods for access control or for CORBA, which are described in later<br />

chapters.<br />

For particulars, consult the online help for the Server Object Model.<br />

Method Description<br />

abandon Terminates the session after the page completes.<br />

addSessionListener (Java projects only). Adds an event listener to the<br />

Session Event Listener.<br />

auditMessage Writes a message to an audit file keyed to a hit<br />

number.<br />

auditPage Turns on session auditing for the current page. The<br />

audit files contain information about requests and<br />

responses and user-generated auditing messages.<br />

callByProjID Calls a dynamic page, given its project ID.<br />

createFileURL Returns the URL for a file, including a secure static<br />

page.<br />

createMapURL Returns the URL for a dynamic image map.<br />

createPageURL Returns the URL for a dynamic page.<br />

createStaticURL Returns the URL for a static page.<br />

endAuditing Stops session auditing.<br />

get Retrieves the value of a name/value pair stored in<br />

the Session object. See put.<br />

114


Method Description<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

getAdoConnStrByID Returns the connection string associated with the<br />

ADO connection that has a particular project ID.<br />

getConnectionManager Returns a reference to the session’s<br />

DMConnectionManager object.<br />

getErrors Returns a reference to the session’s Errors object.<br />

getHostName Returns a string containing the hostname of the<br />

current machine. This method is useful, for<br />

example, to determine which background server is<br />

generating an error.<br />

getPagesVisited Returns a PagesVisited object with the dynamic<br />

and secure-static pages visited by this session.<br />

getServerGroupName Returns a string containing the name of the server<br />

group to which the project was published (as set in<br />

the project’s site description; see the example<br />

below). This value can be used to generate a URL,<br />

but it’s not usually required because most URLs are<br />

relative to the application’s root directory.<br />

Dynamic - server group<br />

Server Group Host:moe.haht.com<br />

Server Group:webapps<br />

File: d:\hahtsite\masters\moe.haht.com\<br />

webapps40.hsg<br />

getStateCookieString Returns a string that is the cookie for the current<br />

session. This string is meaningful if the site is set up<br />

to use cookies; see the Application object’s<br />

isUsingCookies method. The string includes the<br />

state ID and CGI path and looks something like<br />

this:<br />

Set-Cookie: HS_StateId=TbI-v6MO-<br />

GepKs3M0GYjh-RCNw; path=/cgibin/hsrun/webapps40/ExamplProj/<br />

getStateId Returns the current state ID. Each session has a<br />

unique state ID, which is useful for naming<br />

temporary files or CORBA objects.<br />

getString Retrieves the value of a variable stored in the<br />

Session object using putString. Also see get.<br />

115


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Method Description<br />

getTimeout Returns the timeout value for the current session —<br />

that is, how many seconds must elapse, with the<br />

user not accessing the application, before the<br />

Application Server will terminate the session. See<br />

setTimeout, keepAlive.<br />

getURL Returns the URL for a project item, given a project<br />

ID.<br />

getUserName Returns the user name (if any) associated with the<br />

current session. See setUserName.<br />

isNewApp Returns true if this is the first dynamic page<br />

executed in a new instance of an application. This<br />

method returns false for every other dynamic<br />

page executed in the application.<br />

keepAlive Resets the timeout value, to keep a session from<br />

timing out. See getTimeout, setTimeOut.<br />

lock Blocks other client threads from modifying data<br />

stored in the Session object.<br />

onStart, onEnd Event handlers called when a session is about to<br />

start or end. In a Java project, you can customize<br />

these methods in HahtSession.java. In a<br />

HAHTtalk Basic project, you can override them<br />

with the HahtSessionOnStart and<br />

HahtSessionOnEnd pseudo-methods.<br />

put Associates a value with a name and stores the<br />

name/value pair in the Session object. See get.<br />

putString Associates a string value with a name and stores the<br />

name/value pair in the Session object. See<br />

getString.<br />

remove Removes the association of the named variable<br />

with a value. Applies to name/value pairs created<br />

with put or putString.<br />

removeSessionListener (Java projects only). Removes an event listener<br />

from the list of session listeners.<br />

returnHAHTPageObject (Java projects only). If the requested page has<br />

already been instantiated, returns a reference to<br />

that object. Otherwise, the method instantiates the<br />

page and returns a reference to it.<br />

116


Method Description<br />

The Request object<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

setTimeout Sets the timeout value for the current session, in<br />

seconds. See getTimeout, keepAlive.<br />

setUserName Associates a user name with a session.<br />

startAuditing Starts session auditing, beginning with the current<br />

page.<br />

unlock Disables a lock that has been preventing other<br />

client threads from modifying data stored in the<br />

Session object.<br />

whoAmI Returns a string containing the name of the<br />

currently executing function.<br />

whoCalledMe Returns a string containing the name of the calling<br />

function.<br />

The Request object lets you access data a browser sends to the Web server with<br />

an HTTP request, including:<br />

Topic Refer to<br />

Getting the value of a field “Retrieving field values” on page 117<br />

Getting the value of a cookie “Retrieving cookie values” on page 121<br />

Getting information about the Web<br />

server and the remote host making the<br />

request<br />

Retrieving field values<br />

“Retrieving environment variables” on<br />

page 122<br />

During a session, the Web browser passes data to the Web server in the form<br />

of name/value pairs. One source of such data is a form. On a Web page, forms<br />

have many uses — for example, collecting data that may be entered into a<br />

database, or displaying read-only information. When a user enters<br />

information into a form, that information can be sent back to the Web server<br />

in one of two ways:<br />

117


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

118<br />

If the form’s method is GET, the data is sent as part of the URL string,<br />

which looks something like this:<br />

Name=Scott&Location=SouthPole&Button1=Submit<br />

If the form’s method is POST, the data is sent to the Web server in a<br />

separate message packet.<br />

Field variables can come from other sources besides a form. For example, you<br />

might design a Web page that passes parameters on a link (using the link’s<br />

Query field). Or you might place in-line code on a Web page that calculates a<br />

value and passes it to the destination page. Each variable is passed as a<br />

name/value pair on the URL.<br />

The catalog_main.html page from Haht_Intro demonstrates two methods of<br />

passing fields to a destination page.<br />

First of all, each category (OUTDOOR, HOUSEHOLD, and so on) is actually an<br />

image which functions as a link to the destination page. The query string for<br />

the link contains the category of item being searched for — for example,<br />

“CatGrp=4” for Outdoor items. In addition, you can enter a product name and<br />

click on SEARCH BY NAME, which adds the name/value pair<br />

“SearchName=youritem” to the query string.


Retrieving field values<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Whether the data comes from a form or by some other means, a request<br />

typically includes a number of field variables. The Request object’s<br />

getURLField method lets you access these values without the need to<br />

determine whether the data was sent using GET or POST. Given a field name,<br />

getURLField returns the field’s value.<br />

Returning to the Haht_Intro example, the destination page,<br />

CatalogDisp.html, first tests to see if the query string has a value for<br />

“CatGrp”; if that value is missing, it tests for a value for “SearchName.” It uses<br />

one of those values to define a shared query over the database.<br />

HAHTtalk Basic<br />

If aRequest.getURLField("CatGrp") "" Then<br />

...<br />

ElseIf aRequest.getURLField("SearchName") "" Then<br />

...<br />

sParam = "'%" & aRequest.getURLField("SearchName") & "%'"<br />

...<br />

End If<br />

Testing for a field’s existence<br />

The Haht_Intro example tests for an empty string, which can mean one of two<br />

things: either the field cannot be found, or the field actually contains an<br />

empty string (""). If you simply want to check whether a field exists, use the<br />

getURLFieldExists or getURLFieldCount method.<br />

Retrieving a field’s value by its index<br />

If you call getURLField with an index into the collection of field variables, it<br />

returns the name/value string corresponding to that index. To retrieve the<br />

values of all fields in a form, you could use code like this:<br />

Java<br />

for (int fieldNum=1; fieldNum


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

HAHTtalk Basic<br />

Dim FieldNum As Integer<br />

For FieldNum = 1 to aRequest.getURLFieldCount()<br />

Print aRequest.getURLField(FieldNum) & ""<br />

Next FieldNum<br />

(Note that indexing into the field array is one-based, not zero-based.) In this<br />

case, each field would be returned as a name/value string, like this:<br />

txtLastName=Simpson<br />

txtFirstName=Bart<br />

txtCity=Springfield<br />

Button1=Submit<br />

If you index past the number of available fields, the method returns an empty<br />

string.<br />

Fields with multiple values<br />

Sometimes a form will have more than one value for the same field. For<br />

example, a list box like the one shown below contains multiple values, and the<br />

user can select more than one item in the list:<br />

In this case, the browser sends a name/value pair, using the same fieldname,<br />

for each item selected — for example, "txtCity=Berlin&txtCity=Amsterdam".<br />

To retrieve these values, you use the same methods as above, but with an<br />

additional argument:<br />

120<br />

getURLField (fieldname, n) returns the value of the nth occurrence of<br />

fieldname.<br />

getURLFieldCount (fieldname) returns the number of values the<br />

browser sent for a particular field. A count of zero means that the field<br />

isn’t present in the form data; perhaps the user made no selection.<br />

getURLFieldExists (fieldname, n) returns true if occurrence n of field<br />

fieldname exists, and false otherwise.


Adding fields and overriding field values<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

On the destination page, you can call setURLField to override the value of a<br />

field, and you can call addURLField to set the value of an additional field,<br />

which will then behave as if it had been passed from the calling page.<br />

Retrieving cookie values<br />

A cookie is a string passed in the HTTP headers between a Web server and a<br />

browser. If the browser is configured to accept cookies, it will store the cookies<br />

on the user’s system and later, on request, will make the cookie available to the<br />

Web server. Information stored in cookies can include items such as user<br />

names, user preferences, or pages last visited. In <strong>HAHTsite</strong>, if the site is<br />

configured to use cookies, the state ID is also passed in a cookie.<br />

The Response object contains methods to set cookies; the Request object,<br />

methods to retrieve cookie values. You retrieve cookie values just as you<br />

retrieve field values.<br />

getCookieCount returns the number of cookies sent from the browser.<br />

getCookie(cookie) returns the value of the named cookie.<br />

getCookie(index) treats the cookies like an array and returns the cookie<br />

corresponding to the index argument; the first cookie has an index of<br />

one.<br />

Retrieving cookie collections<br />

A single cookie may store several pieces of data — for example,<br />

“dimensions=height=10&width=5”. These multiple-value cookies are also<br />

called cookie collections. To retrieve these values, you must use the getCookie<br />

method and then parse the results. For example,<br />

Java<br />

String myCookie = aRequest.getCookie("dimensions");<br />

HAHTtalk Basic<br />

Dim MyCookie As String<br />

MyCookie = aRequest.getCookie("dimensions")<br />

would return “height=10&width=5”. For information on setting these cookie<br />

values, see “Multiple values within a single cookie” on page 128.<br />

121


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Retrieving multiple cookies with the same name<br />

A cookie collection (above) refers to a single cookie with multiple values.<br />

However, you can also have several cookies with the same name but different<br />

paths. In this case, they are all sent with the request string, beginning with the<br />

deepest path. For example, the cookie with a path of “www/home/products”<br />

would appear on the string before “www/home.” If you simply call<br />

aRequest.getCookie(cookie), you will retrieve the first cookie value on the<br />

string. However, you can also index into the set of cookies:<br />

122<br />

getCookieCount(cookie) returns the number of values returned for this<br />

cookie.<br />

getCookie(cookie, index) returns the cookie value corresponding to<br />

index.<br />

For more information on cookies, including the path field, see “Setting<br />

cookies” on page 127.<br />

Retrieving attachments<br />

An HTTP request often includes one or more attachments, which are placed in<br />

temporary files in the Application Server’s userroot directory.<br />

getURLAttachmentExists returns true if the named attachment exists,<br />

and false otherwise.<br />

getURLAttachmentCount returns the number of attachments transferred.<br />

getURLAttachment returns the name of the temporary file associated with<br />

the file upload form field.<br />

getURLAttachmentType returns the content-type for the attachment<br />

associated with the file upload form field. If the browser didn’t send a<br />

content-type, then the return value is an empty string.<br />

For more information about attachments, including an example, see<br />

“Working with a file attachment” on page 142.<br />

Retrieving environment variables<br />

An HTTP request can include information such as the request method (“GET,”<br />

“POST,” and so on) or the content-type or length of the data being transferred.<br />

The Web server passes this information to the CGI program in the form of<br />

environment variables.<br />

Just as the getURLField method retrieves the value of a form field, the<br />

getServerVariable method retrieves the value of an environment variable.


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

getServerVariableCount returns the total number of environment<br />

variables passed to the Web server.<br />

getServerVariable(variablename) returns the value of an environment<br />

variable. (The name is not case sensitive.)<br />

getServerVariable(index) returns the value of the environment variable<br />

corresponding to the given index, in the form name=value.<br />

If the name can’t be found, or if the index into the collection of environment<br />

variables is out of range, the method returns an empty string.<br />

Tip - If you are debugging an application, you can view the<br />

Web server’s environment variables in <strong>HAHTsite</strong>’s Output<br />

window.<br />

This code prints out all the environment variables returned by the Web server:<br />

Java<br />

int numVars = aRequest.getServerVariableCount();<br />

for (int i = 0; i < numVars; i++) {<br />

out.print(aRequest.getServerVariable(i) + "");<br />

}<br />

HAHTtalk Basic<br />

Dim NumVars As Integer, FieldNum As Integer<br />

NumVars = aRequest.getServerVariableCount()<br />

For FieldNum = 1 to NumVars<br />

Print aRequest.getServerVariable(FieldNum) + ""<br />

Next FieldNum<br />

The environment variables returned depend on the Web server you’re using<br />

and the operating system under which you are running. For more<br />

information, consult the documentation for your Web server.<br />

Summary of Request object methods<br />

This table summarizes the methods of the Request object. For particulars,<br />

consult the online help for the Server Object Model.<br />

123


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Method Description<br />

addURLField Adds a name/value pair to the set of fields<br />

passed from the calling page. You can then<br />

retrieve its value with getURLField.<br />

getCookie Given the name of a cookie, returns its value.<br />

Given an index, treats the cookies like an array<br />

and returns the cookie corresponding to the<br />

index argument; the first cookie has an index<br />

of one.<br />

Given a cookie name and an index n, returns<br />

the value of the nth occurrence of the cookie.<br />

getCookieCount Returns the number of cookies sent from the<br />

browser.<br />

Given a cookie name, returns the number of<br />

cookies with this name.<br />

getInputStream Returns the java.io.ByteArrayInputStream<br />

object for the client input stream.<br />

getServerVariable Given the name of an environment variable,<br />

returns its value. (The name is not case<br />

sensitive.)<br />

Given an index, returns the value of the<br />

corresponding environment variable, in the<br />

form name=value.<br />

If the name cannot be found, or if the index<br />

into the collection of environment variables is<br />

out of range, the method returns an empty<br />

string.<br />

getServerVariableCount Returns the total number of environment<br />

variables given by the Web server to the<br />

Application Server.<br />

getURLAttachment Returns the name of the temporary file<br />

associated with the file upload form field.<br />

getURLAttachmentCount Returns the number of attachments transferred.<br />

getURLAttachmentExists Returns true if the named attachment exists,<br />

and false otherwise.<br />

getURLAttachmentType Returns the content type of the attachment<br />

associated with the file upload form field.<br />

124


Method Description<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

getURLField Given a field name, returns the value of a field<br />

variable. (The name is case insensitive.)<br />

Given an index (one-based) into a set of fields,<br />

returns the corresponding name/value pair.<br />

If a field cannot be found, the method returns<br />

an empty string. Since there are times when an<br />

empty string may be a valid field value, this<br />

method is not useful for checking for the<br />

existence of a particular field. To check for a<br />

field’s existence, use the getURLFieldExists<br />

or getURLFieldCount method.<br />

getURLFieldCount Returns the number of name/value pairs in the<br />

form or on the URL.This value refers to the<br />

fields the browser sends with the request, not to<br />

the total number of fields in a form as it was<br />

created.<br />

Given a field name, returns the number of<br />

values sent for that field.<br />

Note that:<br />

If a field has multiple values, each value the<br />

browser sends counts as a separate field.<br />

Only the fields the browser sends are counted.<br />

If a list box has 12 possible choices, and the<br />

user selects 3, then the count is incremented<br />

by 3, not 12.<br />

getURLFieldExists Given a field name, returns true if the<br />

specified field exists, and false otherwise.<br />

Given a name and index n (one-based), returns<br />

true if the nth occurrence of the field exists,<br />

and false otherwise.<br />

getUserProp Returns the value of a user-defined property.<br />

isPost Returns true if this URL is a POST operation,<br />

and false if it is a GET.<br />

setURLField Overrides the value of a URL field that was<br />

passed to this page. If the field doesn’t exist,<br />

this method has no effect.<br />

setUserProp Sets a user-defined property to a given value.<br />

125


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

The Response object<br />

The Response object lets the Web server send data back to the browser. It<br />

includes methods for these purposes:<br />

Topic Refer to<br />

Writing header data “Writing headers” on page 126<br />

Setting the values of one or more<br />

cookies<br />

Writing headers<br />

Headers are part of the HTTP protocol and include information describing the<br />

data being sent, such as the Web server name and version, the content type<br />

and length, the date the document was last modified, language and character<br />

set information, and redirector information. Each header line ends with a<br />

header mark, consisting of the “” characters. A blank line signifies<br />

the end of the header section.<br />

Some actions — for example, setting a cookie — must take place while the Web<br />

server is still emitting the HTTP headers, before it starts to send HTML code.<br />

How, then, do you add header lines to an existing page? If you’re adding inline<br />

code to an HTML page, the <strong>IDE</strong> distinguishes between code that generates<br />

HTTP headers and code that generates HTML. If you call a method such as<br />

addHeaderLine or setCookie, that output is stored in a separate buffer and is<br />

sent as part of the HTTP headers. This feature lets you add in-line code to a<br />

page without worrying about the mechanics of writing headers versus writing<br />

HTML.<br />

Terminating headers<br />

If you’re writing a separate code page instead of in-line code, then you’re<br />

responsible for writing the headers and calling endHeaders appropriately.<br />

If you call one dynamic page from another — as a direct call, not a link — then<br />

you must first call endHeaders, so that the HTTP headers will not be displayed<br />

on the page.<br />

To terminate headers, add this line to your in-line code:<br />

126<br />

“Setting cookies” on page 127<br />

Writing out the HTML “Writing the HTML output” on page<br />

129


Java<br />

aResponse.endHeaders();<br />

HAHTtalk Basic<br />

aResponse.endHeaders<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Anything below that line is automatically emitted as part of the HTML output<br />

stream. If you don’t explicitly call endHeaders, it is assumed to have been<br />

called at the end of the page.<br />

Writing custom headers<br />

Normally, the <strong>HAHTsite</strong> <strong>IDE</strong> writes a standard Response header. However, you<br />

can send a custom header by calling the addHeaderLine method. If you are not<br />

currently “in headers,” the write operation is suppressed.<br />

Adding content information to a header line<br />

Once a header line has been written, it can’t be changed. The one exception is<br />

the content-type header line, containing the MIME type of the data being<br />

sent, such as "text/html" or "image/gif." Within the <strong>IDE</strong>, the default<br />

content-type is “text/html.” To change it, call the setContentType method.<br />

For more information about HTTP headers, consult a reference such as W3C<br />

(http://www.w3.org).<br />

Setting cookies<br />

Setting a cookie sends it to the client browser, to be stored (with the user’s<br />

permission) on the user’s system for later retrieval. (See “Retrieving cookie<br />

values” on page 121.) Cookies must be set in the HTTP headers (see “Writing<br />

headers” on page 126).<br />

To set a cookie, you specify its name and value. You may also want to set<br />

additional attributes, such as the cookie’s expiration date or a valid domain<br />

and path for returning the cookie. Or you may want to stipulate that the<br />

cookie should be sent only over a secure connection.<br />

setCookie(cookie, value) sets the cookie using default attributes (see<br />

the table, below, for defaults).<br />

setCookie(cookie, domain, expires, path, secure, value) sets the<br />

additional attributes described in the table.<br />

127


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Parameter Description<br />

cookie The name of the cookie, which should be unique for the given<br />

path. (Within different directories or subdirectories, there may be<br />

cookies with the same name.)<br />

domain Specifies an Internet domain name, such as haht.com. The<br />

cookie is sent only in response to requests to the named domain.<br />

Note that domain will match any hosts within that domain; for<br />

example, haht.com would also match a hostname of<br />

products.haht.com. If domain is null, it defaults to the<br />

hostname of the Web server that set the cookie in the first place.<br />

expires Specifies the date on which the cookie expires, in standard GMT<br />

format (for example, “Mon, 29-Jun-98 18:03:00 GMT”). If<br />

expires is null, or if the date isn’t later than the current date,<br />

the cookie automatically expires when the session ends.<br />

path Specifies a path within a specified domain. The cookie is sent<br />

only in response to requests to this path or any directories<br />

contained within it. A path of /docs would also match<br />

/docs/techsupport and /docs/marketing. If path is null,<br />

then it defaults to the application path.<br />

secure This argument is a boolean; if true, the cookie is secure,<br />

meaning that the browser should send the cookie only if it has a<br />

secure (HTTPS) connection to the Web server. (The default is<br />

false.)<br />

value A string containing the cookie’s value.<br />

Multiple values within a single cookie<br />

It’s possible to set a cookie that contains multiple pieces of data. This is<br />

sometimes called a cookie collection. To set these values, call setCookie, passing<br />

it the cookie name and a single string that contains all the cookie data,<br />

separated by a delimiter that’s not used elsewhere in the cookie. Here’s an<br />

example that uses the ampersand as a delimiter:<br />

Java<br />

aResponse.setCookie("dimensions", "height=10&width=5");<br />

HAHTtalk Basic<br />

aResponse.setCookie "dimensions", "height=10&width=5"<br />

128


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

To retrieve these values, see “Retrieving cookie collections” on page 121. For<br />

more information about setting cookies, consult the documentation for your<br />

Web server.<br />

Writing the HTML output<br />

Typically, you write HTML output using print or println methods (in Java)<br />

or the Print statement (in HAHTtalk Basic). You must add the necessary HTML<br />

paragraph formatting tags such as “” or “...”.<br />

Java<br />

In a Java project, each Page automatically gets the default HTMLWriter,<br />

using this code:<br />

HtmlWriter out;<br />

out = aResponse.getWriter();<br />

If you add in-line code to your page, you can use print or println<br />

statements like this:<br />

out.print(aRequest.getURLfield("Name") + "");<br />

HAHTtalk Basic<br />

In a HAHTtalk Basic project, you can simply call the print statement, like<br />

this:<br />

Print aRequest.getURLField("txtLastName") & ""<br />

The output from write operations is always buffered. At the end of the page,<br />

the buffer is flushed. If you’re generating a long page, you can call the<br />

Response object’s flush method to flush the output and begin buffering the<br />

data again.<br />

Additional write methods<br />

There are two additional write methods you may want to use:<br />

writeBinary writes binary data, such as GIF data. You must set the page’s<br />

content-type to image/gif (or jpeg or png).<br />

setWriter lets you use a subclassed HtmlWriter — for example, one that<br />

always writes its output to a file.<br />

129


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

Summary of Response object methods<br />

Method Description<br />

addHeaderLine Outputs a full header line. The Application Server<br />

automatically adds the header mark, signifying<br />

end-of-line.<br />

clear Empties the Response object’s output stream.<br />

end Flushes the output stream and closes the Response<br />

writer.<br />

endHeaders Terminates the header section of the response with a<br />

CR/LF sequence.<br />

flush Flushes the output stream and begins buffering data<br />

again.<br />

getContentType Returns a string containing the content-type header<br />

line.<br />

getOutputStream Returns the current output stream.<br />

getWriter Returns the current HTML writer.<br />

HTMLEncode Processes a string according to the HTML 3.2<br />

specification for special characters, so that they will<br />

display correctly on an HTML page.<br />

inHeaders Returns true if headers are still being output, and<br />

false if endHeaders has been called.<br />

reset Empties the output stream.<br />

setContentType Sets the content-type header line to the specified type.<br />

You can call setContentType multiple times if<br />

necessary. When endHeaders is called, the<br />

Application Server emits the content-type header line<br />

using the last value you set. This functionality can be<br />

useful if you need to change the content type on the<br />

fly.<br />

setCookie Sets a cookie.<br />

setOutputStream Sets the current output stream.<br />

130


Method Description<br />

Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

setWriter Sets the HtmlWriter for the Response object. This<br />

method lets you use a subclassed HtmlWriter —<br />

for example, one that always writes its output to<br />

a file.<br />

URLEncode Processes a string according to the RFC 2068 and RFC<br />

1808 specifications for special characters, so that the<br />

string can be sent in HTTP headers.<br />

write Writes a string to the output stream of this Response<br />

object.<br />

writeBinary Writes binary data, such as GIF data.<br />

131


Chapter 5: <strong>HAHTsite</strong> Server Object Model<br />

132


Forms-Related<br />

<strong>Programming</strong><br />

6<br />

What’s in this chapter ..................................................................................134<br />

Calling a subroutine from a form ................................................................134<br />

Writing the subroutine ............................................................................138<br />

Associating the subroutine with a form .................................................139<br />

Attaching a file to a form.............................................................................140<br />

Adding a File Upload control to a page..................................................141<br />

Working with a file attachment..............................................................142<br />

Custom Form Handler widgets ....................................................................145<br />

Writing the form-handler function.........................................................145<br />

Creating the custom form-handler widget .............................................152<br />

133


Chapter 6: Forms-Related <strong>Programming</strong><br />

What’s in this chapter<br />

In most cases, you handle the submission of a form using a data agent or a<br />

page that includes code that parses a URL to get the values submitted in the<br />

form. However, <strong>HAHTsite</strong> provides additional form-handling capabilities. For<br />

instance, you can have your application call a HAHTtalk Basic subroutine or a<br />

Java method when a form is submitted. One of the examples in this chapter<br />

illustrates how you might use such a subroutine to write a Binary Large Object<br />

named in a form to a database.<br />

Using the File Upload form field, a user can submit a file along with a form.<br />

When the form is submitted, the file is moved to the Application Server. The<br />

chapter discusses both how to add a File Upload field to a page and how to<br />

manage uploaded files.<br />

Finally, the chapter explains how to create a custom Form Handler widget in<br />

a HAHTtalk Basic project. You may use a custom Form Handler widget if your<br />

application requires a form handler that does something other than save form<br />

data to a file or a Web page or include that data in an email message.<br />

Calling a subroutine from a form<br />

When you define the properties of a form, you can specify an action that<br />

should occur when the form is submitted. Often, this action is to loop back to<br />

the form page or to load a dynamic page. However, you can also request that<br />

your application call a Java method or a HAHTtalk Basic subroutine when the<br />

form is submitted.<br />

Why would you want to call a method or subroutine? Usually, you use this<br />

feature to perform some task that can’t be accomplished with a standard<br />

command handler, like the command handler for a Move Next or Insert<br />

button. For instance, the example discussed in this section illustrates how you<br />

could use a form action of Subroutine to write a Binary Large Object (BLOB) to<br />

a database. In this example, the user must enter in a form a name to associate<br />

with a picture and the path to an image.<br />

134


The subroutine will then take the following steps:<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

1 Open a connection to the database, instantiate a Recordset, and set the<br />

active connection for the recordset.<br />

2 Get the filename of the image, and open the file for reading.<br />

3 Add a new record to the recordset, and get a handle to the picture field.<br />

4 Read chunks of data from the image file and write them to the database<br />

field.<br />

5 Update the recordset.<br />

6 Close the file input stream and the recordset.<br />

The listing below shows an abbreviated version of the subroutine as it might<br />

appear in a Java project. For a complete listing for the subroutine — in both<br />

Java and HAHTtalk Basic — see “Calling a subroutine as a form action” on page<br />

362.<br />

135


Chapter 6: Forms-Related <strong>Programming</strong><br />

Java<br />

package FileUploadJava;<br />

import com.haht.*;<br />

import com.haht.project.*;<br />

import com.haht.ado.Abstract.*;<br />

import java.io.*;<br />

class WritePictureToAccess extends Object<br />

implements HAHTPage<br />

{<br />

static final int BUFSIZE = 1024;<br />

136<br />

public void run (Request aRequest, Response aResponse)<br />

{<br />

Connection myConn;<br />

try<br />

{<br />

myConn = Haht.getSession().getConnectionManager().<br />

getSharedConnectionByName("NameAndPict");<br />

}<br />

catch (com.haht.HahtException e)<br />

{<br />

return;<br />

}<br />

Recordset myRS = new com.haht.ado.Recordset();<br />

myRS.setActiveConnection (myConn);<br />

myRS.setCursorType<br />

(com.haht.ado.CursorTypeEnum.adOpenKeyset);<br />

myRS.setLockType<br />

(com.haht.ado.LockTypeEnum.adLockOptimistic);<br />

try<br />

{<br />

myRS.open("NameAndPict");<br />

}<br />

catch (java.lang.Exception e)<br />

{<br />

}


Java<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

java.io.File pictureFile = new java.io.File<br />

(Haht.getApplication().getUserRoot() +<br />

'/' + aRequest.getURLAttachment("uplPicture"));<br />

FileInputStream pictureStream;<br />

Field pictureFld;<br />

try<br />

{<br />

pictureStream = new FileInputStream<br />

(pictureFile);<br />

}<br />

catch (java.io.FileNotFoundException e)<br />

{<br />

return;<br />

}<br />

myRS.addNew ();<br />

myRS.getField("Name").setString<br />

(aRequest.getURLField("txtName"));<br />

pictureFld = myRS.getField("Picture");<br />

byte [] pictureBuf = new byte[BUFSIZE];<br />

int nBytesRead = 0;<br />

do<br />

{<br />

try<br />

{<br />

nBytesRead = pictureStream.read(pictureBuf);<br />

if (nBytesRead > 0)<br />

{<br />

pictureFld.appendChunk<br />

(pictureBuf, nBytesRead);<br />

}<br />

}<br />

catch (java.io.IOException e)<br />

{<br />

}<br />

}<br />

while (nBytesRead > 0);<br />

137


Chapter 6: Forms-Related <strong>Programming</strong><br />

Java<br />

}<br />

Writing the subroutine<br />

Obviously, the content of your subroutine will be determined primarily by<br />

what you want the subroutine to do. However, there are a few guidelines that<br />

you should follow.<br />

In a Java project, your class must implement the HAHTPage interface. This<br />

interface requires that you implement one method, run, whose signature is<br />

shown below.<br />

void run (Request aRequest, Response aResponse)<br />

If you implement this method, when <strong>HAHTsite</strong> calls your class’s run method,<br />

it will pass to the subroutine a Request object that contains the URL used to<br />

execute the subroutine. You can parse this URL to obtain information such as<br />

the picture name entered on the form that was submitted:<br />

aRequest.getURLField("txtName");<br />

<strong>HAHTsite</strong> also passes to the run method a Response object, which you can use<br />

to send HTML to the user’s browser. In addition, you have the option of<br />

passing both the Request and Resposne objects to a dynamic page when your<br />

method has completed its part of the job.<br />

In a HAHTtalk Basic project, there are no similar requirements for a Basic<br />

subroutine. However, you may need to get references to your session’s Request<br />

and Response objects — for the same reasons you need them in a Java method.<br />

You can get these references using the following code:<br />

138<br />

}<br />

myRS.update();<br />

try<br />

{<br />

pictureStream.close();<br />

}<br />

catch (java.io.IOException e)<br />

{<br />

}<br />

myRS.close();<br />

com.haht.io.HtmlWriter out = aResponse.getWriter();<br />

out.print("Image written to database");


HAHTtalk Basic<br />

Dim aResponse As Object<br />

Dim aRequest As Object<br />

Set aResponse = Haht.getResponse()<br />

Set aRequest = Haht.getRequest()<br />

Associating the subroutine with a form<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

Once you’ve written your subroutine, you can associate it with a form so that<br />

when the form is submitted, the subroutine will be executed. To create this<br />

association, perform the following steps.<br />

To specify that a subroutine should be called when a form is submitted<br />

1 Right-click the form to bring up a pop-up menu that displays the<br />

operations you can perform in this context.<br />

2 Select Form... from the pop-up menu.<br />

The Form Properties dialog appears.<br />

3 From the Type list box, select Subroutine.<br />

4 In the Path text box, enter the name of the method or subroutine.<br />

In a Java project, you may have to fully qualify this method name:<br />

If the method is implemented outside the page that contains the form<br />

— that is, defined in a Java source file — this name must have the<br />

form packageName.className.methodName. For example,<br />

FileUploadJava.WritePictureToAccess.run would be a valid name,<br />

139


Chapter 6: Forms-Related <strong>Programming</strong><br />

140<br />

assuming that the WritePictureToAccess class is part of the project<br />

FileUploadJava. (Remember that for Java projects, the project name is<br />

the default package name.)<br />

If the method is implemented on the page that contains the form —<br />

in the Server-side Code view — you need only supply the method<br />

name.<br />

In a HAHTtalk Basic project, you simply enter the name of the subroutine.<br />

5 Click OK.<br />

Your form will now cause a subroutine to be called when the form is<br />

submitted.<br />

Attaching a file to a form<br />

<strong>HAHTsite</strong>’s File Upload form field enables a user to attach a file to a form and<br />

to send the file to the Application Server’s initial working directory when the<br />

user submits the form. The File Upload form field places a text box and a<br />

Browse button onto a form. In his or her browser, the user can either type the<br />

name or pathname of a file into the text box or use the Browse button to find<br />

the file on his or her local machine or LAN.<br />

Note - Not all browsers support this file-upload feature.<br />

Netscape Navigator 2.0 and later does support the feature;<br />

Internet Explorer 3.0 and earlier does not.<br />

When the user submits a form that contains a File Upload field, the<br />

name/value pairs for the form’s fields are sent to the Web server. The Web<br />

server then passes this information to the Application Server, which moves a<br />

copy of the file to its initial working directory. By default, the initial working<br />

directory is <strong>HAHTsite</strong>InstallDir\userroot\projectName — for example,<br />

C:\<strong>HAHTsite</strong>4.0\userroot\FileUploadJava.<br />

When the file is moved to the initial working directory, it is given a unique<br />

name created by prepending the user’s state ID (a unique string) to the file’s<br />

name. You can obtain the unique filename by using a Request object’s<br />

getURLAttachment method. This and other methods related to handling file<br />

attachments are discussed in “Working with a file attachment” on page 142.


Adding a File Upload control to a page<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

You add a file-upload form field to a form using the <strong>IDE</strong>. The procedure for<br />

adding this field is explained below.<br />

To add a File Upload field to a form<br />

1 Position your cursor on the page at the point at which you want to place<br />

the File Upload form field.<br />

If your cursor is inside a form, the File Upload field will be added to that<br />

form; otherwise, the <strong>IDE</strong> will automatically create a form into which to<br />

place the new field.<br />

2 From the Insert menu, select Form Field > File Upload, or click the File<br />

Upload button .<br />

The File Upload form field is written to your form.<br />

3 Right-click the new field to display a pop-up menu of actions you can take<br />

in this context.<br />

4 Select Form Field... from the pop-up menu.<br />

The Form Field Properties dialog appears.<br />

5 Edit the properties shown on the General tab (optional).<br />

The table below explains what information you can enter on this tab.<br />

Field Explanation<br />

Name The name of the File Upload field. This is the name you<br />

use to refer to the Java object that represents the field.<br />

141


Chapter 6: Forms-Related <strong>Programming</strong><br />

6 Click OK.<br />

This is all you have to do to enable the user to submit a file with a form and<br />

have that file copied to the Application Server’s initial working directory. If<br />

you want to process the file, you must use the Server Object Model methods<br />

discussed in “Working with a file attachment” below.<br />

Working with a file attachment<br />

When a file is submitted with a form and you want to handle the file<br />

programatically, you can place the code that will process the file in one of two<br />

places:<br />

142<br />

Field Explanation<br />

Value The value of the file-upload field when the form is<br />

submitted. Normally, this will be a pathname that the<br />

user types in or selects using the Browse button.<br />

However, you can provide the field a default value by<br />

setting this form-field property.<br />

Label A label that you want to appear to the left or right of the<br />

File Upload field when the page is browsed.<br />

Label Alignment If you specified a label for the field, choosing the Left<br />

radio button causes the label to appear to the left of the<br />

field when the page is browsed, and the Right radio<br />

button causes the label to be displayed on the right.<br />

In a subroutine to be called when the form containing the file-upload<br />

field is submitted. For information on calling a subroutine from a form,<br />

see “Calling a subroutine from a form” on page 134.<br />

In “user code” that is called when a particular form button is clicked,<br />

causing the form to be submitted. For information on calling “user code”<br />

from a form button, see “Calling user code from a button” on page 183.<br />

The example used in “Calling a subroutine from a form” on page 134 is a good<br />

illustration of manipulating a file using a subroutine called when a form is<br />

submitted. This section refers to that example in explaining how to work with<br />

a file submitted with a form.<br />

If you recall, the subroutine discussed in that section takes an image file<br />

submitted with a form and writes it to a database. In the course of moving the<br />

contents of the file to the database, the subroutine performs two actions that<br />

you’ll always want to perform when working with a file submitted with a<br />

form:


Chapter 6: Forms-Related <strong>Programming</strong><br />

1 Check the URL used to call the subroutine to see if the URL contains a<br />

field that holds the name of a file attachment. If this field does not exist,<br />

the user didn’t supply a filename or some error occurred, and you should<br />

call an error-message page.<br />

You can determine whether the URL contains such a field using the<br />

Request object’s getURLAttachmentExists method as shown below.<br />

Java<br />

// Check to see if the user has submitted a picture name and a<br />

// filename.<br />

if (aRequest.getURLFieldExists("txtName")<br />

&& aRequest.getURLAttachmentExists("uplPicture"))<br />

{<br />

// Bulk of the subroutine goes here.<br />

...<br />

}<br />

else<br />

{<br />

// Instantiate an error page and call its run routine.<br />

...<br />

}<br />

HAHTtalk Basic<br />

' Check to see if the user has submitted a picture name and a<br />

' filename.<br />

'<br />

If (aRequest.getURLFieldExists("txtName") And _<br />

aRequest.getURLAttachmentExists("uplPicture")) Then<br />

' Bulk of the subroutine goes here.<br />

...<br />

Else<br />

' Instantiate an error page and call its run routine.<br />

...<br />

End If<br />

2 Get the name of the file that was transferred to the Application Server. The<br />

file won’t have the same name it had when the user entered its name in<br />

your form. <strong>HAHTsite</strong> prepends the user’s state ID to the original filename<br />

143


Chapter 6: Forms-Related <strong>Programming</strong><br />

144<br />

so that it turns out looking something like this:<br />

T7UqieNDj0YplcN40CEVbC0_Kohahtsite.jpg.<br />

You obtain this filename using the Request object’s getURLAttachment<br />

method as shown below. In this example, uplPicture is the name of the<br />

form’s File Upload form field.<br />

Java<br />

java.io.File pictureFile = new java.io.File<br />

(Haht.getApplication().getUserRoot() +<br />

'/' + aRequest.getURLAttachment("uplPicture"));<br />

HAHTtalk Basic<br />

Dim sPictureFileName as String<br />

sPictureFileName = HahtApplication.getUserRoot() & "/" _<br />

& aRequest.getURLAttachment("uplPicture")<br />

The Request object also provides methods that enable you to determine the<br />

content type of an attachment and to determine how many file-attachment<br />

fields are in a URL (if there is more than one). The table below summarizes the<br />

Request methods related to handling file attachments.<br />

Method Explanation<br />

getURLAttachmentCount indicates how many files were submitted with<br />

the form<br />

getURLAttachmentExists indicates whether the URL contains a<br />

file-attachment field for a particular file-upload<br />

field<br />

getURLAttachment gets the name of the file that was attached to<br />

the form using a particular file-upload field<br />

getURLAttachmentType gets the content type of an attached file. This<br />

content type might be something like<br />

image/jpeg or audio/basic.


Custom Form Handler widgets<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

HAHTtalk Basic projects include a Form Handler widget that enables you to<br />

add to a form a button whose action is to write the values of a form’s fields to:<br />

a file<br />

an HTML page<br />

an email message<br />

HAHTtalk Basic projects also give you the ability to create custom<br />

form-handler widgets by writing the Basic function that will be executed when<br />

the form button representing the widget is clicked. Because this function is<br />

passed information about the Web application, information about the<br />

environment in which the application is running, and the contents of the<br />

form’s fields, custom form handlers usually make use of this information. “An<br />

example form-handler function” on page 149 illustrates how to write a<br />

function that uses this information in a simple way.<br />

Note - The custom form-handler widget is a useful feature, but<br />

it has been retained primarily for compatibility with <strong>HAHTsite</strong><br />

3.x. This feature has not been ported to Java projects because<br />

you can create the equivalent of a custom form-handler widget<br />

in Java projects by writing a method that is called when a form<br />

is submitted or when a particular form button is clicked. This<br />

method can obtain information about the values of form fields<br />

and the values of Web-server environment variables using the<br />

getServerVariable method of the Request class. <strong>HAHTsite</strong><br />

Basic programmers can also use this technique.<br />

The remainder of this chapter is for programmers who want to create new<br />

custom form-handler widgets. It explains how to:<br />

write a form-handler function in HAHTtalk Basic<br />

how to create a form-handler widget based on the Basic function you<br />

created earlier<br />

Writing the form-handler function<br />

The HAHTtalk Basic code around which you build a custom form-handler<br />

widget must be a function, not a subroutine. In addition, the name of your<br />

function must be the same as the name of the code file that contains it.<br />

Included in the <strong>HAHTsite</strong>InstallDir\scripts directory is a sample<br />

form-handler function FormHand, which is contained in the file FormHand.hbs.<br />

You can use this function as a template for your own form handler.<br />

145


Chapter 6: Forms-Related <strong>Programming</strong><br />

Notice that the sample form-handler function requires two parameters, one of<br />

type Environment and one of type FormArray. The Environment data structure<br />

contains the values of a number of Web-server environment variables and<br />

Web-application properties. The FormArray data structure contains the names<br />

and values of your form’s form fields. For definitions of these structures, see<br />

“Parameters of the form-handler function” on page 146.<br />

Parameters of the form-handler function<br />

The first parameter required by a form-handler function is a parameter of type<br />

Environment. The definition of this data type is shown below.<br />

146


HAHTtalk Basic<br />

Type Environment<br />

ComputerName as string<br />

ComSpec as string<br />

GATEWAY_INTERFACE as string<br />

HTTP_ACCEPT as string<br />

HTTP_CONNECTION as string<br />

HTTP_HOST as string<br />

HTTP_REFERER as string<br />

HTTP_USER_AGENT as string<br />

OS as string<br />

Os2LibPath as string<br />

Path as string<br />

PATH_INFO as string<br />

PROCESSOR_ARCHITECTURE as string<br />

PROCESSOR_<strong>IDE</strong>NTIFIER as string<br />

PROCESSOR_LEVEL as string<br />

PROCESSOR_REVISION as string<br />

QUERY_STRING as string<br />

REMOTE_ADDR as string<br />

REMOTE_HOST as string<br />

REQUEST_METHOD as string<br />

SCRIPT_NAME as string<br />

SERVER_NAME as string<br />

SERVER_PORT as string<br />

SERVER_PROTOCOL as string<br />

SERVER_SOFTWARE as string<br />

SERVER_URL as string<br />

SystemRoot as string<br />

SystemDrive as string<br />

windir as string<br />

NewApp as boolean<br />

DirName as string<br />

HTXName as string<br />

PathName as string<br />

PageName as string<br />

ServerName as string<br />

StateId as string<br />

Timeout as long<br />

End Type<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

147


Chapter 6: Forms-Related <strong>Programming</strong><br />

The table below shows how the members of this structure map to WebApp<br />

properties and environment variables retrievable via the WebApp method<br />

Environ$. (For documentation of the WebApp object, see the <strong>HAHTsite</strong> 3.x<br />

programmer’s guide. For information about how WebApp properties and<br />

methods map to elements in the Server Object Model, see Appendix A,<br />

“<strong>HAHTsite</strong> 3.x WebApp Methods and Properties.”)<br />

Structure Member Definition<br />

ComputerName Webapp.Environ$("COMPUTERNAME")<br />

ComSpec Webapp.Environ$("ComSpec")<br />

GATEWAY_INTERFACE Webapp.Environ$("GATEWAY_INTERFACE")<br />

HTTP_ACCEPT Webapp.Environ$("HTTP_ACCEPT")<br />

HTTP_CONNECTION Webapp.Environ$("HTTP_CONNECTION")<br />

HTTP_HOST Webapp.Environ$("HTTP_HOST")<br />

HTTP_REFERER Webapp.Environ$("HTTP_REFERER")<br />

HTTP_USER_AGENT Webapp.Environ$("HTTP_USER_AGENT")<br />

OS Webapp.Environ$("OS")<br />

Os2LibPath Webapp.Environ$("Os2LibPath")<br />

Path Webapp.Environ$("Path")<br />

PATH_INFO Webapp.Environ$("PATH_INFO")<br />

PROCESSOR_ARCHITECTURE Webapp.Environ$("PROCESSOR_ARCHITECTURE")<br />

PROCESSOR_<strong>IDE</strong>NTIFIER Webapp.Environ$("PROCESSOR_<strong>IDE</strong>NTIFIER")<br />

PROCESSOR_LEVEL Webapp.Environ$("PROCESSOR_LEVEL")<br />

PROCESSOR_REVISION Webapp.Environ$("PROCESSOR_REVISION")<br />

QUERY_STRING Webapp.Environ$("QUERY_STRING")<br />

REMOTE_ADDR Webapp.Environ$("REMOTE_ADDR")<br />

REMOTE_HOST Webapp.Environ$("REMOTE_HOST")<br />

REQUEST_METHOD Webapp.Environ$("REQUEST_METHOD")<br />

SCRIPT_NAME Webapp.Environ$("SCRIPT_NAME")<br />

SERVER_NAME Webapp.Environ$("SERVER_NAME")<br />

148


Structure Member Definition<br />

The definition of the FormArray structure is shown below:<br />

Type FormArray<br />

FieldName as string<br />

Value as string<br />

End Type<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

SERVER_PORT Webapp.Environ$("SERVER_PORT")<br />

SERVER_PORT Webapp.Environ$("SERVER_PORT")<br />

SERVER_SOFTWARE Webapp.Environ$("SERVER_SOFTWARE")<br />

SERVER_URL Webapp.Environ$("SERVER_URL")<br />

SystemRoot Webapp.Environ$("SystemRoot")<br />

SystemDrive Webapp.Environ$("SystemDrive")<br />

windir Webapp.Environ$("windir")<br />

NewApp Webapp.NewApp<br />

DirName Webapp.DirName<br />

HTXName Webapp.HTXName<br />

PathName Webapp.PathName<br />

ServerName Webapp.ServerName<br />

StateId Webapp.StateId<br />

Timeout Webapp.Timeout<br />

You must place the definitions of both the Environment type and the<br />

FormArray type above your function definition in your code file. For an<br />

example function definition, see “An example form-handler function.”<br />

An example form-handler function<br />

Assume that your application contains a form that requires a user to submit an<br />

email address, a user name, and a password.<br />

149


Chapter 6: Forms-Related <strong>Programming</strong><br />

When the user submits this form, the custom form handler:<br />

150<br />

Writes a file, Users.txt, to the Application Server’s userroot directory.<br />

This file contains the data submitted with the form in a comma-separated<br />

format.<br />

Sends an email message to the user who submits the form. (Note that the<br />

code that writes this email message uses a member of the Environment<br />

structure.)<br />

After the custom form handler performs these actions, the application displays<br />

a response page that thanks the user for registering and shows the time of<br />

registration.<br />

The HAHTtalk Basic function for the custom form handler is shown below:


HAHTtalk Basic<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

' Definitions of Environment and FormArray Types go here.<br />

Public Function Sample(myEnv As Environment, myFields() As _<br />

FormArray) As Integer<br />

On Error Goto Sample_Error<br />

Dim i As Integer<br />

Dim m As New Message<br />

Dim user As String<br />

Dim email As String<br />

Dim password As String<br />

For i = LBound(myFields) To UBound(myFields)<br />

If myFields(i).FieldName = "Username" Then<br />

user = myFields(i).Value<br />

ElseIf myFields(i).FieldName = "Password" Then<br />

password = myFields(i).Value<br />

ElseIf myFields(i).FieldName = "Address" Then<br />

email = myFields(i).Value<br />

End If<br />

Next i<br />

' Write information to user's file in UserRoot<br />

Open "Users.txt" For Append As #1<br />

Print #1, user & "," & password & "," & email<br />

Close #1<br />

' Mail Confirmation<br />

m.To.New email<br />

m.From = "info@haht.com"<br />

m.Subject = "Registration Confirmation"<br />

m.SmtpServer = "mailhost"<br />

m.Body.Writeln "Registration Confirmation for " & email & _<br />

"received from remote host: " & myEnv.REMOTE_HOST<br />

m.Body.Writeln "Your username is: " & user<br />

m.Body.Writeln "Your password is: " & password<br />

m.Submit<br />

151


Chapter 6: Forms-Related <strong>Programming</strong><br />

HAHTtalk Basic<br />

Sample_Error:<br />

Sample = 0<br />

' Go To Response Page<br />

Call HS_Response()<br />

End Function<br />

Creating the custom form-handler widget<br />

Once you’ve written the HAHTtalk Basic function that performs the actions<br />

you want your custom form-handler widget to perform, you can create the<br />

widget by following the directions below.<br />

To create a custom widget<br />

1 Place your cursor in your form at the position where you want the widget<br />

(represented as a form button) to appear.<br />

2 Drag a Form Handler widget from the Widgets folder in your Project<br />

window to your page.<br />

152<br />

The Form Handler Properties dialog appears.<br />

3 Click the Custom button in the Form Handler Properties dialog box.<br />

The Custom dialog appears.


4 Fill out the Custom dialog box.<br />

The table below discusses each form field in the dialog.<br />

Form Field Explanation<br />

Chapter 6: Forms-Related <strong>Programming</strong><br />

Description Enter a short name for your custom<br />

form-handler widget. <strong>HAHTsite</strong> adds this name<br />

to the list of form handlers you can add to a<br />

page (within this project) using the Form<br />

Handler widget.<br />

Code Page Name Specify the name of the .hbs file that includes<br />

your HAHTtalk Basic function.<br />

Redisplay Page If you leave this box checked, the page that<br />

contains your custom form handler will be<br />

redisplayed after the form-handler function is<br />

executed. If your function calls a dynamic page<br />

— as the example function does — you should<br />

remove the check from this box.<br />

Default Button Label Supply a label for the form-handler button.<br />

153


Chapter 6: Forms-Related <strong>Programming</strong><br />

154


Form Fields<br />

<strong>Programming</strong><br />

7<br />

What’s in this chapter ..................................................................................156<br />

Setting form-field properties ........................................................................156<br />

Examples of setting form-field properties...............................................156<br />

Setting and getting form-field properties ...............................................161<br />

FormField properties................................................................................163<br />

Button properties.....................................................................................165<br />

Checkbox properties................................................................................167<br />

Combo properties ....................................................................................168<br />

FileUpload properties...............................................................................168<br />

ListElement and Listbox classes ..............................................................169<br />

Radiobutton properties............................................................................175<br />

StaticText properties ................................................................................176<br />

TextArea properties ..................................................................................178<br />

Textbox properties ...................................................................................178<br />

Calculating form-field values .......................................................................180<br />

Calling user code from a button..................................................................183<br />

Code associated with a button versus code associated with a form .....183<br />

Configuring a button to call user code ..................................................184<br />

155


Chapter 7: Form Fields <strong>Programming</strong><br />

What’s in this chapter<br />

This chapter discusses both how to write code that affects form fields and how<br />

to use a form field (a button) to call user-written code.<br />

As you’ll read below, all <strong>HAHTsite</strong> form fields (text boxes etc.) are Java objects,<br />

and these objects have methods that enable you to set their properties at<br />

runtime. While you usually set form-field properties when you design your<br />

form using the <strong>IDE</strong>, you may want to set some properties conditionally. For<br />

instance, you may want to make a Move First button invisible if your<br />

application is already displaying the first record in a recordset.<br />

Another type of form-field programming involves manipulating values<br />

retrieved from a data source before they are displayed in form fields. You can<br />

change these values by adding code to a page between the data agent that<br />

retrieves the values and the form that is populated by the data agent.<br />

Finally, the chapter discusses how you can call “user code” when a particular<br />

button (form field) is used to submit the form.<br />

Setting form-field properties<br />

Each form field in a form — whether it be a text box or a radio button — is a<br />

Java object and has a set of properties (member variables) that you can set. This<br />

section begins with a couple of examples that illustrate problems you can solve<br />

by setting these form-field properties programatically. The section then<br />

presents reference information about what properties you can set for each<br />

object and how to set and read the values of these properties.<br />

156<br />

To see the introductory examples, look at “Examples of setting form-field<br />

properties” on page 156.<br />

For reference information about form-field properties and how to set<br />

them, see “Setting and getting form-field properties” on page 161.<br />

Examples of setting form-field properties<br />

This section demonstrates how to solve two common problems by setting<br />

form-field properties. The first example assumes that your application uses a<br />

form to present the user with information from a database, and that the user<br />

can navigate from record to record using Move First, Move Next, Move<br />

Previous, and Move Last buttons. The example makes the Move Previous<br />

button invisible if the user tries to access a record before the first record and


Chapter 7: Form Fields <strong>Programming</strong><br />

makes the Move Next button invisible if the user tries to access a record<br />

beyond the last record.<br />

The second example illustrates a simple method of internationalizing the<br />

static text in a form.<br />

Example 1: Turning off visibility for a button<br />

Say that you have an application that enables users to work with the records<br />

in an employee-information database. Users can view, insert, update, or delete<br />

records. They can also navigate the database using Move First, Move Next,<br />

Move Previous, and Move Last buttons.<br />

Further, assume that you want the Move Previous button to be removed from<br />

the form when the user’s record pointer is pointing at BOF and the Move Next<br />

button to be removed when the user’s record pointer is pointing at EOF.<br />

157


Chapter 7: Form Fields <strong>Programming</strong><br />

The code required to implement this feature is very simple. Just place the<br />

following code somewhere between the data agent that is populating these<br />

fields and the form.<br />

Java<br />

btnMoveNext.setVisible(true);<br />

btnMovePrevious.setVisible(true);<br />

if (daPopulater.getRecordset().getEOF()) {<br />

btnMoveNext.setVisible(false);<br />

}<br />

if (daPopulater.getRecordset().getBOF()) {<br />

btnMovePrevious.setVisible(false);<br />

}<br />

HAHTtalk Basic<br />

btnMoveNext.setVisible True<br />

btnMovePrevious.setVisible True<br />

If (daPopulater.getRecordset().getEOF()) Then<br />

btnMoveNext.setVisible False<br />

End If<br />

If (daPopulater.getRecordset().getBOF()) Then<br />

btnMovePrevious.setVisible False<br />

End If<br />

158


Chapter 7: Form Fields <strong>Programming</strong><br />

The getBOF and getEOF methods check to see whether the current recordset of<br />

the page’s data agent (daPopulater) is pointing before the first record or after<br />

the last record. (For more information about <strong>HAHTsite</strong>’s interface to data<br />

agents and their recordsets, see Chapter 8, “Data-Agent <strong>Programming</strong>.”) If one<br />

of these conditions is true, the appropriate button’s setVisible method turns<br />

the visibility of the object off.<br />

Note - The first two statements in this block make both<br />

buttons visible. Without these statements, once a button’s<br />

visibility was turned off, it would never be turned on again.<br />

Example 2: Internationalizing a form<br />

Here’s another situation in which you might want to set the properties of form<br />

fields. Say that you’re working with the interface shown in “Example 1:<br />

Turning off visibility for a button” on page 157 and that you want to be able<br />

to display the labels next to the text boxes in either English or Spanish. (You<br />

can use the same technique to change the language of the text associated with<br />

any form field.)<br />

First, you might prompt the user for a language preference and store that<br />

preference in a session-scope variable, for instance, language. You’ll also need<br />

to make sure that the labels are Static Text objects, not just text. You can then<br />

call the code shown below:<br />

159


Chapter 7: Form Fields <strong>Programming</strong><br />

Java<br />

This code assumes that you have defined the variable language in the<br />

HahtSession class. This class is defined in the file HahtSession.java, which is<br />

located in your project’s Session folder.<br />

if (hahtSession.language == "Spanish") {<br />

staLastName.setValue("Apellido:");<br />

staFirstName.setValue("Nombre:");<br />

staStreetAddr.setValue("Direccion:");<br />

staCity.setValue("Ciudad:");<br />

staState.setValue("Estado:");<br />

staZipCode.setValue("Codigo Postal:");<br />

}<br />

HAHTtalk Basic<br />

This code assumes that you’ve defined the global variable language in the file<br />

globals.hbs.<br />

If (language = "Spanish") Then<br />

staLastName.setValue "Apellido:"<br />

staFirstName.setValue "Nombre:"<br />

staStreetAddr.setValue "Direccion:"<br />

staCity.setValue "Ciudad:"<br />

staState.setValue "Estado:"<br />

staZipCode.setValue "Codigo Postal:"<br />

End If<br />

This code uses the setValue method of the Static Text object to change each<br />

object’s Value member variable.<br />

160<br />

Note - To change a Static Text object’s label — as opposed to<br />

the text itself — you can use the setLabel method. (In the<br />

example above, the Static Text objects don’t have labels<br />

because the objects are being used as labels.) You can also use<br />

the setLabel method to change the label associated with other<br />

form fields, for example, text boxes and radio buttons. For<br />

most fields, the label you supply appears to the left or right of<br />

the field when the page is browsed.


Setting and getting form-field properties<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

This section contains primarily reference material that details what properties<br />

you can set for each form-field object and what methods you call to set these<br />

properties. However, there are a couple of things you should understand about<br />

<strong>HAHTsite</strong> form fields and their properties before you begin setting these<br />

properties.<br />

First, as was mentioned earlier, each form field is a Java object. Therefore, it’s<br />

important to understand the relationships between the Java classes from<br />

which these objects are created. These class relationships are shown in the<br />

figure below.<br />

FormField<br />

Buttons Checkbox FileUpload Listbox<br />

Radiobutton StaticText TextArea Textbox<br />

ListElement<br />

Combo<br />

As you can see, most of the classes that represent objects you can place on a<br />

page (like Button and Checkbox) are subclasses of FormField. This means that<br />

all the properties and property-accessor methods defined in the FormField<br />

class are inherited by the other classes shown. (For the purposes of this<br />

documentation, this hierarchy means that the reference information for an<br />

object of type Textbox is the union of the information presented for the<br />

FormField class and that presented for the Textbox class.) Combo is a subclass<br />

of Listbox as well, but this relationship doesn’t affect your use of these two<br />

classes because they expose the same interface.<br />

One other word of introduction. There are two methods of setting form-field<br />

properties in <strong>HAHTsite</strong>: you can either use a set method or set a member<br />

variable directly. The code below illustrates the use of a set method.<br />

161


Chapter 7: Form Fields <strong>Programming</strong><br />

Java<br />

staLastName.setValue("Apellido:");<br />

HAHTtalk Basic<br />

staLastName.setValue "Apellido:"<br />

The following code illustrates how you can set a member variable of an object<br />

directly:<br />

Java<br />

staLastName.Value = "Apellido:";<br />

HAHTtalk Basic<br />

staLastName.Value = "Apellido:"<br />

HAHT recommends that you use the set methods to set form-field properties,<br />

and, consequently, the upcoming sections document these methods as the<br />

interface to use in setting and reading form-field properties. Again, though,<br />

the member variables that represent these properties are public and can be set<br />

directly. For a list of the member variables you can set for a particular object,<br />

see the online help for the <strong>HAHTsite</strong> Server Object Model.<br />

The table below directs you to information about setting the properties of the<br />

object in which you’re interested.<br />

Section Description<br />

“FormField properties” on page<br />

163<br />

162<br />

explains how to set and read the properties<br />

that are common to all form fields.<br />

FormField is a superclass of all the other<br />

classes listed in this table; therefore, the<br />

methods listed here can be used with any<br />

form-field object.<br />

“Button properties” on page 165 explains how to set and read the properties of<br />

a button (a Submit button, a Reset button,<br />

etc.)


Section Description<br />

“Checkbox properties” on page<br />

167<br />

FormField properties<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

As was mentioned earlier, FormField is a superclass of the classes representing<br />

the following form-field objects:<br />

Button<br />

Check box<br />

Combo box<br />

File-upload control<br />

List box<br />

Radio button<br />

Static text<br />

Text area<br />

Text box<br />

explains how to set and read the properties of<br />

a check box<br />

“Combo properties” on page 168 explains how to set and read the properties of<br />

a combo box<br />

“FileUpload properties” on page<br />

168<br />

“ListElement and Listbox classes”<br />

on page 169<br />

“Radiobutton properties” on<br />

page 175<br />

“StaticText properties” on page<br />

176<br />

“TextArea properties” on page<br />

178<br />

“Textbox properties” on page<br />

178<br />

explains how to set and read the properties of<br />

a file-upload widget, which enables you to<br />

copy a file to the Application Server when<br />

you submit your form<br />

explains how to change the contents of a list<br />

box at runtime<br />

explains how to set and read the properties of<br />

a radio button<br />

explains how to set and read the properties of<br />

a static-text object<br />

explains how to set and read the properties of<br />

a text-area widget<br />

explains how to set and read the properties of<br />

a text box<br />

163


Chapter 7: Form Fields <strong>Programming</strong><br />

Because these objects are created from subclasses of the FormField class, you<br />

can use FormField methods to set properties that all of the objects have in<br />

common. For example, you can set the visibility of any object like this:<br />

Java<br />

This code changes the Visible attribute of a Button object from on to off. It<br />

assumes that the object btnMoveFirst has already been instantiated.<br />

btnMoveFirst.setVisible(false);<br />

HAHTtalk Basic<br />

This code changes the Visible attribute of a Button object from on to off. It<br />

assumes that the object btnMoveFirst has already been instantiated.<br />

btnMoveFirst.setVisible False<br />

The following table lists the most commonly used set and get methods for use<br />

with all the subclasses of FormField.<br />

Method Explanation<br />

addExtAttr enables you to add an extended attribute to a form-field<br />

object. This extended attribute is an HTML attribute not<br />

represented by one of the object’s standard properties<br />

(value, etc.). Note that case matters when you’re storing<br />

and retrieving these extended attributes<br />

setLabelAlignment determines whether a form field’s label is displayed on<br />

the left or right of the field when the page is browsed.<br />

See setLabel.<br />

setLabel establishes the value of a label to be displayed to the left<br />

or right of the form field when the page is browsed. All<br />

form-field objects except those of type Button can<br />

display labels.<br />

setName changes the name of the form field. You use this name<br />

to refer to the object that represents the form field.<br />

164


Method Explanation<br />

Button properties<br />

<strong>HAHTsite</strong> enables you to put four types of buttons on a page:<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

setValue establishes the value of the form field. This is the value<br />

that is submitted with the form. In some cases, the value<br />

is also displayed in the browser. For example, the value<br />

of a button is used as its label, and a text box’s value<br />

appears in the text box.<br />

setVisible determines whether a field is visible or not. That is, a<br />

page’s run method or HS_ subroutine does not generate<br />

HTML for an invisible form field.<br />

getExtAttrValue retrieves an extended attribute of an object by name.<br />

The name you use to retrieve the value of an attribute is<br />

case sensitive.<br />

getLabelAlignment indicates whether the object’s label is to be displayed on<br />

the left or right of the corresponding form field<br />

getLabel retrieves a form field’s current label<br />

getName retrieves a form field’s current name<br />

getValue retrieves a form field’s current value<br />

isVisible indicates whether a form field is currently marked as<br />

visible or not<br />

toString returns an HTML representation of the form field as a<br />

string<br />

Submit button - submits the values on a form to a form handler or<br />

performs some database-related action<br />

Reset button - returns the form fields’ values to what they were when the<br />

page was first displayed<br />

Button button - executes a client-side script<br />

Image button - similar to a Submit button except that its label is an<br />

image instead of text<br />

You can set a button’s properties programatically to accomplish such tasks as<br />

the following. Suppose that you want to set a session-scope variable to change<br />

the labels on all of your buttons from text labels to pictures. You could<br />

accomplish this task using code similar to the following:<br />

165


Chapter 7: Form Fields <strong>Programming</strong><br />

Java<br />

if (hahtSession.picturesOnButtons == true) {<br />

btnMoveFirst.setStyle<br />

(com.haht.project.form.Button.STYLE_IMAGE);<br />

btnMoveFirst.setPictureURL(Haht.getSession().createStaticURL<br />

("<strong>HAHTsite</strong>.gif","default"));<br />

}<br />

HAHTtalk Basic<br />

If (HahtSession.picturesOnButtons = True) Then<br />

Set Haht_TempJavaObj = GetJavaClass _<br />

("com.haht.project.form.Button")<br />

btnMoveFirst.setStyle Haht_TempJavaObj.STYLE_IMAGE<br />

btnMoveFirst.setPictureURL HahtSession.createStaticURL _<br />

("<strong>HAHTsite</strong>.gif", "default")<br />

Set Haht_TempJavaObj = Nothing<br />

End If<br />

You use the setStyle method to change a button from one type to another<br />

(from a Submit button to an Image button, for example) and the<br />

setPictureURL method to specify the location of the image to be displayed on<br />

the button.<br />

The table below lists the methods of the Button class that you can use to set<br />

and retrieve the properties of a Button object.<br />

Method Explanation<br />

setLowSrcURL specifies the URL of the image to be used as an Image<br />

button’s Low-Resolution Image<br />

setPictureURL specifies the URL of the image to be used as an Image<br />

button’s Source Picture<br />

setStyle sets a button’s type to one of the following values:<br />

Submit, Reset, Button, or Image<br />

getLowSrcURL gets the URL of the image being used as an Image<br />

button’s Low-Resolution Image<br />

getPictureURL gets the URL of the image being used as an Image<br />

button’s Source Picture<br />

166


Method Explanation<br />

getStyle gets the type of a button<br />

Checkbox properties<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

When you add a check box to a form using the <strong>IDE</strong>, you can specify:<br />

the value of the check box if the form it is on is submitted while the box<br />

is checked<br />

the value of the check box if the form it is on is submitted while the box<br />

is unchecked<br />

the initial state of the checkbox: checked or unchecked<br />

You can also set or read these properties — and others — at runtime using<br />

methods of the Checkbox class. For example, you might want to determine at<br />

runtime whether a check box, chkExample, should be checked or unchecked<br />

when it is first displayed. To do this, you would include code similar to the<br />

following above the form that contains the check box.<br />

Java<br />

if (...) {<br />

chkExample.setChecked(true);<br />

}<br />

HAHTtalk Basic<br />

If (...) Then<br />

chkExample.setChecked True<br />

End If<br />

The table below enumerates the methods used most often to work with check<br />

box properties.<br />

Method Explanation<br />

setChecked enables you to change the checked status of a<br />

check box — from unchecked to checked or<br />

from checked to unchecked<br />

167


Chapter 7: Form Fields <strong>Programming</strong><br />

Method Explanation<br />

setCheckedIfValueIs sets the checked status of a check box to<br />

checked if a string that you pass as an argument<br />

matches the current checked value of the check<br />

box<br />

setUnCheckedValue sets the value the check box has when the<br />

check box is unchecked<br />

getUnCheckedValue retrieves the check box’s unchecked value<br />

isChecked returns the value of the Checked member<br />

variable, which indicates whether the check box<br />

will be checked when the page it is on is<br />

displayed<br />

168<br />

Note - You set the checked value of a check box using the<br />

setValue method, which Checkbox inherits from FormField.<br />

Combo properties<br />

In the Server Object Model, Combo is a subclass of Listbox. However, while<br />

Combo overrides a few methods defined in the Listbox class, this is entirely<br />

transparent to you. The interface used to set and read combo box properties is<br />

exactly the same as the interface used to work with list boxes. See “ListElement<br />

and Listbox classes” on page 169 for a description of this interface.<br />

FileUpload properties<br />

The properties you can set for a file-upload field are all very general. You can<br />

set the field’s:<br />

Name<br />

Value<br />

Label<br />

Label alignment<br />

Visibility<br />

The methods you use to work with these properties are all inherited from<br />

FormField. Therefore, you can find reference information about these<br />

methods in “FormField properties” on page 163.


ListElement and Listbox classes<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

The ListElement and Listbox classes enable you (and <strong>HAHTsite</strong>) to create list<br />

boxes that contain particular sets of list entries, or elements. An object of the<br />

Listbox class represents the list box itself, and each entry in the list is an<br />

object of type ListElement.<br />

Note - List elements can also be added to combo boxes since<br />

Combo is a subclass of Listbox.<br />

There are three possible types of list elements:<br />

Design-time list elements. <strong>HAHTsite</strong> creates design-time list elements<br />

when you use the <strong>IDE</strong> to create a list box and add list items to the list.<br />

For each list item, <strong>HAHTsite</strong> instantiates a list element with a type<br />

property whose value is STATIC_ELEMENT.<br />

Populater list elements. If you design a page so that a data agent is used<br />

to populate a list box or combo box, for each list item, <strong>HAHTsite</strong><br />

instantiates a list element of type POPULATER_ELEMENT.<br />

Runtime list elements. These are elements — of type PAGE_RUN_ELEMENT<br />

— that you add to a list box or combo box by making calls to<br />

ListElement and Listbox methods.<br />

Any list box can contain any combination of these three types of elements.<br />

For information about creating list elements and working with list boxes, see<br />

the following sections:<br />

“Creating list elements” on page 169<br />

“Getting and setting ListElement properties” on page 171<br />

“Adding list elements to a list” on page 171<br />

“Selecting an element in a list” on page 172<br />

“Finding an item in a list” on page 173<br />

“Getting and setting Listbox properties” on page 173<br />

Creating list elements<br />

List box<br />

List element<br />

A list element has four member variables:<br />

A display value. This is the string that is displayed in the list.<br />

169


Chapter 7: Form Fields <strong>Programming</strong><br />

170<br />

An internal value. This is the value of the list box when the form<br />

containing the list box is submitted with a particular display value<br />

selected. Each display value has a corresponding internal value.<br />

A selected status. If a list element's selected status is set to true, the list<br />

element will be highlighted when the list box is displayed.<br />

An element type (or creation type). This type indicates whether the<br />

element was created at design time, by a populater, or by user-written<br />

code. The following constants represent these three types:<br />

STATIC_ELEMENT, POPULATER_ELEMENT, and PAGE_RUN_ELEMENT. <strong>HAHTsite</strong><br />

uses this type to determine when to remove elements from a list.<br />

Design-time elements are never removed; populater elements are<br />

removed each time the list box is populated; and page-run elements are<br />

removed each time the page is run.<br />

To create a list element, you call one of the ListElement class's constructors.<br />

ListElement(String aDisplayVal)<br />

ListElement(String aDisplayVal, String anInternalVal,<br />

boolean aSelOnOff, int aCreateFlag)<br />

If you use the first form of the constructor, <strong>HAHTsite</strong> sets the list element's<br />

internal value to the empty string, its selection flag to false, and its type to<br />

STATIC_ELEMENT.<br />

The code fragments below illustrate how to instantiate a list element in both<br />

Java and HAHTtalk Basic.<br />

Java<br />

ListElement element1 = new ListElement("JaneDoe", "12345",<br />

false, PAGE_RUN_ELEMENT);<br />

HAHTtalk Basic<br />

Dim element1 As Object<br />

Set element1 = CreateJavaObject("ListElement", "Jane Doe", _<br />

"12345", False, PAGE_RUN_ELEMENT)<br />

In this case, the list element’s display value is “Jane Doe,” its internal value is<br />

Jane’s employee number 12345, and the element will not be highlighted by<br />

default.


Chapter 7: Form Fields <strong>Programming</strong><br />

Note - It's also possible to create a list element and insert that<br />

element into a list in a single step. For information on how to<br />

do this, see “Adding list elements to a list” on page 171.<br />

Getting and setting ListElement properties<br />

Once you've created a ListElement, you can read or set the properties of this<br />

object using the methods listed in the table below.<br />

Method Description<br />

setCreateFlag Indicates whether this list element was created at design<br />

time, by a populater (a data agent), or by user code. In<br />

your code, you’ll want to set this flag to<br />

PAGE_RUN_ELEMENT to indicate that you’re adding this<br />

item to the list at runtime.<br />

setDisplayValue Sets a list element’s display value, the value that will be<br />

shown in the list box.<br />

setInternalValue Sets a list element’s internal value. This value will be the<br />

list box’s value when the form is submitted.<br />

setSelected Sets the list element’s selected flag, to determine<br />

whether the list element will be highlighted when the<br />

list box is displayed.<br />

getCreateFlag Reads the list element’s element type: STATIC_ELEMENT,<br />

PAGE_RUN_ELEMENT, or POPULATER_ELEMENT.<br />

getDisplayValue Reads the list element’s display value.<br />

getInternalValue Reads the list element’s internal value.<br />

isSelected Gets the value of the list element’s selected flag.<br />

Adding list elements to a list<br />

This section covers how to insert list elements into a list box and how to<br />

remove them.<br />

You have three options when you insert a list element (or elements) into a list<br />

box. You can:<br />

Insert a list element that you created earlier.<br />

Create a list element and insert it into a list box in a single step.<br />

Insert a vector of list elements into a list box.<br />

171


Chapter 7: Form Fields <strong>Programming</strong><br />

The prototypes for the methods that perform these tasks are shown below:<br />

int insertElementAt(ListElement anElement, int index)<br />

int insertElementAt(String aDisplayVal, String an InternalVal,<br />

boolean aSelOnOff, int aCreateFlag, int index)<br />

void insertElementAt(Vector aList, int index)<br />

For each method, the index parameter indicates the point in the list at which<br />

the new element(s) should be added. For example, if you specify an index of<br />

3, the new element will become the third item in the list box's list.<br />

172<br />

Note - You can replace an existing list item using the method<br />

setElementAt. (This method’s counterpart, getElementAt,<br />

returns the ListElement object at a particular index.)<br />

To remove an item from a list box, use one of the methods shown in the table<br />

below.<br />

Method Description<br />

removeAllElements Removes all of a list box’s list items.<br />

removeElementAt Removes the list item at a particular index into the list.<br />

removeElements Removes all list items of a particular type:<br />

STATIC_ELEMENT, PAGE_RUN_ELEMENT, or<br />

POPULATER_ELEMENT.<br />

Selecting an element in a list<br />

Using methods of the Listbox class, you can specify:<br />

Whether the user can select only one value from the list box before<br />

submitting the form containing the list box, or whether the user can<br />

select several values.<br />

Which list element or elements (if any) should be highlighted (selected)<br />

when the list box is first displayed.<br />

A Listbox object contains a member variable that determines whether<br />

multiple selections are allowed. You can read the value of this variable using<br />

the method isMultiple, and you can set the value using the method<br />

setMultiple. If the variable is set to true, multiple selections are allowed.<br />

Note - One difference between list boxes and combo boxes is<br />

that combo boxes do not allow multiple selections.<br />

To indicate that a list item should be selected — or deselected — when the list<br />

box is displayed, use one of the methods listed in the table below.


Method Description<br />

Finding an item in a list<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

selectIfDisplayValueIs Clears the existing selection, and then selects all<br />

of the items in the list whose display value<br />

matches a value you supply.<br />

selectIfInternalValueIs Clears the existing selection, and then selects all<br />

of the items in the list whose internal value<br />

matches a value you supply.<br />

selectItem Selects the item at the position you indicate. If<br />

this is a single-select list box, all other items are<br />

deselected.<br />

deSelectAll Deselects all of the elements in the list.<br />

deSelectItem Deselects the element at the position indicated<br />

by an index.<br />

The Listbox class contains several methods that enable you to determine the<br />

current location (index) of a list element within a list box. These methods are<br />

shown in the table below.<br />

Method Description<br />

findDisplayValue Finds an element with a display value equal to a<br />

value you supply. The comparison ignores case.<br />

findInternalValue Finds an element with an internal value equal to a<br />

value you supply. The comparison ignores case.<br />

getSelected Finds the first selected item that follows an index<br />

you provide.<br />

Getting and setting Listbox properties<br />

The Listbox class also contains accessor methods that enable you to get or set<br />

a number of properties of the list box or of a list element contained in the list<br />

box. See the table below.<br />

173


Chapter 7: Form Fields <strong>Programming</strong><br />

Method Description<br />

setInsertPopulaterElementsFirst Moves any list elements of type<br />

POPULATER_ELEMENT to the beginning<br />

of the list. By default, such entries are<br />

placed at the end of the list.<br />

setMultiple Sets or clears the HTML attribute<br />

multiple for this list box. This<br />

attribute controls whether or not<br />

multiple selections are allowed in the<br />

list box.<br />

setSize Sets the HTML size attribute. The<br />

size attribute controls the number of<br />

elements that will be visible when the<br />

list box is displayed in the browser.<br />

getDisplayValue Returns the display value of the list<br />

element at the index you supply.<br />

getElementCount Returns the number of list elements in<br />

the list.<br />

getInsertPopulaterElementsFirst Indicates whether list elements of type<br />

POPULATER_ELEMENT will be displayed<br />

in the list box first or last.<br />

getInternalValue Returns the internal value of the list<br />

element at the index you supply.<br />

isMultiple Returns true if the multiple attribute<br />

is set for this list box; otherwise, it<br />

returns false.<br />

isSelected Returns true if the list element at the<br />

index you specify is selected. Returns<br />

false if the item is not selected or<br />

doesn't exist.<br />

getSize Returns the value of the list box’s size<br />

(HTML) attribute. The size attribute<br />

controls the number of elements that<br />

will be visible when the list box is<br />

displayed in the browser.<br />

174


Radiobutton properties<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

By setting the properties of Radiobutton objects, you can control at runtime<br />

such things as which radio button in a group is selected. For example, say that<br />

one of your forms has a group of three radio buttons — radioSelf,<br />

radioSpouse, and radioDependent — and that when you created the radio<br />

buttons you chose to have radioSelf checked by default. However, at runtime<br />

you would like to be able to change which radio button is selected by default.<br />

Perhaps if the last time the form was submitted, the radioSelf radio button<br />

was checked, you would like the radioSpouse radio button to be checked by<br />

default. You can make this change by using the Radiobutton method<br />

setChecked.<br />

Java<br />

if (...) {<br />

radioSelf.setChecked(false);<br />

radioSpouse.setChecked(true);<br />

}<br />

HAHTtalk Basic<br />

if (...) Then<br />

radioSelf.setChecked False<br />

radioSpouse.setChecked True<br />

End If<br />

The table below lists all of the methods commonly used to set and read the<br />

properties of radio buttons:<br />

Method Explanation<br />

setCheckedIfValueIs sets the radio button’s Checked variable to<br />

true if the argument you pass to the method<br />

matches the current value of the radio button.<br />

If this variable is set to true, the radio button is<br />

checked when its page is first displayed.<br />

setChecked sets the radio button’s Checked variable to<br />

true unconditionally. If this variable is set to<br />

true, the radio button is checked when its page<br />

is first displayed.<br />

175


Chapter 7: Form Fields <strong>Programming</strong><br />

Method Explanation<br />

setGroupName establishes the name of the button group to<br />

which a radio button belongs<br />

getGroupName retrieves the name of the button group to which<br />

a radio button belongs<br />

isChecked determines whether a radio button’s Checked<br />

variable is set to true<br />

StaticText properties<br />

There are a couple of common reasons for setting a property of a static-text<br />

field at runtime. For example, suppose that a static-text field on your page is a<br />

hypertext link and that you want to be able to set the destination of the link<br />

at runtime. You could use code similar to the following to accomplish this<br />

task.<br />

Java<br />

if (...) {<br />

staticLink.setHREF(hahtSession().createStaticURL<br />

("Destination.html","default"));<br />

}<br />

HAHTtalk Basic<br />

If (...) Then<br />

staticLink.setHREF HahtSession.createStaticURL _<br />

("Destination.html", "default")<br />

End If<br />

As another example, consider the case where you’ve read a currency value<br />

from a database and assigned it to a static-text field. By default, this value will<br />

be displayed without the proper formatting. To display the value as a dollar<br />

amount, you would normally set the Format property of the static-text field<br />

using the <strong>IDE</strong>. However, you could also format the value by calling the method<br />

setDisplayText above the form containing the field:<br />

176


Java<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

static1.setDisplayText(com.haht.Haht.format(static1.value,<br />

"Currency"));<br />

HAHTtalk Basic<br />

static1.setDisplayText Format$(static1.value,"Currency")<br />

Note - For a list of the predefined formats you can use in this<br />

call, see Chapter 14, “Working with Form Fields,” in the<br />

<strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>.<br />

The table below lists the methods most commonly used to set and read the<br />

properties of StaticText objects.<br />

Method Explanation<br />

setDisplayText controls the string to be displayed in a<br />

static-text field without changing the<br />

underlying value of the field. Usually, this string<br />

is a reformatted version of the field’s value. You<br />

can reformat this field’s value using the<br />

Format$ function (HAHTtalk Basic) or the<br />

format method (Java).<br />

setEscapeHTMLChars determines whether characters such as ‘’ in a static text field’s value are interpreted as<br />

being part of an HTML tag or not. If an object’s<br />

mEscapeHTMLChars variable is set to true (the<br />

default), these characters are interpreted as<br />

HTML and are used in formatting the<br />

non-HTML portion of the value. If the variable<br />

is set to false, the characters are displayed as<br />

part of the value.<br />

setHREF used with static text that is (the default<br />

case)also a link. Establishes the URL of the page<br />

being linked to.<br />

setLinkID used with static text that is also a link. Sets the<br />

project ID of the page being linked to.<br />

177


Chapter 7: Form Fields <strong>Programming</strong><br />

Method Explanation<br />

setTarget used with static text that is also a link.<br />

Establishes the frame in which to display the<br />

page being linked to.<br />

getHREF used with static text that is also a link. Returns<br />

the URL of the destination page.<br />

getLinkID used with static text that is also a link. Returns<br />

the project ID of the destination page.<br />

getTarget used with static text that is also a link. Returns<br />

the name of the frame in which the destination<br />

page will be displayed.<br />

isEscapeHTMLChars returns true if HTML special characters are<br />

being interpreted as such<br />

TextArea properties<br />

A text-area object’s properties enable you determine at runtime the size of the<br />

text area and whether word wrap is turned on or off. The table below lists the<br />

methods that you use to set and read these properties.<br />

Method Explanation<br />

setCols establishes the number of columns in the text<br />

area<br />

setRows establishes the number of rows in the text area<br />

setWordWrap turns word wrap on or off. If word wrap is off,<br />

your text remains on one line until you type<br />

Enter.<br />

getCols returns the number of columns in a text area<br />

getRows returns the number of rows in a text area<br />

isWordWrap determines whether word wrap is on or off<br />

Textbox properties<br />

Being able to set text-box properties at runtime is handy for many tasks,<br />

including internationalization. For instance, the code below enables you to set<br />

178


Chapter 7: Form Fields <strong>Programming</strong><br />

the size of a Phone field to 12 if the user is working in the United States and<br />

to 16 if the user is working in France:<br />

Java<br />

if (language == "English") {<br />

txtPhone.setSize(12);<br />

}<br />

else if (language == "French") {<br />

txtPhone.setSize(16);<br />

}<br />

else {<br />

...<br />

}<br />

HAHTtalk Basic<br />

If (language = "English") Then<br />

txtPhone.setSize 12<br />

ElseIf (language = "French") Then<br />

txtPhone.setSize 16<br />

Else<br />

...<br />

End If<br />

The table below lists the most useful of the methods you can use to set and<br />

read the properties of Textbox objects.<br />

Method Explanation<br />

setHidden sets a Textbox object’s Hidden variable to true<br />

or false. If this variable is set to true, the text<br />

box becomes a “hidden” form field; otherwise,<br />

it’s a regular text box.<br />

Primarily used for compatibility with <strong>HAHTsite</strong><br />

3.x.<br />

setMaxLength establishes the maximum number of characters<br />

that can be entered in the field<br />

setPassword used to indicate that a text box is a password<br />

field. When you enter characters in a password<br />

field, they are not echoed literally.<br />

179


Chapter 7: Form Fields <strong>Programming</strong><br />

Method Explanation<br />

setSize determines the width of the text box in<br />

characters, that is, how many characters you<br />

can view at once<br />

getMaxLength returns the maximum number of characters<br />

that can be entered in the field<br />

getSize returns the width of the field in characters<br />

isHidden returns the value of the object’s Hidden<br />

variable, which determines whether the text<br />

box is a “hidden” field<br />

isPassword returns the value of the object’s Password<br />

variable, which determines whether the field is<br />

a password field or not<br />

Calculating form-field values<br />

Suppose that you’ve developed a form to display information stored in a<br />

database concerning the quarterly sales totals for your sales people.<br />

A data agent on your HTML page retrieves each sales person’s name, employee<br />

number, and quarterly sales figures from a database and displays them in your<br />

form.<br />

180


Chapter 7: Form Fields <strong>Programming</strong><br />

This is fine. But suppose you also want the form to display each sales person’s<br />

total sales for the fiscal year to date. This is not the type of value that you<br />

would store in your database because it can easily be calculated from the<br />

quarterly sales figures. The remainder of this section explains how to perform<br />

this type of calculation and display the result using <strong>HAHTsite</strong>.<br />

Suppose your HTML page contains a heading, followed by a data agent,<br />

followed by a form. If you add code between the data agent and the form, that<br />

code will be executed:<br />

after the data agent has performed the most recently requested<br />

command, such as Move Next<br />

before the data retrieved by the data agent is actually displayed in the<br />

form<br />

You can use methods of the form-field classes used in the form to read and set<br />

the values that will be displayed in the form.<br />

Assume that you want to take the quarterly sales figures retrieved by the data<br />

agent, calculate the yearly total, and display that total in a static-text field<br />

labeled Year-to-Date Sales. You can do this using the code shown below.<br />

181


Chapter 7: Form Fields <strong>Programming</strong><br />

Java<br />

try<br />

{<br />

double salesQ1 = (new<br />

Double(staticFirstQtrSales.getValue())).doubleValue();<br />

double salesQ2 = (new<br />

Double(staticSecondQtrSales.getValue())).doubleValue();<br />

double salesQ3 = (new<br />

Double(staticThirdQtrSales.getValue())).doubleValue();<br />

double salesQ4 = (new<br />

Double(staticFourthQtrSales.getValue())).doubleValue();<br />

double salesCY = salesQ1 + salesQ2 + salesQ3 + salesQ4;<br />

String salesCYStr = Double.toString(salesCY);<br />

staticYearSales.setValue(salesCYStr);<br />

}<br />

catch ( NumberFormatException e )<br />

{<br />

out.println("Exception = " + e.getMessage());<br />

}<br />

HAHTtalk Basic<br />

Dim Q1Sales As Double<br />

Dim Q2Sales As Double<br />

Dim Q3Sales As Double<br />

Dim Q4Sales As Double<br />

Dim FYSales As Double<br />

Q1Sales = Val(staticFirstQtrSales.getValue())<br />

Q2Sales = Val(staticSecondQtrSales.getValue())<br />

Q3Sales = Val(staticThirdQtrSales.getValue())<br />

Q4Sales = Val(staticFourthQtrSales.getValue())<br />

FYSales = Q1Sales + Q2Sales + Q3Sales + Q4Sales<br />

staticYearSales.setValue Str$(FYSales)<br />

This code uses the getValue method of the quarterly sales static-text objects<br />

to obtain the quarterly sales figures. The code then sums the quarterly figures<br />

and calls the setValue method to set the value of a year-to-date-sales<br />

static-text field. When the form is displayed, the sum will be displayed in the<br />

appropriate field.<br />

182


Chapter 7: Form Fields <strong>Programming</strong><br />

For more information about setting and reading form field attributes using the<br />

setValue and getValue methods, see “Setting and getting form-field<br />

properties” on page 161.<br />

Calling user code from a button<br />

Similar to the way in which your application can call a subroutine associated<br />

with a form at the time you submit the form, you can have your application<br />

execute “user code” associated with a button when a form is submitted as a<br />

result of that button being clicked. These two features give you similar<br />

capabilities; in fact, the example presented in “Calling a subroutine from a<br />

form” on page 134 (writing a BLOB to a database) could just as well have been<br />

handled by “user code” associated with a button. However, there are also<br />

important differences between the two methods of calling user code. These<br />

differences are discussed in “Code associated with a button versus code<br />

associated with a form” below.<br />

This section also covers the mechanics of configuring a button to have a<br />

Submit Action of User Code.<br />

Code associated with a button versus code associated<br />

with a form<br />

Many tasks can be handled in either a subroutine associated with a form or<br />

user code associated with a particular button; in both cases, <strong>HAHTsite</strong> executes<br />

code when a form is submitted. However, it’s important to understand the<br />

183


Chapter 7: Form Fields <strong>Programming</strong><br />

differences between these two actions and how the actions relate to one<br />

another.<br />

The obvious differences are that:<br />

184<br />

a subroutine associated with a form is executed every time its form is<br />

submitted, while user code associated with a button is executed only<br />

when its form is submitted as a result of a particular button being pressed<br />

only one subroutine can be associated with a form while you can<br />

associate different subroutines with different form buttons<br />

One thing, however, might not be so obvious. On a single page, you can’t use<br />

both a form action of Subroutine and a button action of User Code. This fact<br />

has to do with the way in which command handlers for buttons are generated.<br />

If the form’s action is not Automatic/SELF, <strong>HAHTsite</strong> does not even generate a<br />

command handler for a form button, so any subroutine you associated with<br />

that button will never be called. You must loop back to the page on which you<br />

began before the “user code” associated with a button can be executed.<br />

Configuring a button to call user code<br />

To configure a button so that user-supplied code is called when the button is<br />

selected, follow these steps.<br />

To configure the button:<br />

1 Double-click the form button to bring up the Form Field Properties<br />

window.


2 From the Action combo box, select the User Code option.<br />

Chapter 7: Form Fields <strong>Programming</strong><br />

A group of fields labeled Subroutine appears in the window.<br />

3 In the Definition field, enter the name of a Basic subroutine or a Java<br />

method.<br />

In a Basic project, you can enter the name of any subroutine in the<br />

project, along with any required parameters. In a Java project, you must<br />

adhere to the following rules:<br />

You must enter the name of a method defined on the current page. This<br />

means that you must have used the page’s Server-side Code view to<br />

enter your code.<br />

Enter an argument list. The argument list can be empty, but the<br />

parentheses must be present.<br />

Don’t terminate your call with a semicolon. The code generator adds a<br />

semicolon for you.<br />

4 Select the OK button.<br />

185


Chapter 7: Form Fields <strong>Programming</strong><br />

186


Data-Agent<br />

<strong>Programming</strong><br />

8<br />

Data agents and command handlers ...........................................................188<br />

Calling data-agent methods at runtime.......................................................190<br />

Setting a data agent’s command .............................................................190<br />

Performing a data-agent action...............................................................192<br />

Getting and setting the values of a data agent’s fields ..........................196<br />

Getting a reference to a data agent’s connection...................................198<br />

Dealing with recordsets ...........................................................................198<br />

Getting parameters to stored procedures................................................202<br />

Refreshing a data agent’s data.................................................................203<br />

Sorting records .........................................................................................204<br />

Filtering records .......................................................................................205<br />

Handling errors........................................................................................210<br />

Enabling tracing.......................................................................................210<br />

The structure of a command handler..........................................................212<br />

Modifying a command handler ...................................................................216<br />

Where to add code to a command handler ...........................................216<br />

Examples of adding code to a command handler .................................217<br />

Changing the flow of control in a command handler ..........................225<br />

Example of changing the flow of control ..............................................227<br />

187


Chapter 8: Data-Agent <strong>Programming</strong><br />

Data agents and command handlers<br />

As you know if you’ve created a <strong>HAHTsite</strong> page that links a form to a database,<br />

<strong>HAHTsite</strong> uses objects called data agents to:<br />

188<br />

get an ADO recordset from a data source<br />

populate form fields in a form using a set of bindings defined in the data<br />

agent<br />

<strong>HAHTsite</strong> performs actions against the data agent’s recordset when a user<br />

clicks a form button. For example, if the user clicks a Move Next button, code<br />

generated by <strong>HAHTsite</strong> calls the data agent’s performAction method using an<br />

argument that indicates that the data agent should change its current record.<br />

Once the data agent’s record pointer has been updated, the page can exit. The<br />

next time the page is run, the data agent will populate the form with data from<br />

the new current record.


Chapter 8: Data-Agent <strong>Programming</strong><br />

The code generated to perform the action associated with a form button is<br />

called a command handler. Each button has its own command handler, and this<br />

method or subroutine performs the following tasks:<br />

If the Submit Action associated with the clicked button was Insert or<br />

Update, the command handler binds the data in the form to fields in the<br />

data agent’s current record. If the action was Query or Find, the<br />

command handler fills in the Query or Find criteria.<br />

In all cases, the command handler performs the requested operation.<br />

If the operation was successful, the command handler calls the button’s<br />

success page.<br />

If the operation was not successful, the command handler calls the<br />

button’s failure page.<br />

The remainder of this chapter discusses two important ways in which you can<br />

customize pages that include data agents:<br />

You can call data-agent methods directly by placing Java or HAHTtalk<br />

Basic code on your page (Server-side Code view).<br />

In this view, you’ll see two methods or subroutines named<br />

dataAgent_OnPreRun and dataAgent_OnPostRun. When you execute your<br />

page, dataAgent_onPreRun executes immediately before the<br />

dataAgent.run routine executes. (dataAgent.run executes the data agent’s<br />

initial command, if necessary, and opens the data agent’s recordset.) The<br />

dataAgent_OnPostRun routine executes immediately after dataAgent.run<br />

completes — before any data retrieved from the data source has been<br />

bound to form fields.<br />

The dataAgent_OnPreRun method or subroutine is a good place to do such<br />

things as change the data agent’s command, and the<br />

dataAgent_OnPostRun routine gives you an opportunity to examine the<br />

values in the data agent’s current record before the values in that record<br />

are bound to form fields.<br />

For further information about the DataAgent methods you can call from<br />

these routines, see “Calling data-agent methods at runtime” on page 190.<br />

You can customize the command handlers that <strong>HAHTsite</strong> generates to<br />

control what happens when a user clicks a form button. You can add<br />

functionality to these command handlers or change the normal flow of<br />

control in them. For additional information on this subject, see “The<br />

structure of a command handler” on page 212 and “Modifying a<br />

command handler” on page 216.<br />

189


Chapter 8: Data-Agent <strong>Programming</strong><br />

Calling data-agent methods at runtime<br />

The DataAgent class includes a number of methods that enable you to control<br />

the behavior of a data agent at runtime. This section contains information<br />

about the most frequently used of these methods. This subset of methods<br />

allows you to:<br />

190<br />

set the command that a data agent will use to get its recordset<br />

perform a data-agent action, such as inserting a record<br />

get or set the value of a field in a data agent’s recordset<br />

get a reference to a data agent’s connection<br />

get a reference to a data agent’s recordset<br />

get the values of a stored procedure’s output parameters<br />

refresh a data agent’s data<br />

sort a data agent’s records<br />

filter the records going in to the data agent’s recordset<br />

handle a data agent’s errors<br />

enable tracing for a data agent<br />

Setting a data agent’s command<br />

The command associated with a data agent determines how the data agent<br />

obtains its recordset. This command can be a database table name, the name<br />

of a stored procedure, the name of a view, or (if the data agent is connected to<br />

a relational database) a SQL statement. You set such a command when you<br />

create a data agent using the <strong>IDE</strong>; however, you can override this original<br />

command using the DataAgent class’s setCommand method.<br />

For example, say that you have a project that displays records from an<br />

employee-information database and that the data agent in your project uses a<br />

table name (Employees) as its command. You could quickly modify this<br />

project to display information only about employees from North Carolina by<br />

adding code similar to the following to your page’s dataAgent_OnPreRun<br />

routine (Server-side Code view).<br />

Java<br />

da1.setCommand("SELECT * FROM Employees WHERE State = 'NC'");<br />

da1.setCommandType (com.haht.ado.CommandTypeEnum.adCmdText);


HAHTtalk Basic<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

da1.setCommand "SELECT * FROM Employees WHERE State = 'NC'"<br />

da1.setCommandType ADO_CommandTypeEnum_adCmdText<br />

In this case, the data agent’s command is being changed from a table name to<br />

a SQL statement. Note that you provide the new command using the<br />

setCommand method and that you use the setCommandType method to specify<br />

the type of the new command. (You don’t need to specify the type if the<br />

command type isn’t changing.) The table below shows the Java class variables<br />

(constants) that you can use with the setCommandType method in Java<br />

projects.<br />

Constant Meaning<br />

CommandTypeEnum.adCmdStoredProc The command is the name of a stored<br />

procedure.<br />

CommandTypeEnum.adCmdTable The command is the name of a table<br />

or a view.<br />

CommandTypeEnum.adCmdText The command is a textual command,<br />

such as a SQL statement. The<br />

command might also be a command<br />

requesting data from a nonrelational<br />

data source.<br />

CommandTypeEnum.adCmdUnknown The type of the command is<br />

unknown.<br />

In HAHTtalk Basic projects, you use similar constants, but the constants have<br />

slightly different names:<br />

ADO_CommandTypeEnum_adCmdStoredProc<br />

ADO_CommandTypeEnum_adCmdTable<br />

ADO_CommandTypeEnum_adCmdText<br />

ADO_CommandTypeEnum_adCmdUnknown<br />

The Basic constants are defined in the file ADOConstants.hbh, which <strong>HAHTsite</strong><br />

automatically includes in the generated code for every page that contains a<br />

data agent.<br />

191


Chapter 8: Data-Agent <strong>Programming</strong><br />

192<br />

Note - These constants are defined so that Basic projects do not<br />

have to incur the overhead of creating a Java class object in<br />

order to set a data agent’s command type.<br />

That’s all there is to changing a data agent’s command. However, there are a<br />

couple of side effects of using the setCommand method that you should be<br />

aware of:<br />

If your command is the name of a stored procedure, any “pre-fetch”<br />

filtering or sorting operations are changed to “post-fetch” filtering or sort<br />

operations. This change is necessary because “pre-fetch” operations can<br />

modify the command text by adding a WHERE or ORDER BY clause, which<br />

is inappropriate for a stored-procedure call.<br />

If you change the command from a non-SQL command to a SQL<br />

command, the data agent’s mIsStandardSQL member variable remains set<br />

to false until you explicitly change it. If you are performing pre-fetch<br />

filtering or sorting, you should change the value of this variable by<br />

calling setIsStandardSQL with a parameter of true. Pre-fetch operations<br />

are usually more efficient if mIsStandardSQL is set to true.<br />

If the data agent whose command you are setting is being used to<br />

populate a form (which is typically the case), the data agent’s notion of<br />

which Page Items (form fields) are bound to which Data Items (fields in<br />

the data agent’s recordset) must be taken into consideration. That is, the<br />

recordset retrieved by the new command must contain a field with the<br />

appropriate name and data type for each of the data agent’s Data Items so<br />

that the data agent can populate the corresponding form fields.<br />

If the original data-agent command was to call a stored procedure and<br />

the new command is to call a different stored procedure, the two stored<br />

procedures must have the same parameters, or they need to be modified.<br />

Performing a data-agent action<br />

A data agent usually performs actions, such as changing the current record or<br />

updating a record, when a user clicks a form button whose target is that data<br />

agent. The data agent also performs an action the first time that the page on<br />

which it appears is run. All this is typically handled with generated code.<br />

However, it’s also possible to write code that causes the data agent to perform<br />

an action:<br />

when a form button is clicked<br />

when the data agent’s page is first displayed<br />

The following sections explain in more detail how to write this type of code.


Performing data-agent actions<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

Typically, a data agent performs an action when the command handler<br />

associated with a form button calls the data agent’s performAction method.<br />

It’s also possible to call this method directly.<br />

The two prototypes for this method are shown below:<br />

boolean performAction(int anAction)<br />

boolean performAction(int anAction, java.lang.Object<br />

anActionArg)<br />

The first form of the method takes as its argument a constant. In Java projects,<br />

this constant is a final class variable of the class<br />

com.haht.project.datamanager.DMConstants. The constants you can use<br />

with the first form of this method are shown in the table below.<br />

Constant Action<br />

ACTION_ADD_NEW adds a new record to the data agent’s recordset<br />

ACTION_CANCEL_UPDATE enables you to cancel an Insert operation after a<br />

new record has been created, but before the<br />

record has been updated<br />

ACTION_CLEAR clears the form fields being populated by the<br />

data agent<br />

ACTION_DELETE deletes the data agent’s current record<br />

ACTION_FIND performs an ADO Find operation. Finds the first<br />

record in the data agent’s recordset that meets a<br />

single criterion and moves the current-record<br />

pointer to that record. You must have set up<br />

your find criterion (by calling<br />

setFindCriteria) before you perform this<br />

action.<br />

ACTION_INSERT inserts the values of the form fields being<br />

populated by the data agent into a new record<br />

in the data agent’s recordset<br />

ACTION_MOVE_FIRST makes the first record in the data agent’s<br />

recordset the current record<br />

ACTION_MOVE_LAST makes the last record in the data agent’s<br />

recordset the current record<br />

ACTION_MOVE_NEXT makes the next record in the data agent’s<br />

recordset the current record<br />

193


Chapter 8: Data-Agent <strong>Programming</strong><br />

Constant Action<br />

ACTION_MOVE_PREVIOUS makes the previous record in the data agent’s<br />

recordset the current record<br />

ACTION_NEXT_RECORDSET loads a new recordset into the data agent — the<br />

next in a series of recordsets retrieved by the<br />

data agent’s last command<br />

ACTION_NONE no action<br />

ACTION_QUERY returns a set of records (from the data agent’s<br />

recordset) that meet a set of criteria you supply.<br />

You must establish these criteria by making one<br />

or more calls to setQueryCriteria before you<br />

perform this action.<br />

ACTION_REQUERY causes the data agent to get a new recordset by<br />

calling the data agent’s current command<br />

(established by the last call to setCommand)<br />

ACTION_UPDATE updates the data agent’s current record<br />

You use similarly named constants in a HAHTtalk Basic project. You just need<br />

to prepend DMConstants_ to a name shown in the table above. For example,<br />

to request a move-next action, you would use the constant<br />

DMConstants_ACTION_MOVE_NEXT. These Basic constants are defined in the file<br />

SOMConstants.hbh, which is included in the generated code for every page<br />

with a data agent.<br />

There are also two constants that require or may take an associated argument:<br />

ACTION_EXEC_COMMAND and ACTION_FIND<br />

(DMConstants_ACTION_EXEC_COMMAND and DMConstants_ACTION_FIND in Basic<br />

projects). You use these constants with the second form of the performAction<br />

method. (The constant is the first argument to the method.)<br />

The constant ACTION_EXEC_COMMAND causes performAction to execute the<br />

command that you supply as an argument (the second argument to<br />

performAction). The argument associated with ACTION_EXEC_COMMAND can be<br />

a string or null.<br />

194<br />

If the argument is a string, it must be the command that you want the<br />

data agent to use to get a new recordset. This command can be the name<br />

of a table, the name of a stored procedure, and so forth. (This argument<br />

is analogous to the argument to the setCommand method.)<br />

If the argument is null, performAction executes the last command set<br />

using the setCommand method.


Chapter 8: Data-Agent <strong>Programming</strong><br />

The constant ACTION_FIND causes performAction to find the next record in<br />

the recordset that meets the criterion specified in its associated argument, a<br />

string. This string must have the form columnName operator value. For<br />

example, the string "State = 'NC'" is a valid find-criteria string.<br />

Note - Both a connection and a recordset must be open before<br />

you call performAction with any constant other than<br />

ACTION_NONE or ACTION_EXEC_COMMAND. In addition, a<br />

connection must be open before you call performAction with<br />

the constant ACTION_EXEC_COMMAND.<br />

Here’s an example of how you might use the performAction method in your<br />

project. Say that your application calls a stored procedure that returns two<br />

recordsets and that the two recordsets have the same columns. You can only<br />

work with the first recordset using the standard data agent commands. To load<br />

the second recordset into the data agent, you would need to call<br />

performAction with the ACTION_NEXT_RECORDSET argument. For example, you<br />

could add code to the command handler for a Move Next button to have your<br />

application load the second recordset when a user clicks a Move Next button<br />

while looking at the last record in the first recordset.<br />

Note - For detailed information about command handlers, see<br />

“The structure of a command handler” on page 212 and<br />

“Modifying a command handler” on page 216.<br />

Setting a data agent’s initial command<br />

It’s also possible to set a data agent’s initial command programatically. You do<br />

this using the setInitialAction method, whose prototype is shown below:<br />

void setInitialAction(int anAction)<br />

This method takes as its argument a constant defined in the class<br />

com.haht.project.datamanager.DMConstants (Java projects) or in the file<br />

SOMConstants.hbh (HAHTtalk Basic projects). The constants most commonly<br />

used with this method are shown in the table below.<br />

Java HAHTtalk Basic<br />

DMConstants.ACTION_CLEAR DMConstants_ACTION_CLEAR<br />

DMConstants.ACTION_MOVE_FIRST DMConstants_ACTION_MOVE_FIRST<br />

DMConstants.ACTION_MOVE_LAST DMConstants_ACTION_MOVE_LAST<br />

DMConstants.ACTION_MOVE_NEXT DMConstants_ACTION_MOVE_NEXT<br />

DMConstants.ACTION_MOVE_PREVIOUS DMConstants_ACTION_MOVE_PREVIOUS<br />

195


Chapter 8: Data-Agent <strong>Programming</strong><br />

For a complete list of the constants you can use with the setInitialAction<br />

method, see “Performing data-agent actions” on page 193.<br />

Since a data agent’s initial action can be set using the <strong>IDE</strong>, you will generally<br />

only use this method if you want to change the initial action based on some<br />

user preference. For example, some users might want to browse a set of records<br />

beginning with the first record, while others might want browse the records<br />

starting with the last record.<br />

Java<br />

if (...) {<br />

da1.setInitialAction<br />

(com.haht.project.datamanager.DMConstants.ACTION_MOVE_FIRST);<br />

}<br />

else {<br />

da1.setInitialAction<br />

(com.haht.project.datamanager.DMConstants.ACTION_MOVE_LAST);<br />

}<br />

HAHTtalk Basic<br />

If (...) Then<br />

da1.setInitialAction DMConstants_ACTION_MOVE_FIRST<br />

Else<br />

da1.setInitialAction DMConstants_ACTION_MOVE_LAST<br />

End If<br />

Getting and setting the values of a data agent’s fields<br />

The DataAgent class includes a number of methods that enable you to set and<br />

retrieve the values of fields in a data agent’s recordset. These methods can be<br />

useful in command handlers where you need to set or test the value of a field<br />

before a data-agent action is performed. For instance, a code example<br />

presented later in this chapter — see “Altering a form-field value before<br />

binding” on page 218 — illustrates how you might set a field value in a<br />

command handler to ensure that a field containing an empty string is given a<br />

reasonable default value before its record is inserted in a database.<br />

The table below lists the get and set routines that are available.<br />

196


Method Explanation<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

getFieldString retrieves the value of a field in the current<br />

record as a String. The single argument to this<br />

method can be a String containing a field<br />

name or an integer representing the position of<br />

the field within the record.<br />

getFieldStringByNameOr<br />

Ordinal<br />

retrieves the value of a field in the current<br />

record as a String. The single argument to this<br />

method must be a String containing a field<br />

name or a positional number.<br />

getFieldVariant retrieves the value of a field in the current<br />

record as a Variant. The single argument to<br />

this method can be a String containing a field<br />

name or an integer representing the position of<br />

the field within the record.<br />

getFieldVariantByNameOr<br />

Ordinal<br />

retrieves the value of a field in the current<br />

record as a Variant. The single argument to<br />

this method must be a String containing a<br />

field name or a positional number.<br />

isFieldNull determines whether the value of a field in the<br />

current record is null. The single argument to<br />

this method can be a String containing a field<br />

name or an integer representing the position of<br />

the field within the record. The method’s return<br />

value is a boolean.<br />

setFieldString sets the value of a field in the current record<br />

using a String. The first argument to this<br />

method can be a String containing a field<br />

name or an integer representing the position of<br />

the field within the record. The second is the<br />

String to which the field should be set.<br />

setFieldToNull sets the value of a field in the current record to<br />

null. The single argument to this method can<br />

be a String containing a field name or an<br />

integer representing the position of the field<br />

within the record.<br />

197


Chapter 8: Data-Agent <strong>Programming</strong><br />

Method Explanation<br />

setFieldVariant Sets the value of a field in the current record<br />

using a Variant. The first argument to this<br />

method can be a String containing a field<br />

name or an integer representing the position of<br />

the field within the record. The second is the<br />

Variant to which the field should be set.<br />

198<br />

Note - It’s a good idea to call the data-agent method<br />

isFieldDataAvailable before reading or writing a field —<br />

especially in a HAHTtalk Basic project, where the try/catch<br />

mechanism is not available. A get or set operation could fail if<br />

you’re working with an empty recordset, have reached EOF,<br />

etc.<br />

Getting a reference to a data agent’s connection<br />

Using the DataAgent class’s getConnection method, you can get a reference to<br />

the Connection object being used by the data agent. Using this Connection<br />

object, you can perform all of the actions associated with that object, such as<br />

opening or closing the connection, executing a command, or managing a<br />

transaction. You can also examine the properties of the connection to<br />

determine such things as:<br />

the timeout value for establishing the connection<br />

the timeout value for executing a command<br />

whether the connection is currently open or closed<br />

The prototype for the getConnection method is shown below:<br />

com.haht.ado.Abstract.Connection getConnection()<br />

Dealing with recordsets<br />

The interface to DataAgent objects enables you to perform several types of<br />

actions related to recordsets. For example, you can:<br />

limit the maximum number of records retrieved by a data agent’s<br />

command<br />

make a recordset read only<br />

get a reference to the ADO Recordset object associated with the data<br />

agent


load a session recordset at session start<br />

Limiting the maximum number of records<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

To limit the maximum number of records returned by a data-agent command,<br />

you use the method setMaxRecords:<br />

void setMaxRecords(int aMax)<br />

For example, the code below limits the size of the data agent’s recordset to 100<br />

records.<br />

Java<br />

if (!da1.getInitialActionHasCompleted()) {<br />

da1.setMaxRecords(100);<br />

}<br />

HAHTtalk Basic<br />

If (da1.getInitialActionHasCompleted() = False) Then<br />

da1.setMaxRecords 100<br />

End If<br />

Note - The call to getInitialActionHasCompleted is necessary<br />

to ensure that the limit on the number of records is set only<br />

the first time the page is run (before the data agent’s initial<br />

action has completed). If you attempt to set the limit each time<br />

the page is run, you’ll get an error the second time the page is<br />

run saying that this property can’t be set while a recordset is<br />

open.<br />

Making a recordset read only<br />

You can make a recordset read only by calling a data agent’s setReadOnly<br />

method. If you call this method, users will not be able to perform operations<br />

that change the data in a recordset, such as Insert. In addition, making a<br />

recordset read only makes certain ADO optimizations possible.<br />

The prototype for the setReadOnly method is shown below:<br />

void setReadOnly(boolean readOnly)<br />

199


Chapter 8: Data-Agent <strong>Programming</strong><br />

Getting a reference to a data agent’s recordset<br />

In addition to setting a maximum number of records and making a recordset<br />

read only, you can also get a reference to a data agent’s recordset using the<br />

method getRecordset:<br />

com.haht.ado.Abstract.Recordset getRecordset()<br />

Once you have this reference, you can use all of the recordset methods and<br />

properties defined by ADO. For example, you’ll have access to methods that<br />

enable you to:<br />

200<br />

cancel an update<br />

move to any record in the recordset<br />

refresh the data in the recordset without requirying the data source<br />

check for EOF and BOF<br />

Loading a session recordset at the start of a session<br />

If your application<br />

uses a session recordset and<br />

you need to access data in that recordset before the user visits a page<br />

containing a data agent whose Data Source is that session recordset,<br />

you can load data into the session recordset at the time a user session begins.<br />

To do this, you add code to an on-start method or function. This method must:<br />

get a reference to the session recordset (a data agent)<br />

set some data-agent properties, such as the data agent’s connection and<br />

its command.<br />

call the data agent’s run method<br />

In a Java project, you must add the code that performs these tasks to the<br />

HahtSession class’s onStart method. (This class is defined in the file<br />

HahtSession.java, which is in your Session folder.) The code below provides<br />

an example of how you might implement the onStart method.


Java<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

public void onStart(com.haht.project.SessionEvent anEvent)<br />

{<br />

com.haht.project.datamanager.DataAgent sessionDA =<br />

((HahtSession)Haht.getSession()).getEmployees();<br />

sessionDA.setConnectionByName(“EmployeeConn”);<br />

sessionDA.setCommand("SELECT * FROM Employees");<br />

sessionDA.setCommandType<br />

(com.haht.ado.CommandTypeEnum.adCmdText);<br />

sessionDA.setIsStandardSQL(true);<br />

sessionDA.setInitialAction<br />

(com.haht.project.datamanager.DMConstants.<br />

ACTION_MOVE_FIRST);<br />

sessionDA.run();<br />

}<br />

In your own code, you’ll need to replace the call to getEmployees with a call<br />

to getSessionRecordset where SessionRecordset is the name of your session<br />

recordset.<br />

In a HAHTtalk Basic project, you must add a code page to your project, and in<br />

this file define a public function called HahtSessionOnStart. See the example<br />

below.<br />

201


Chapter 8: Data-Agent <strong>Programming</strong><br />

HAHTtalk Basic<br />

#include "Session\GeneratedSession.hbh"<br />

#include <br />

#include <br />

Public function HahtSessionOnStart As Boolean<br />

Dim sessionDA As Object<br />

Getting parameters to stored procedures<br />

The DataAgent class contains several methods that are useful for getting the<br />

value of an output parameter (or an input/output parameter) of a stored<br />

procedure or the return value of a stored procedure. These methods are shown<br />

in the table below.<br />

202<br />

Set sessionDA = Employees<br />

sessionDA.setConnectionByName "EmployeeConn"<br />

sessionDA.setCommand "SELECT * FROM EMPLOYEES"<br />

sessionDA.setCommandType ADO_CommandTypeEnum_adCmdText<br />

sessionDA.setIsStandardSQL True<br />

sessionDA.setInitialAction DMConstants_ACTION_MOVE_FIRST<br />

sessionDA.run<br />

HahtSessionOnStart = True<br />

End function<br />

Method Explanation<br />

getParameterString(int) retrieves the value of a parameter or the<br />

return value of a stored procedure as a<br />

String. The argument to this method is an<br />

index into a set of parameters.<br />

getParameterString(String) retrieves the value of a parameter or the<br />

return value of a stored procedure as a<br />

String. The argument to this method is a<br />

String containing the name of a<br />

parameter.<br />

getParameterVariant(int) retrieves the value of a parameter or the<br />

return value of a stored procedure as a<br />

Variant. The argument to this method is<br />

an index into a set of parameters.


Method Explanation<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

getParameterVariant(String) retrieves the value of a parameter or the<br />

return value of a stored procedure as a<br />

Variant. The argument to this method is a<br />

String containing the name of a<br />

parameter.<br />

One restriction you should be aware of here is that a stored procedure’s output<br />

parameters may not be available to your application immediately after the<br />

stored procedure is executed. For example, consider the following SQL Server<br />

stored procedure:<br />

CREATE PROCEDURE total_gallons @colorval varchar(20)='%', @sumgal<br />

integer OUTPUT<br />

AS<br />

SELECT cust_id, paint_supplier.name AS brand, color, gallons<br />

FROM paint_order, paint_supplier<br />

WHERE color LIKE @colorval and<br />

paint_supplier.supplier_id=paint_order.supplier_id<br />

SELECT @sumgal=SUM(gallons)<br />

FROM paint_order<br />

WHERE color LIKE @colorval<br />

The first SELECT statement in this stored procedure returns a recordset. Only<br />

after your application has traversed this recordset (or at least until you’ve done<br />

a Move Last), you cannot get the value of sumgal. Once you’ve accessed the<br />

last record in the recordset, the output parameter becomes available.<br />

Refreshing a data agent’s data<br />

The Advanced tab in the <strong>IDE</strong>’s Data Agent Properties dialog enables you to<br />

check a check box to specify that a data agent’ command should be reexecuted<br />

each time its page is run. Reexecuting this command, of course, refreshes the<br />

data in the data agent’s recordset.<br />

You can also request that the data agent execute its command each time its<br />

page is run using the data agent’s setRefreshOnPageRun method.<br />

Java<br />

da1.setRefreshOnPageRun(true);<br />

203


Chapter 8: Data-Agent <strong>Programming</strong><br />

HAHTtalk Basic<br />

da1.setRefreshOnPageRun True<br />

You can place this call in the “Custom constructor code” section of the<br />

Server-side Code view of your page.<br />

204<br />

Note - The DataAgent class also contains a<br />

getRefreshOnPageRun method that retrieves the value of the<br />

data agent’s refresh property.<br />

Sorting records<br />

If you have a page that includes an ADO report, and that report uses grouping,<br />

the records to be displayed in the report must be sorted. This sorting can take<br />

place on the database server, or it can be performed by the <strong>HAHTsite</strong><br />

Application Server. You can control where the sorting takes place by calling the<br />

appropriate method of the DataAgent class, either setPreSort (database) or<br />

setPostSort (Application Server).<br />

By default, <strong>HAHTsite</strong> generates a call to setPostSort on a page that contains<br />

a report with groups, for example:<br />

daEmployees.setPostSort("lastName", "firstName");<br />

This statement indicates that the sorting should be done on the Application<br />

Server. This type of sorting is the default because of a restriction on sorting<br />

records on the database server: If a SELECT statement refers to two or more<br />

columns that are in different tables but have the same name, a “pre” sort will<br />

not work correctly. In addition, you must always use a “post” sort if your data<br />

source is not a relational database.<br />

Having said that, if you are getting data from a relational database and won’t<br />

run into the naming-conflict problem mentioned above, you should let your<br />

database server do the sorting to increase the efficiency of your application. To<br />

make this change, add code that calls the data agent’s setPreSort method in<br />

your page’s constructor or dataAgent_OnPreRun method. See the code below<br />

for an example:<br />

Java<br />

if (!da1.getInitialActionHasCompleted()) {<br />

daEmployees.setPreSort(daEmployees.getPostSort());<br />

daEmployees.setPostSort("");<br />

}


HAHTtalk Basic<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

If (da1.getInitialActionHasCompleted() = False) Then<br />

da1.setPreSort da1.getPostSort()<br />

da1.setPostSort ""<br />

End If<br />

If the report page has not been run previously, this code calls the data agent’s<br />

setPreSort routine to indicate that the sorting should be done by the<br />

database server. The argument passed to this method is the argument that<br />

<strong>HAHTsite</strong> generated for its call to setPostSort — in this case, "lastName",<br />

"firstName". Finally, the code calls setPostSort with an argument of the<br />

empty string so that records will not be sorted by the Application Server.<br />

Filtering records<br />

The <strong>IDE</strong> provides a nice graphical user interface you can use to specify the<br />

conditions a data agent should use to filter the records it retrieves as a result of<br />

a command. For example, you might want a data agent to retrieve information<br />

about sales orders placed after January 1, 1999. This type of filtering is easy —<br />

and can be done on either the database server or the Applicatin Server — but<br />

has one limitation: the same filters are used each time a particular data agent<br />

obtains a recordset.<br />

Suppose you have a project that enables users to view the orders placed by a<br />

particular customer during a specific period of time. The first page of the<br />

application presents a form that asks the user to specify a customer, a starting<br />

date, and an ending date.<br />

205


Chapter 8: Data-Agent <strong>Programming</strong><br />

Only after this form is submitted will you have the information you need to<br />

construct the necessary filter. Therefore, you must set up the filter<br />

programatically on the target page (the page that will contain your data agent<br />

and present the results of your query). Sample code for both a Java project and<br />

a HAHTtalk Basic project is shown below.<br />

206


Java<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

//<br />

// Conditional pre-filtering - use start, end date of previous<br />

// form IF the user filled either of them out.<br />

//<br />

if (aRequest.getURLFieldExists("txtStartDate") &&<br />

!aRequest.getURLField("txtStartDate").equals(""))<br />

{<br />

daUserSQL.setPreFilter (DMConstants.USER_FILTER_URLFIELD,<br />

"purchase_date", ">=", "txtStartDate",<br />

com.haht.ado.DataTypeEnum.adDate);<br />

}<br />

if (aRequest.getURLFieldExists("txtEndDate") &&<br />

!aRequest.getURLField("txtEndDate").equals(""))<br />

{<br />

daUserSQL.setPreFilter (DMConstants.USER_FILTER_URLFIELD,<br />

"purchase_date", "=", "txtStartDate", _<br />

ADO_DataTypeEnum_adDate<br />

End If<br />

If (aRequest.getURLFieldExists("txtEndDate") AND _<br />

aRequest.getURLField("txtEndDate") "") Then<br />

dapaint_order.setPreFilter DMConstants_USER_FILTER_URLFIELD, _<br />

"purchase_date", "


Chapter 8: Data-Agent <strong>Programming</strong><br />

This code calls the method setPreFilter to indicate that the filtering should<br />

take place on the database server. This method is overloaded and can have the<br />

following signatures:<br />

public void setPreFilter (int aType, String aField, String anOp,<br />

String aCompVal)<br />

public void setPreFilter (int aType, String aField, String anOp,<br />

String aCompVal, Object aMaster)<br />

public void setPreFilter (int aType, String aField, String anOp,<br />

String aCompVal, int aDataType)<br />

public void setPreFilter (int aType, String aField, String anOp,<br />

String aCompVal, Object aMaster, int aDataType)<br />

The table below describes the parameters that the method takes.<br />

Parameter Description<br />

aType A constant that indicates the type of the comparison value<br />

to be used in the filter criterion, which has the form field<br />

operator comparisonValue.<br />

In Java projects, you select a constant defined in<br />

com.haht.project.datamanager.DMConstants. The<br />

constants you can choose from are:<br />

208<br />

USER_FILTER_CONSTANT - The comparison value is a<br />

constant.<br />

USER_FILTER_VARIABLE - The comparison value is the<br />

current value of a variable.<br />

USER_FILTER_URLFIELD - The comparison value is the<br />

value of a URL field.<br />

USER_FILTER_RS_FLD - The comparison value is the value<br />

of a field in a master recordset.<br />

In HAHTtalk Basic projects, the corresponding values are<br />

defined in the include file SOMConstants.hbh. These<br />

constants have the same names as their Java counterparts<br />

except that you must prepend DMConstants_ to each name.<br />

For instance, the HAHTtalk Basic equivalent of<br />

USER_FILTER_CONSTANT is<br />

DMConstants_USER_FILTER_CONSTANTS.<br />

aField The name of a column in your data agent’s recordset.


Parameter Description<br />

anOp An operator. The possible operators are:<br />

=<br />

<<br />

><br />

=<br />

<br />

LIKE<br />

IS NULL<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

IS NOT NULL<br />

If you use one of the last two options for this parameter,<br />

there is no need to supply the aCompVal parameter.<br />

aCompVal The value with which you want to compare the value of a<br />

field in your data agent’s recordset. This value can be a<br />

constant, the value of variable, the value of a URL field, or<br />

the value of a field in a master recordset. In the last case,<br />

aCompValue should be the name of a field in a master<br />

recordset.<br />

aMaster The data agent containing the master recordset. You supply<br />

this value only if your aType parameter is<br />

USER_FILTER_RS_FLD.<br />

aDataType An ADO constant that specifies the data type of the<br />

comparison value. <strong>HAHTsite</strong> uses this argument to determine<br />

how to escape the comparison value. If you don’t supply this<br />

argument, <strong>HAHTsite</strong> treats all comparison values as database<br />

strings; that is, it encloses them in single quotes. If the<br />

comparison value is of a data type that should not be single<br />

quoted, you must supply this argument.<br />

The DataAgent class also contains methods for setting up filtering to be done<br />

on the Application Server. These methods are named setPostFilter and have<br />

the signatures shown below:<br />

public void setPostFilter (int aType, String aField, String anOp,<br />

String aCompVal)<br />

public void setPostFilter (int aType, String aField, String anOp,<br />

String aCompVal, Object aMaster)<br />

209


Chapter 8: Data-Agent <strong>Programming</strong><br />

The parameters to these methods are the same as those used with the<br />

setPreFilter methods.<br />

Handling errors<br />

When a data agent attempts to perform an action and an error occurs,<br />

<strong>HAHTsite</strong> creates an ADO Error object. If several errors occur, several Error<br />

objects are created in a collection.<br />

The DataAgent class provides two methods that you can use to deal with such<br />

errors: getErrorCount and getError:<br />

int getErrorCount()<br />

com.haht.ado.Abstract.Error getError(int index)<br />

The method getErrorCount indicates the number of errors that occurred as a<br />

result of the data agent’s last call to performAction or performInitialAction,<br />

and the getError method returns a reference to one of the Error objects in<br />

the collection. Once you have a reference to an Error object, you can use the<br />

Error class’s getDescription method to get a description of the error.<br />

Typically, you’ll call these error methods from a command handler’s prefailure<br />

event handler and then display your error information on a failure page. For a<br />

complete discussion of how to write this event handler and a complementary<br />

failure page, see “Customizing a failure page” on page 223.<br />

Enabling tracing<br />

In the <strong>IDE</strong> — on the Advanced tab of the Data Agent Properties dialog — you<br />

can turn on a data-agent feature called tracing. If you turn tracing on, <strong>HAHTsite</strong><br />

writes to a log file information about the activity of the data agent. Part of a<br />

sample log file is shown below.<br />

210


Chapter 8: Data-Agent <strong>Programming</strong><br />

----------------------------------------------------------------<br />

Starting trace at Mon Jan 04 12:09:14 CST 1999<br />

DataAgent(da1).setInitialAction( movefirst)<br />

DataAgent(da1).setCommandType: new type=2<br />

DataAgent(da1).setConnectionByName: id=EmployeeConn<br />

DataAgent(da1).performInitialAction: action=movefirst<br />

DataAgent(da1).openPendingConnections(ID): connection is non-null<br />

DataAgent(da1).performInitialAction: opening recordset if nonnull<br />

command.<br />

DataAgent(da1).openRS, opening RS, command=Employees<br />

DataAgent(da1).openRS: Allocating new recordset<br />

DataAgent(da1).openRS: setting Max Records to 2<br />

DataAgent(da1).openRS, after open, EOF=false, BOF=false<br />

DataAgent(da1).run: FieldDataAvailable =true<br />

DataAgent(da1).getFieldString(Last Name)<br />

DataAgent(da1).getFieldString: value='Doe'<br />

DataAgent(da1).getFieldString(First Name)<br />

DataAgent(da1).getFieldString: value='John'<br />

DataAgent(da1).getFieldString(Street Addr)<br />

DataAgent(da1).getFieldString: value='4200 Six Forks Rd'<br />

DataAgent(da1).getFieldString(City)<br />

DataAgent(da1).getFieldString: value='Raleigh'<br />

DataAgent(da1).getFieldString(State)<br />

DataAgent(da1).getFieldString: value='NC'<br />

DataAgent(da1).getFieldString(Zip)<br />

DataAgent(da1).getFieldString: value='27609'<br />

This is an all-or-nothing proposition. Once you turn tracing on, it remains on<br />

for the duration of a session.<br />

To limit the scope of the tracing, you can use the DataAgent class’s setTracing<br />

method:<br />

void setTracing(boolean tracingStatus)<br />

For example, you might want to have tracing turned on only when a particular<br />

command handler is running. To achieve this result, simply turn tracing on at<br />

the beginning of the command handler and off at the end of the command<br />

handler.<br />

211


Chapter 8: Data-Agent <strong>Programming</strong><br />

The structure of a command handler<br />

In database applications, it’s common for a page to include a data agent<br />

followed by a form.<br />

If such a form’s action is Automatic/SELF and the form contains buttons,<br />

<strong>HAHTsite</strong> generates a form handler for the page. This form handler looks like<br />

this:<br />

212


Java<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

public void mapFormToCmd (com.haht.project.Request aRequest,<br />

com.haht.project.Response aResponse)<br />

{<br />

boolean bCmdHandlerCalled = false;<br />

if (aRequest.getURLFieldExists("btnMoveFirst"))<br />

{<br />

Form1_btnMoveFirst_ch(aRequest, aResponse);<br />

bCmdHandlerCalled = true;<br />

}<br />

else if (aRequest.getURLFieldExists("btnMoveNext"))<br />

{<br />

Form1_btnMoveNext_ch(aRequest, aResponse);<br />

bCmdHandlerCalled = true;<br />

}<br />

...<br />

if (! bCmdHandlerCalled)<br />

{<br />

getErrors().add<br />

("Received form command did not invoke a command-handler",<br />

"form-handler");<br />

run (aRequest, aResponse);<br />

}<br />

}<br />

213


Chapter 8: Data-Agent <strong>Programming</strong><br />

HAHTtalk Basic<br />

Public Sub HS_EmployeeInfo_fH<br />

Dim bCmdHandlerCalled As Boolean<br />

Dim thePage As Object, theErrors As Object<br />

Dim aResponse As Object<br />

Set aResponse = Haht.getResponse()<br />

On Error Goto HAHTErrorHandler_fH<br />

bCmdHandlerCalled = False<br />

If (Haht.getRequest().getURLFieldExists("btnMoveFirst")) Then<br />

Form1_btnMoveFirst_ch<br />

bCmdHandlerCalled = True<br />

ElseIf (Haht.getRequest().getURLFieldExists("btnMoveNext")) _<br />

Then<br />

Form1_btnMoveNext_ch<br />

bCmdHandlerCalled = True<br />

...<br />

End If<br />

If (Not bCmdHandlerCalled) Then<br />

Set thePage = Haht.getPage()<br />

Set theErrors = thePage.getErrors()<br />

theErrors.add _<br />

"Received form command didn't invoke a command-handler", _<br />

"form-handler"<br />

Set thePage = Nothing<br />

Set theErrors = Nothing<br />

HS_EmployeeInfo<br />

End If<br />

End Sub<br />

This form handler simply looks at the incoming URL datastream when the<br />

user submits a form from a browser, determines which button was clicked, and<br />

calls a generated command handler that matches that button. In both Java and<br />

HAHTtalk Basic projects, a command handler has a name of the form<br />

buttonName_ch. It’s important to understand the structure of a command<br />

handler because, as you’ll see in the next section, these handlers are designed<br />

to be customized, and you need to understand where you can add your own<br />

code and how you can customize the flow of control.<br />

The tasks that a command handler performs are as follows:<br />

1 Bind the data submitted with the form to fields in the recordset<br />

represented by the data agent that is the target of the command (button).<br />

214


Chapter 8: Data-Agent <strong>Programming</strong><br />

This data binding applies only to Insert and Update commands. (For Find<br />

and Query operations, the criteria to be used for the operation are<br />

established at this point.)<br />

2 Execute the command associated with the button used to submit the<br />

form.<br />

3 If the command succeeds, go to a success page.<br />

4 If the command fails, go to a failure page.<br />

Without going into too much detail, the figure below shows you more<br />

specifically how <strong>HAHTsite</strong> would structure the command handler for a button<br />

named btnUpdate on a form named Form1.<br />

Note - The method names used in this figure are taken from a<br />

Java project; however, a HAHTtalk Basic command handler is<br />

structured the same way.<br />

Entry point<br />

btnUpdate_bindFields() {<br />

// Bind fields from URL to data-agent fields.<br />

}<br />

btnUpdate_execAction() {<br />

// Execute action.<br />

if (action is successful) {<br />

stepVar=PROCEED_DO_SUCCESS_PAGE<br />

}<br />

else {<br />

stepVar=PROCEED_DO_FAILURE_PAGE<br />

}<br />

}<br />

btnUpdate_ch() {<br />

btnUpdate_bindFields()<br />

btunUpdate_execAction()<br />

if (stepVar= =PROCEED_DO_SUCCESS_PAGE) {<br />

run success page<br />

}<br />

if (stepVar= =PROCEED_DO_FAILURE_PAGE) {<br />

run failure page<br />

}<br />

}<br />

215


Chapter 8: Data-Agent <strong>Programming</strong><br />

As you’ll see in the next section, there are four places where you can add code<br />

to change the behavior of such a command handler. It’s also possible to skip<br />

steps in the standard sequence of command-handler actions:<br />

1 Bind data (Insert and Update only)<br />

2 Execute action<br />

3 Run success page<br />

4 Run failure page<br />

The upcoming section, “Modifying a command handler,” explains in detail<br />

how to — and why you would want to — customize your command handlers.<br />

Modifying a command handler<br />

As was mentioned in “The structure of a command handler” on page 212, you<br />

can add code to a command handler in several places. In addition, the code<br />

you add can alter the flow of control in the command handler. This section<br />

contains the following subsections:<br />

216<br />

“Where to add code to a command handler” on page 216<br />

“Examples of adding code to a command handler” on page 217<br />

“Changing the flow of control in a command handler” on page 225<br />

“Example of changing the flow of control” on page 227<br />

Where to add code to a command handler<br />

In each command handler in your application, there are either three or four<br />

places where you can add code. Command handlers for Insert and Update<br />

buttons have four such places, and most other command handlers have three.<br />

Here are the locations:<br />

Just before the command handler binds data from a URL to data-agent<br />

fields (Insert and Update command handlers only). To add code that will<br />

be executed at this point, you add statements to the generated function<br />

buttonName_onBind.<br />

Just before the command handler executes the command associated with<br />

the button used to submit the form. To add code that will be executed at<br />

this point, you add statements to the generated function<br />

buttonName_onExec.


Chapter 8: Data-Agent <strong>Programming</strong><br />

Just before the command handler runs its success page. To add code that<br />

will be executed at this point, you add statements to the generated<br />

function buttonName_onSuccess.<br />

Just before the command handler runs its failure page. To add code that<br />

will be executed at this point, you add statements to the generated<br />

function buttonName_onFail.<br />

When you look at the Server-side Code view of your page, you’ll see these<br />

empty functions just above the related command handler.<br />

You customize these functions by typing in the white areas just below the<br />

method or subroutine names. Any code you type in the white areas of the<br />

screen will be retained when the code for your page is regenerated.<br />

This will all probably make more sense when you look at an example or two<br />

of why you might add code to a command handler. You can find such<br />

examples in the next section, “Examples of adding code to a command<br />

handler.”<br />

Examples of adding code to a command handler<br />

This section presents several examples of how you can add functionality to a<br />

generated command handler:<br />

217


Chapter 8: Data-Agent <strong>Programming</strong><br />

218<br />

The first example illustrates how to change a form-field value between<br />

the time the value is submitted and the time the command handler binds<br />

that value to a data agent.<br />

The second example is a variation of an example used in Chapter 6,<br />

“Forms-Related <strong>Programming</strong>”: it explains how to insert a Binary Large<br />

Object (BLOB) in a database using a command handler’s prebind routine.<br />

The third example explains how to use a prefailure routine to customize<br />

a failure page.<br />

Altering a form-field value before binding<br />

When a user clicks an Insert or Update button on a form and a command<br />

handler is called, the command handler normally binds the data submitted to<br />

fields in the button’s target data agent. However, you have a chance to<br />

intercept this data, and to change it in any way you like, before the data is<br />

bound to data-agent fields. You do this by adding code to your command<br />

handler’s prebind routine: buttonName_onBind.<br />

For example, let’s say that you have a project that:<br />

reads personal data submitted by potential subscribers from a temporary<br />

database<br />

allows you to insert subscriber records into a permanent database


Chapter 8: Data-Agent <strong>Programming</strong><br />

If the subscriber did not supply a country name, you want to bind the value<br />

“United States” to the data agent’s Country field before the normal binding<br />

occurs. (Normal binding will not affect the Country field because the Country<br />

text box is empty.). To accomplish this, you can add code to the Insert<br />

command handler’s prebind function. See the code samples below.<br />

Java<br />

protected void btnInsert_onBind<br />

(com.haht.project.Request aRequest,<br />

com.haht.project.Response aResponse,<br />

com.haht.project.datamanager.DMHandlerInfo aHandlerInfo)<br />

{<br />

// Insert code to run before binding data to the command btnInsert.<br />

if (aRequest.getURLField("txtCountry").equals(""))<br />

{<br />

da1.setFieldString("Country", "United States");<br />

}<br />

}<br />

HAHTtalk Basic<br />

Private Sub btnInsert_onBind(aHandlerInfo As Object)<br />

' Insert code to run before binding data to the command btnInsert.<br />

If (Haht.getRequest().getURLField("txtCountry") = "") Then<br />

dsSubscriberInfo.setFieldString "Country", "United States"<br />

End If<br />

End Sub<br />

This is a simple example, but it illustrates how to get a value submitted with a<br />

form before the form’s values are bound to a data agent, and how to bind<br />

values to a data agent. For a lengthier example of how to customize a<br />

command handler’s prebind routine, see “Inserting a BLOB into a database”<br />

below.<br />

Inserting a BLOB into a database<br />

This section presents another example of how you might customize a<br />

command handler’s prebind method. Suppose you have a form that contains<br />

a File Upload form field. When a user runs your application, he or she will<br />

enter the path to an image file in the File Upload text field. When the user<br />

clicks the Insert button, you want to take this pathname, open the image file,<br />

and write the contents of the file to a BLOB field in your database. (The record<br />

219


Chapter 8: Data-Agent <strong>Programming</strong><br />

containing the image will also contain a picture name that you can use to<br />

identify the image.)<br />

Since <strong>HAHTsite</strong> doesn’t generate code for inserting a large binary object into a<br />

database, you must add code similar to the following to a command handler<br />

to insert this object in your database.<br />

220


Java<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

protected void btnInsert_onBind(com.haht.project.Request<br />

aRequest, com.haht.project.Response aResponse,<br />

com.haht.project.datamanager.DMHandlerInfo aHandlerInfo)<br />

{<br />

//<br />

// Get filename of uploaded image, open it, and prepare to<br />

// appendChunk it into the recordset field<br />

//<br />

String sPictureFileName = Haht.getApplication().<br />

getUserRoot() + '/' + aRequest.getURLAttachment<br />

("mfuPicture");<br />

java.io.File pictureFile = new java.io.File<br />

(sPictureFileName);<br />

FileInputStream pictureStream;<br />

try<br />

{<br />

pictureStream = new FileInputStream (pictureFile);<br />

}<br />

catch (java.io.FileNotFoundException e)<br />

{<br />

aRequest.setUserProp("ErrorMessage",<br />

"Uploaded file not found!");<br />

aHandlerInfo.setProceedAction<br />

(DMConstants.PROCEED_DO_FAILURE_PAGE);<br />

return;<br />

}<br />

// Recordset has done addNew, so we have a Field to put<br />

// picture in. Get picture field for appending data into<br />

//<br />

Field pictureFld = daNameAndPict.getRecordset().<br />

getField("Picture");<br />

Field nameFld = daNameAndPict.getRecordset().<br />

getField("Name");<br />

nameFld.setString(aRequest.getURLField("txtName"));<br />

221


Chapter 8: Data-Agent <strong>Programming</strong><br />

Java<br />

222<br />

//<br />

// Allocate a buffer and read until we're done<br />

//<br />

byte [] pictureBuf = new byte[BUFSIZE];<br />

int nBytesRead;<br />

int nBytesTotal = 0;<br />

do<br />

{<br />

try<br />

{<br />

nBytesRead = pictureStream.read (pictureBuf);<br />

nBytesTotal += nBytesRead;<br />

if (nBytesRead > 0)<br />

pictureFld.appendChunk (pictureBuf, nBytesRead);<br />

}<br />

catch (java.io.IOException e)<br />

{<br />

aRequest.setUserProp("ErrorMessage",<br />

"Error occurred while reading/writing image");<br />

daNameAndPict.getRecordset().cancelUpdate();<br />

aHandlerInfo.setProceedAction<br />

(DMConstants.PROCEED_DO_FAILURE_PAGE);<br />

try<br />

{<br />

pictureStream.close();<br />

}<br />

catch (java.io.IOException e2)<br />

{<br />

}<br />

return;<br />

}<br />

}<br />

while (nBytesRead > 0);


Java<br />

}<br />

//<br />

// Close file, continue<br />

//<br />

try<br />

{<br />

pictureStream.close();<br />

}<br />

catch (java.io.IOException e)<br />

{<br />

}<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

Note - Appendix C, “Code Examples,” presents code you could<br />

use in a HAHTtalk Basic project to perform this same task. See<br />

the section “Modifying a command handler” on page 370.<br />

If you’ve read Chapter 6, “Forms-Related <strong>Programming</strong>,”, you’ll recognize this<br />

example as a variation of an earlier example that illustrated how to write a<br />

BLOB to a database by calling a subroutine as the action of a form. Note that<br />

several steps taken in the earlier example are not necessary in this one,<br />

including:<br />

opening a connection<br />

opening a recordset<br />

adding a new record to the recordset<br />

Because this section’s example code is being called from an Insert button’s<br />

command handler, these actions have already been performed at the time the<br />

code is called.<br />

Customizing a failure page<br />

Suppose you implemented the example in “Inserting a BLOB into a database”<br />

on page 219, which uses a custom Insert command handler to insert a BLOB<br />

in a database, and the insertion failed. You could use the <strong>IDE</strong> to customize the<br />

Insert button so that an error page would be run if the insertion failed, but<br />

how would you write some custom content to that error page? This section<br />

tells you how.<br />

The simple answer is that you can add code to the Insert button’s prefailure<br />

routine to make customizing the failure page possible. See the sample code<br />

below.<br />

223


Chapter 8: Data-Agent <strong>Programming</strong><br />

Java<br />

protected void btnInsert_onFail<br />

(com.haht.project.Request aRequest,<br />

com.haht.project.Response aResponse,<br />

com.haht.project.datamanager.DMHandlerInfo aHandlerInfo)<br />

{<br />

// Insert code to run after the btnInsert command fails.<br />

aRequest.setUserProp("ErrorMessage","Insertion of picture "<br />

+ aRequest.getURLField("txtName") + " failed.");<br />

}<br />

224<br />

Note - In a HAHTtalk Basic project, you could use a global<br />

variable to hold the error message.<br />

This code uses the setUserProp method of the Request object passed to the<br />

method to set a user property associated with the Request object. The two<br />

arguments to this method are the name of a user property (which is user<br />

defined) and the value of that property. Since this Request object is passed to<br />

the failure page’s run method, that run method can use the Request object’s<br />

getUserProp method to get this message in order to display it.<br />

The Normal view of a sample failure page is shown below.<br />

Java<br />

// Check to see if the message was passed in<br />

// Request.UserProp("Message") or ("ErrorMessage")<br />

if (aRequest.getUserProp("ErrorMessage") != null)<br />

setErrorMessage ((String) aRequest.getUserProp<br />

("ErrorMessage"));<br />

else if (aRequest.getUserProp("Message") != null)<br />

setMessage ((String) aRequest.getUserProp("Message"));<br />

// Display success or error message here, using property set by<br />

// caller.<br />

out.print ("");<br />

if (mMsgIsError)<br />

out.print("sMsg");<br />

else<br />

out.print("sMsg");<br />

out.print("");<br />

sMsg = "";<br />

mMsgIsError = false;


Chapter 8: Data-Agent <strong>Programming</strong><br />

This page checks the Request object passed to it for an error message<br />

(“ErrorMessage”) or a success message (“Message”). If the user property<br />

“ErrorMessage” has been set, the page gets the value of that property and uses<br />

the user-defined method setErrorMessage to set the value of the user-defined<br />

variable sMsg. This method and member variable are defined in the Server-side<br />

Code view of the failure page.<br />

Java<br />

// private methods<br />

/**<br />

* Set displayed message text, and mark for display as non-error<br />

**/<br />

public void setMessage(String aMsg)<br />

{<br />

sMsg = aMsg;<br />

mMsgIsError = false;<br />

}<br />

/**<br />

* Set displayed message text, and mark for display as error<br />

**/<br />

public void setErrorMessage (String aMsg)<br />

{<br />

sMsg = aMsg;<br />

mMsgIsError = true;<br />

}<br />

...<br />

// private member variables<br />

private String sMsg = "";<br />

private boolean mMsgIsError = false;<br />

This example requires you to write a little code in three different places, but<br />

should be a very useful example if you’re customizing your application’s<br />

command handlers.<br />

Changing the flow of control in a command handler<br />

In addition to adding code to a command handler, you can change the flow<br />

of control in the command handler. The normal flow of control is shown<br />

below.<br />

225


Chapter 8: Data-Agent <strong>Programming</strong><br />

You can easily change this flow, however, by setting a constant in a command<br />

handler’s prebind, preexecute, presuccess, or prefailure routine. Here’s how the<br />

mechanism works.<br />

When a command handler calls one of the methods or subroutines shown<br />

below, it passes to that subroutine or method an object of type DMHandlerInfo:<br />

226<br />

ButtonName_onBind<br />

ButtonName_onExec<br />

ButtonName_onSuccess<br />

ButtonName_onFail<br />

One of this object’s member variables, mProceed, stores a constant that<br />

indicates what action the command handler should take after the user-defined<br />

routine exits. This constant is preset to PROCEED_DO_NEXT_STEP when the<br />

user-defined routine is called. The constants you can use in setting this action<br />

are listed in the table below.<br />

Constant Explanation<br />

PROCEED_DO_NEXT_STEP Continue with the next step. For example, if the<br />

handler-information object’s mProceed variable<br />

is set to PROCEED_DO_NEXT_STEP in a prebind<br />

routine, the next step to be performed will be<br />

the binding step.


Constant Explanation<br />

Chapter 8: Data-Agent <strong>Programming</strong><br />

PROCEED_SKIP_NEXT_STEP Skip the next step. For example, if the<br />

handler-information object’s mProceed variable<br />

is set to PROCEED_SKIP_NEXT_STEP in a<br />

prebind routine, the next step to be performed<br />

will be the execute-action step.<br />

PROCEED_DO_SUCCESS_PAGE Go directly to the success routine.<br />

PROCEED_DO_FAILURE_PAGE Go directly to the failure routine.<br />

Note - In HAHTtalk Basic project, you should prepend<br />

DMConstants_ to the names of these constants.<br />

The upcoming section “Example of changing the flow of control,” illustrates<br />

how to set the mProceed variable to one of these constants.<br />

Example of changing the flow of control<br />

Here’s a simple example of how to change the flow of control in a command<br />

handler. Say that you have a prebind routine, like the one discussed in<br />

“Customizing a failure page” on page 223, that records error information in a<br />

user property of a Request object if an error occurs. For instance, the prebind<br />

routine in that example can fail if the routine is unable to find the file it is<br />

supposed to read. At this point, you should not only record your error<br />

information, but tell the command handler to go directly to its failure routine.<br />

The code below illustrates how to do this.<br />

Java<br />

try<br />

{<br />

pictureStream = new FileInputStream (pictureFile);<br />

}<br />

catch (java.io.FileNotFoundException e)<br />

{<br />

aRequest.setUserProp("ErrorMessage","File not found!");<br />

aHandlerInfo.setProceedAction<br />

(DMConstants.PROCEED_DO_FAILURE_PAGE);<br />

return;<br />

}<br />

227


Chapter 8: Data-Agent <strong>Programming</strong><br />

Note that the variable mProceed is set using the DMHandlerInfo object’s<br />

setProceedAction method.<br />

228


<strong>Programming</strong> with<br />

the Connection<br />

Manager<br />

9<br />

The DMConnectionManager class ...............................................................230<br />

Opening a connection..................................................................................230<br />

Opening a shared connection.................................................................231<br />

Opening a private connection ................................................................232<br />

Closing a connection....................................................................................232<br />

Connections in HAHTtalk Basic projects.....................................................233<br />

229


Chapter 9: <strong>Programming</strong> with the Connection Manager<br />

The DMConnectionManager class<br />

The <strong>HAHTsite</strong> Server Object Model includes a connection-manager class<br />

named DMConnectionManager. This class includes methods that enable you to<br />

open or obtain a reference to a shared connection and to open a private<br />

connection. Once you obtain a Connection, you can use it in your ADO<br />

programming as you normally would. For example, you might instantiate a<br />

Recordset and then set the recordset’s active connection using your<br />

Connection object.<br />

A shared connection can be opened by a session the first time the connection<br />

is needed and then be used for the duration of the session by both your code<br />

and any number of data agents. Sharing a connection improves an<br />

application’s performance because you avoid the overhead of opening<br />

multiple connections. Some applications may require or prefer to use private<br />

connections, however. For example, an application that performs transactions<br />

might choose to conduct those transactions over a private connection.<br />

You might be thinking, “ADO allows me to create connections of different<br />

scopes, so why would I use the connection manager?” There are two main<br />

reasons:<br />

230<br />

The management of connection strings is simplified. If you need to<br />

change a connection string, you can make the change in one place — the<br />

definition of the connection — and all of the code pages that might open<br />

the connection will know about the new connection string.<br />

You can share a connection with one or more data agents. A data agent<br />

uses the DMConnectionManager class to open a shared connection to a<br />

data source, and you can use a method of this class to get a reference to<br />

the same connection.<br />

The remainder of this chapter discusses the procedures for opening and<br />

closing shared and private connections using the DMConnectionManager class.<br />

Opening a connection<br />

The general procedure for opening a connection or getting a reference to a<br />

shared connection is as follows:<br />

1 Create an ADO connection using the <strong>HAHTsite</strong> <strong>IDE</strong>. The procedure for<br />

creating this connection is covered in Chapter 15, “Connecting to a Data<br />

Source,” in the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>.


Chapter 9: <strong>Programming</strong> with the Connection Manager<br />

2 If the user will be getting a reference to a shared connection and the<br />

connection’s data source requires that the user log in, set up a login page<br />

that user must visit before getting the shared connection. The name of<br />

this login page is an attribute of the connection.<br />

3 Call the appropriate SOM method to open or get a reference to the<br />

connection.<br />

The subsections below explain in detail how to call the proper method to<br />

establish a shared or private connection.<br />

Opening a shared connection<br />

Generally, you get a reference to a shared connection using the method<br />

getSharedConnectionByName:<br />

com.haht.ado.Abstract.Connection getSharedConnectionByName<br />

(String connName)<br />

The single argument to this method is the name of an ADO connection<br />

created in the <strong>IDE</strong>.<br />

Note - You can also get a reference to a shared connection<br />

using the method getSharedConnectionByID. Using this<br />

method, however, makes your code a little harder to read since<br />

it requires the project ID of a connection as its argument. This<br />

method is primarily for use by data agents.<br />

Before you call the getSharedConnectionByName method, you should<br />

determine whether the connection’s data source requires that users log in. If<br />

users must log in, your application must include a data agent that establishes<br />

the shared connection before your code attempts to get a reference to that<br />

connection. Also, the definition of the connection itself must include the<br />

name of a login page that will enable users to log in to the data source.<br />

The call to getSharedConnectionByName will return null if:<br />

the connection required a login and the user has not logged in yet<br />

a connection of the name you supplied does not exist<br />

Java programmers: The getSharedConnectionByName method can throw two<br />

exceptions: SharedConnectionUnpreparedException and<br />

UnknownConnectionException. This means that you should make this call<br />

using the try/catch mechanism. The first exception indicates that the<br />

connection’s data source requires a login and that the user has not logged in,<br />

and the second exception indicates that the application does not know of a<br />

connection with the name you specified.<br />

231


Chapter 9: <strong>Programming</strong> with the Connection Manager<br />

Opening a private connection<br />

Generally, you open a private connection using the method<br />

openPrivateConnectionByName:<br />

232<br />

com.haht.ado.Abstract.Connection openPrivateConnectionByName<br />

(String connName, String userID, String password)<br />

The three arguments to this method are:<br />

the name of an ADO connection created in the <strong>IDE</strong><br />

a user ID to be used in logging in to the data source<br />

a password to be used in logging in to the data source<br />

Use empty strings for the second and third arguments if the connection’s data<br />

source does not require that users log in.<br />

Note - You can also open a private connection using the<br />

method openPrivateConnectionByID. Using this method,<br />

however, makes your code a little harder to read since it<br />

requires the project ID of a connection as its argument. This<br />

method is primarily for use by data agents.<br />

The call to openPrivateConnectionByName will return null if:<br />

the method is unable to log in to the connection’s data source<br />

a connection of the name you supplied does not exist<br />

Java programmers: The openPrivateConnectionByName method can throw<br />

two exceptions: PrivateConnectionUnpreparedException and<br />

UnknownConnectionException. This means that you should make this call<br />

using the try/catch mechanism. The first exception indicates that the<br />

connection’s data source requires a login and that the method was unable to<br />

log the user in, and the second exception indicates that the application does<br />

not know of a connection with the name you specified.<br />

Closing a connection<br />

Because you might want to open and close a private connection repeatedly<br />

during a session — for example, you might want to open and close the<br />

connection each time you access a data source — <strong>HAHTsite</strong> provides a method<br />

that enables you to close a private connection explicitly:<br />

void closePrivateConnection(com.haht.ado.Abstract.Connection)


Chapter 9: <strong>Programming</strong> with the Connection Manager<br />

If you don’t call this method, <strong>HAHTsite</strong> closes all private connections when a<br />

session ends.<br />

Similarly, <strong>HAHTsite</strong> closes all shared connections automatically when a<br />

session ends.<br />

Connections in HAHTtalk Basic projects<br />

Because most HAHTtalk Basic programmers would prefer to work with<br />

connection objects of type ADODB.Connection rather than objects of type<br />

com.haht.ado.Connection, <strong>HAHTsite</strong> includes four Basic functions that<br />

return connections:<br />

getSharedConnectionByID<br />

getSharedConnectionByName<br />

openPrivateConnectionByID<br />

openPrivateConnectionByName<br />

These functions serve the same general purpose as their Server Object Model<br />

counterparts, but return connections of type ADODB.Connection.<br />

In addition, the class ADODB.Connection defines a closePrivateConnection<br />

method that you can use to close private connections.<br />

233


Chapter 9: <strong>Programming</strong> with the Connection Manager<br />

234


Working with<br />

Client-side Scripts<br />

10<br />

Introduction to client-side scripts................................................................236<br />

Types of client-side scripts............................................................................238<br />

Choosing a scripting language.....................................................................238<br />

Client-side scripts and the HTML editor .....................................................240<br />

Writing in-line scripts...................................................................................243<br />

Writing script functions ...............................................................................244<br />

About event handlers ...................................................................................247<br />

Browser compatibility issues ........................................................................249<br />

About Dynamic HTML .................................................................................252<br />

Scripts with server-side expressions .............................................................257<br />

235


Chapter 10: Working with Client-side Scripts<br />

Introduction to client-side scripts<br />

Client-side scripts enable you to include executable content in Web pages,<br />

providing dynamically created HTML content, interaction with the user, and<br />

control of the Web browser. You can use client-side scripts in a variety of ways.<br />

Some of the common uses are:<br />

236<br />

to validate form fields before submitting a form<br />

to animate menus to indicate mouseovers<br />

to display a special picture, depending on the user’s history<br />

to enforce an ordered navigation of a set of Web pages<br />

to interact with and control the execution of applets<br />

As a simple example of what you can do with client-side scripts, try entering<br />

the following text into a page using the Normal view of the HTML editor:<br />

The Fibonacci sequence<br />

document.write("1, 1");<br />

first = 1; second = 1;<br />

for(i=0; i


Chapter 10: Working with Client-side Scripts<br />

The JavaScript code that you place on a Web page is interpreted by the browser,<br />

which dynamically generates the HTML content that is displayed. Using<br />

client-side scripts allows you to run programs on a viewer’s computer within<br />

the Web browser.<br />

The <strong>HAHTsite</strong> <strong>IDE</strong>/IP includes a rich script-aware HTML editor for writing,<br />

testing, and debugging client-side scripts in a Web page. The HTML editor<br />

supports both JavaScript and VBScript as scripting languages. In addition, the<br />

Document Object Models (DOM) for the major Web browsers are incorporated<br />

into the editor, allowing drag-and-drop insertion of objects, properties, and<br />

methods from the DOM directly into the scripts. This is a very powerful<br />

feature that simplifies the complex task of writing scripts using objects in the<br />

browser’s DOM. Perhaps the most difficult task associated with writing<br />

client-side scripts is dealing with incompatibilities in the different versions of<br />

Netscape Navigator and Internet Explorer. The HTML editor filters the DOM<br />

presented in the editor, supporting writing scripts for targeted browsers.<br />

This chapter explains how to use the HTML editor to create Web pages with<br />

scripts. The reader is assumed to understand JavaScript or VBScript and the<br />

concepts involved in using the DOM for the target browser. Because of the<br />

predominate use of JavaScript, the examples in this chapter use JavaScript.<br />

However, the use of the HTML editor is the same, regardless of the scripting<br />

language.<br />

237


Chapter 10: Working with Client-side Scripts<br />

Types of client-side scripts<br />

When you’re using its Normal view, the <strong>IDE</strong>’s HTML editor acts as a WYSIWYG<br />

Web page editor. When used in this mode, the editor has features that enable<br />

you to add client-side scripts to a Web page. In addition, the editor has a Client<br />

Scripts view that you can use to create event handlers and functions for your<br />

scripts.<br />

The HTML editor supports three basic types of scripts in a page:<br />

238<br />

in-line scripts. The HTML editor allows you to type script statements<br />

directly into a Web page, at the place that the browser should execute the<br />

script. These in-line scripts appear in the Normal view of the HTML<br />

editor and are marked with a special font. Writing in-line scripts is<br />

explained in “Writing in-line scripts” on page 243.<br />

page-scope functions. You can write script functions to perform common<br />

functions or to improve readability. Page-scope functions are created in<br />

the Client Scripts view of the HTML editor and are available to in-line<br />

scripts or event handlers anywhere on the page. These functions are not<br />

visible in the Normal view. If you put the bulk of your scripting code into<br />

functions, Web pages with in-line code maintain a more WYSIWYG look<br />

because they have fewer in-line statements. Creating page-scope<br />

functions is discussed in “Writing script functions” on page 244.<br />

event handlers. The Client Scripts view of the HTML editor provides a<br />

convenient way to write event handlers associated with an event for an<br />

object on the page. The scripts for each event are created and edited in<br />

the Client Scripts view, and are not shown on the page in the Normal<br />

view. More information about writing event handlers is provided in<br />

“Scripting event handlers” on page 247.<br />

Choosing a scripting language<br />

The HTML editor supports the use of both JavaScript and VBScript in<br />

client-side scripts. Both languages provide basic control flow and support for<br />

creating Web pages that are customized at display time. However, JavaScript is<br />

recognized by more browsers and is more widely used than VBScript.<br />

The most important difference between JavaScript and VBScript is browser<br />

support. JavaScript is supported by Navigator and IE. VBScript is only<br />

supported by IE. If you use VBScript, only clients that are using IE will be able<br />

to correctly view your pages with scripts. Scripting-language and


Chapter 10: Working with Client-side Scripts<br />

browser-compatibility issues are discussed further in “Browser compatibility<br />

issues” on page 249.<br />

You can choose to use either JavaScript or VBScript as the current scripting<br />

language. If you intend to use only one language for all your scripts, you can<br />

make this choice once using an HTML editor option, and all the scripts that<br />

you write will be generated in that language. If you need to write in both<br />

JavaScript and VBScript, you must change this setting each time you edit a<br />

different type of script.<br />

To select the current scripting language<br />

1 From the main menu, select Tools > Options....<br />

The Options dialog appears.<br />

2 Select the Client Scripts tab.<br />

3 From the Default Client Script LANGUAGE combo box, select either<br />

JavaScript or VBScript. You can also type an entry into this field to specify<br />

a different scripting language or a specific version of a language, such as<br />

JavaScript1.2.<br />

4 Click OK.<br />

The script language you select will be used by the HTML editor for any new<br />

scripts that are created.<br />

239


Chapter 10: Working with Client-side Scripts<br />

Client-side scripts and the HTML editor<br />

When an HTML page is opened in a project, it is first displayed using the<br />

Normal view of the HTML editor. The Normal view displays an editing<br />

window with a WYSIWYG representation of the page. While you’re in this<br />

view, client-side scripts appear as in-line code, or as icons, depending on the<br />

setting of the View Code as Icon option.<br />

When you switch to the Client Scripts view, the DOM Objects tab is selected<br />

in the Project window. The DOM Objects panel contains a graph<br />

representation of the client-side script tags and client-side objects. The objects<br />

and tags are placed in a hierarchy represented by folders. The editing window<br />

contains the currently selected script. The DOM Objects window only displays<br />

the object model when the HTML editor is in the Client Scripts view.<br />

240<br />

Note - There are no real folders corresponding to this<br />

representation. The folders are only used as a convenient<br />

mechanism for presenting the tags and objects in an<br />

easy-to-use way.<br />

The Client-Side Script Tags folder lists both functions and in-line scripts<br />

contained in the page. The first script in the list of Client-Side Script Tags is<br />

used to create page-scope functions. Page-scope functions are discussed in<br />

“Writing script functions” on page 244. Any other functions or in-line scripts<br />

in a page will also appear as script elements in this list.<br />

The script that is currently being edited is signified by a red highlight box<br />

around the script’s icon. In the illustration above, the first script item, which<br />

contains the page scope functions, is being edited. When you switch between<br />

Normal and Client Scripts view, if possible, the HTML editor maintains the<br />

focus on the item currently being edited. For instance, if you are editing (or<br />

place the cursor in) an in-line function while in Normal view, then switch to<br />

the Client Scripts view, the script containing that function will be<br />

automatically selected for editing.


Chapter 10: Working with Client-side Scripts<br />

Tip - If you are not sure which in-line script or function a<br />

particular script in the list of Client-Side Script Tags represents,<br />

select the script for editing and switch back to the Normal view<br />

of the editor. The script you have selected will be the currently<br />

selected object.<br />

Browsing the object model<br />

Client-Side DOM Objects represent objects in the browser object model. The<br />

Client-Side DOM Objects graph has two root level objects, window and<br />

navigator. The window object represents the Web browser window or a frame<br />

within a window. All page-scope variables belong to this object. The document<br />

object, contained in the window object, represents the document associated<br />

with the window. By traversing the hierarchy, you can see the objects, events,<br />

properties, and methods that define the object model.<br />

The following types of items appear in the DOM Objects panel:<br />

icon item<br />

objects - the forms, buttons, text boxes, or even the document<br />

arrays - items of the same type (e.g., scripts, forms, frames, images)<br />

properties - object attributes<br />

functions - object functions<br />

events - event handler scripts can be associated with these events<br />

In addition to icons representing the type of item, you will notice that some<br />

items have a browser indicator on the icon. These additional indicators mark<br />

items that are only defined in Navigator 4.x or IE 4.x, or both. The browser<br />

indicator may appear on icons for objects, properties, functions, and events.<br />

No browser symbol on the item indicates that the feature is supported by all<br />

of the browsers (or at least the third generation browsers.)<br />

icon Browsers supported<br />

Most browsers support these objects, properties, functions, or events.<br />

Navigator 4.x only<br />

241


Chapter 10: Working with Client-side Scripts<br />

icon Browsers supported<br />

242<br />

IE 4.x only<br />

Navigator 4.x and IE 4.x only (not supported in earlier versions of the<br />

browsers)<br />

Note - When you’re browsing the DOM Object panel, the<br />

script currently being edited may not always be visible.<br />

Remember that the icon for the script being edited in the<br />

editing window is indicated by a red highlight box.<br />

Configuring the Client Scripts view<br />

The DOM Objects window of the Client Scripts view of the editor can be<br />

configured to display as much or as little information as you would like to see.<br />

Instead of displaying all of the objects supported by all of the browsers, you<br />

can display just the objects supported by specific browsers.<br />

To configure the DOM Objects panel<br />

1 From the main toolbar, select Tools > Options....<br />

The Options dialog appears.<br />

2 Click on the Client Scripts panel of the Options dialog.<br />

3 Configure the panel to display the information you wish to see.


Field Description<br />

Display Properties and<br />

Methods<br />

Default Client Script<br />

LANGUAGE<br />

Display Objects for<br />

Browsers<br />

4 Click OK.<br />

Chapter 10: Working with Client-side Scripts<br />

Note - Selecting a particular browser’s object model to be<br />

displayed in the Client Scripts view does not prevent you from<br />

writing scripts that are incompatible with the browser. This<br />

selection only affects the object model that is shown. There is<br />

no testing for browser compatibility in the editor.<br />

Writing in-line scripts<br />

You can add scripts in-line on a page while you’re in the Normal view. These<br />

scripts will be visible in the HTML editor, but will not be visible on the page<br />

when viewed by a browser. Script statements and functions are executed in<br />

order as they are read from the page by the browser.<br />

To insert script statements into a page<br />

1 With the page open in the Normal view, place the cursor at the location at<br />

which you want to enter the script.<br />

2 Type in the script statements.<br />

If checked, show the events, properties, and<br />

functions associated with each object. If not checked,<br />

only show the events associated with an object.<br />

Select the scripting language from the drop-down<br />

menu. New event handlers or scripts that you add<br />

will use this value.<br />

Select the browser for which to show the object<br />

model from the drop-down menu. displays all<br />

objects and object features supported by any browser<br />

in this list. Selecting a browser from this list filters<br />

the object model so that only objects and features<br />

supported by that browser appear in the DOM<br />

Objects panel.<br />

Note - The <strong>IDE</strong>/IP does not check for errors in any scripts.<br />

Errors in scripts will not be seen until the page is displayed in<br />

a browser, so it is a good idea to test your pages thoroughly.<br />

243


Chapter 10: Working with Client-side Scripts<br />

3 Select the script statements.<br />

4 Click the Client-side script button on the Character Styles toolbar.<br />

244<br />

The script appears in a special font and color.<br />

The figure below shows a simple JavaScript example that conditionally<br />

displays information in the Web page based on the month.<br />

When a browser receives this page, it interprets the JavaScript code and, based<br />

on the current month, replaces the JavaScript code with the appropriate HTML<br />

output.<br />

Tip - If you want to hide in-line scripts, select View > Code As<br />

Icon from the main toolbar. The scripts on the page will be<br />

replaced with the client-side script icon .<br />

Once you’ve created an in-line script in the Normal view, you can edit it in the<br />

Client Scripts view of the HTML editor. Editing scripts in the Client Scripts<br />

view gives you access to the object model displayed on the DOM Objects tab<br />

in the Projects window.<br />

Writing script functions<br />

You use the Client Scripts view of the HTML editor to create script functions<br />

with page scope. Functions are subroutines that can be called either by in-line<br />

script statements on the page or from event-handler scripts. The visibility or<br />

scope of a function is determined by its position on a page. A function is<br />

visible to any script statement that occurs after the function definition on the<br />

page. A function has page scope if it is visible to statements anywhere on the<br />

page. The HTML editor defines a General script for each page containing<br />

functions that have page scope.


Chapter 10: Working with Client-side Scripts<br />

A common practice is to place code that is called from multiple places on a<br />

page into a function. Functions may also be used to keep the number of in-line<br />

statements inserted into a page small. This will make the page more readable.<br />

To insert a script function into a page<br />

1 Open the page and select View > Client Scripts from the main toolbar.<br />

Shortcut - Use the buttons on the Change Active View toolbar<br />

to switch between views in the HTML editor.<br />

2 Click on the script icon to select the first script in the Client-Side Script<br />

Tags list.<br />

A script for page scope functions appears in the editing window. If the<br />

page has scripts in the tag, this is the first script that appears in the<br />

tag. A page can have multiple scripts in the tag. Each script<br />

appears as a separate icon under the scripts folder. If the tag does<br />

not contain any scripts, a General script is generated. The first line in the<br />

General script initially contains the comment line:<br />

// General SCRIPT tag in HEAD tag. Put page scope client script<br />

// functions here.<br />

3 Type in script functions and variables definitions that require page scope.<br />

To try this out, create the print_todays_date function shown below:<br />

function print_todays_date()<br />

{<br />

var d = new Date();<br />

document.write(d.toLocaleString);<br />

}<br />

4 Switch back to Normal view and insert a call to the function on the page<br />

where you want the date to appear.<br />

print_todays_date();<br />

5 Select the line containing the function call and click on the Client-side<br />

script button.<br />

245


Chapter 10: Working with Client-side Scripts<br />

246<br />

When you browse the page, the date will appear in place of the function<br />

call.<br />

You can also insert functions in-line in a page. These functions will only be<br />

visible to scripts occurring after the function definition on the page. These<br />

functions will be visible in the Normal view and also in the DOM Objects<br />

window in the Client Scripts view of the HTML editor.<br />

If a function is used by multiple pages, you might prefer to keep the function<br />

in a separate file in the project and include it in each script that uses the<br />

function. A function that pops up a dialog to ask “Are you sure?” might be<br />

used on several different pages. If a script includes this function, it only has to<br />

be changed in one place if you what to change this popup.<br />

Shortcut - While editing the page in Normal view,<br />

drag-and-drop the script file from the Project window onto the<br />

page. This will insert a reference to the script file as a<br />

page-scope function.<br />

HTML tags for client-side scripts<br />

The HTML editor generates the HTML tags that contain the scripts<br />

in the page. If you look at the page in HTML Tags view, you will see individual<br />

script tags for each in-line function and set of statements on your page. When<br />

script statements or functions are inserted in-line using the Normal view, the<br />

tags are generated to include the statements at the location in the<br />

body of the HTML where the code appears. Page scope functions, including<br />

references to script files containing functions, are inserted in the tag.<br />

These scripts are placed in the tag so that the functions are defined


Chapter 10: Working with Client-side Scripts<br />

before any other scripts on the page. Event-handler scripts are inserted in the<br />

tag for the object associated with the event.<br />

Although the HTML editor provides a very flexible way to insert client-side<br />

scripts into a HTML page, there may be occasions where you will need to edit<br />

the HTML tags for the scripts directly. The HTML Tags view of the HTML editor<br />

provides a convenient way to do this.<br />

About event handlers<br />

Most browsers in use today have defined a set of objects that represent the<br />

browser and the page that it displays. These objects are commonly referred to<br />

as the Document Object Model or DOM. (The browser object model is<br />

discussed more fully in “The browser object model” on page 250.) The user<br />

interacts with these browser objects by performing actions such as moving a<br />

cursor over a link, pressing a button in a form, clicking in a frame, or loading<br />

a document in a window. These actions are called events. By creating scripts<br />

that run when one of these events occur, you can enable user interaction with<br />

the page and control some browser behavior.<br />

An event handler is a script that the browser invokes when a particular event,<br />

such as a mouseover, occurs. For instance, you could write a script that<br />

displays a different picture when the mouse is held over a picture. The HTML<br />

editor provides an easy way to generate these scripts by allowing you to browse<br />

a hierarchical representation of all of the available objects and their associated<br />

events, select an event to bind to a script, and create the script for that event.<br />

A powerful feature of the HTML editor is the encapsulation of the object<br />

models for all of the commonly used browsers. By selecting the browser(s) that<br />

you want to support in your scripts, you can view the objects and their<br />

associated methods, properties, and events. You can even use drag-and-drop<br />

to insert the code for accessing the object model into your scripts.<br />

Scripting event handlers<br />

Using the browser’s object model, as presented in the DOM Objects window<br />

of the Client Scripts view, you can identify the event that you want to associate<br />

with an event-handler script. “Browsing the object model” on page 241<br />

explains how the objects are organized in the DOM Objects window. While<br />

creating the script, you can also use the DOM Objects view to locate and insert<br />

the code to access properties and functions of any object that is available on<br />

the page. Complete documentation of the object models is outside the scope<br />

247


Chapter 10: Working with Client-side Scripts<br />

of this document. Up-to-date documentation of the object model is available<br />

online from the Web browser vendors. There are also many reference books<br />

with extensive coverage of the use of the object models.<br />

To write an event handler script<br />

1 In the Client Scripts view of the HTML editor, click on the icon of the<br />

event to be associated with the script.<br />

248<br />

The icon for the event will be highlighted with a red box. The editing<br />

window now contains the script currently associated with this event. If<br />

there is no script currently associated with this event, the editing window<br />

will be empty.<br />

Shortcut - In the Normal view of the HTML editor, select the<br />

object with which the script should be associated. Switch to<br />

the Client Scripts view. The DOM Objects panel now indicates<br />

that the currently selected item is an event associated with this<br />

object. The HTML editor maintains focus on selected objects<br />

and events when switching between views.<br />

2 In the edit window, enter the script code for the event. The browser will<br />

execute this code when the event occurs.<br />

3 To insert the code to reference a property or method from the object<br />

model into the script, drag-and-drop the icon for the property or method<br />

from the DOM Objects panel into the editing panel.<br />

Note - Event handling scripts do not appear in the Normal<br />

view of the HTML editor.


Browser compatibility issues<br />

Chapter 10: Working with Client-side Scripts<br />

Perhaps the most difficult part of developing Web content is dealing with<br />

browser compatibility issues. This is especially true when developing<br />

client-side scripts. Aside from differences in features, you must consider which<br />

browsers and platforms the viewers of the Web page will be using. When<br />

writing client-side scripts you need to be aware of:<br />

the scripting language and version (JavaScript or VBScript)<br />

the browser type and version (Navigator, IE, others)<br />

the OS platform and version (Windows, Mac or UNIX)<br />

JavaScript is the predominate scripting language used today. Different<br />

browsers support different versions of JavaScript. The table below shows the<br />

language level support of the two major browsers.<br />

Script Language Navigator Internet Explorer<br />

VBScript IE<br />

JavaScript 1.0 Navigator 2.x IE 3.x<br />

JavaScript 1.1 Navigator 3.x<br />

JavaScript 1.2 Navigator 4.x 1<br />

1. Not fully compliant<br />

IE 4.x<br />

If you specify JavaScript in the Client Scripts tab of the Options dialog, any<br />

browser that supports JavaScript1.0 or later versions will be able to run your<br />

scripts. The <strong>IDE</strong>/IP generates JavaScript code that will only be executed by<br />

browsers that understand the script tag and that have script capabilities turned<br />

on.<br />

The different versions of JavaScript reflect changes in the core language, such<br />

as support for arrays, strings, and Java scripting. The objects in the DOM<br />

Objects window of the Client Scripts view are not part of the JavaScript<br />

language and are not determined by the version of JavaScript used, but by the<br />

browser’s object model.<br />

The greatest difference in browser compatibility is in the Document Object<br />

Model or DOM, and support for Dynamic HTML. The DOM continues to<br />

evolve with each version of the browsers. In Navigator 4.x and IE 4.x, there<br />

was a significant divergence in the DOM. As a result, there has been a push for<br />

a common DOM standard that may result in a common base for writing<br />

249


Chapter 10: Working with Client-side Scripts<br />

client-side scripts in the future. Currently, you have to make some strategic<br />

decisions about which browsers and feature sets to support.<br />

The browser object model<br />

Both Navigator and IE have defined object models that provide a<br />

programming interface to control the content and behavior of the displayed<br />

Web pages. These object models are sometimes referred to as the Document<br />

Object Model, or DOM. Two very important objects in the DOM are the<br />

window object and the document object.<br />

The window object is a root-level object that represents the window that the<br />

browser uses to display a Web page. Some of the objects that can be accessed<br />

from the window object are:<br />

250<br />

frames contained in the window<br />

a document (or Web page) loaded into the window<br />

colors used in drawing items in the window<br />

the URL for the document<br />

The document object, which is subordinate to the window object, represents<br />

the HTML page. Some of the objects accessible from the document include:<br />

images and applets displayed on the page<br />

forms and elements in the forms (text boxes, buttons, radio buttons, etc.)<br />

links and anchors in the page<br />

cookies<br />

Objects have properties or attributes that can be queried and sometimes set by<br />

scripts. Many objects also have functions, which are methods that scripts can<br />

invoke to cause the object to take some action. Many objects also have events<br />

triggered by the browser as the user interacts with the page. Events are<br />

particularly useful for enabling user interaction. When an event occurs, such<br />

as the user clicking on a button, the browser invokes the event handler script<br />

associated with that event.<br />

Strategies for handling browser incompatibilities<br />

The HTML editor gives you the ability to filter out objects, properties, and<br />

events in the graph of objects in the Client Scripts view. You can choose to<br />

browse through all of the possible features, or display a subset of the DOM<br />

containing only those objects, properties, and methods supported by a specific<br />

browser version. In addition, if you right-click on an object in the DOM and


Chapter 10: Working with Client-side Scripts<br />

select Properties..., a Document Object Properties dialog lists the browsers that<br />

support that object.<br />

Here are a few strategies for addressing browser compatibility:<br />

least common denominator. If you use only the language features and<br />

DOM supported by Navigator 2.x, your scripts will run on all of the<br />

browsers currently in use. The level of sophistication possible at this level<br />

is fairly low. The only dynamic content supported is forms, form fields,<br />

and links. By moving the bar up to Navigator 3.x, you still retain a<br />

majority of the browsers in use and gain some additional capabilities,<br />

such as dynamic images and the ability to script Java applets.<br />

conditional coding. Write your scripts to determine the browser at<br />

runtime, and run scripts that have been written for that browser version.<br />

You may choose to interleave browser specific code in the page.<br />

Supporting multiple browsers is a lot of work, but it lets you present the<br />

best appearance possible to all viewers.<br />

ignore the problem. Maybe you do not have to write scripts that can be<br />

viewed by everyone. If so, write for the browser version of your choice<br />

and fail gracefully on the rest. Consider yourself very lucky.<br />

Platform specific compatibilities are difficult to anticipate. The basic premise<br />

is that the scripting languages and browser support allow Web content<br />

including scripts to be platform independent. In practice, implementations<br />

are not perfect and there are incompatibilities and as well as bugs that may<br />

cause users to experience difficulty viewing your page. Internet sources such<br />

as user groups and FAQs are your best source for this type of information.<br />

The following example JavaScript code takes advantage of a feature that is only<br />

present in IE 4.x.<br />

var browser = navigator.appName;<br />

var version = parseInt(navigator.appVersion);<br />

var bIsIE4 = (browser.indexOf("MicroSoft") != -1) &&<br />

(version == 4);<br />

// if this is running on IE 4, scroll the form to the top of the<br />

// window<br />

if ( bIsIE4 ) {<br />

document.Form2.scrollIntoView();<br />

}<br />

Although the LANGUAGE attribute of the tag could be used to prevent<br />

browsers from running scripts that include features of later versions of the<br />

language than the browser supports, it is preferable to query the<br />

251


Chapter 10: Working with Client-side Scripts<br />

Window.navigator object to conditionally execute code targeted for specific<br />

browsers.<br />

About Dynamic HTML<br />

Navigator 4.x and IE 4.x introduced greatly enhanced support for Dynamic<br />

HTML (DHTML). In addition to a richer DOM, DHTML has an extended event<br />

model and support for absolute positioning though cascading style sheets<br />

(CSS). Unfortunately, the DOM’s properties used by the fourth generation of<br />

Navigator and IE to position elements are very different. To access the object<br />

properties, you have to use browser sensing. The next generation of browsers<br />

may become more compatible as the standards for a common DOM are<br />

adopted.<br />

In spite of the current difficulties, DHTML offers the option of creating truly<br />

interactive, dynamic Web pages. The HTML editor enables you to develop<br />

DHTML for both Navigator and IE browsers by providing the complete DOM<br />

for both browsers and the ability to drag-and-drop code for object references<br />

as well as an intuitive interface for binding scripts to events. Dynamic<br />

positioning of elements is done through layers in Navigator and CSS<br />

properties in IE. Both of these methods are supported in the HTML editor as<br />

part of the object model for the browser.<br />

Moving objects using DTHML<br />

Here’s a simple example that illustrates how to use DHTML in <strong>HAHTsite</strong> to<br />

animate objects. Say that you want a picture to change its location in a<br />

window when the user clicks a button. This example shows how client scripts<br />

can detect browser types, and move an object using CSS positioning for IE 4.x<br />

browsers and Netscape Layers for Navigator 4.x browsers.<br />

252


This example involves the following steps:<br />

Chapter 10: Working with Client-side Scripts<br />

1 Insert a picture and a set of buttons to control the movement of the<br />

picture on a page.<br />

2 Create a Netscape Layer. This task is described in “To create a Netscape<br />

Layer from a SPAN” on page 253.<br />

3 Add client scripts to the buttons that move the object, using browser<br />

specific mechanisms for positioning the objects.<br />

Why use Netscape Layers for positioning?<br />

In IE 4.x browsers, CSS positioning can be used to position any object in the<br />

document. Navigator 4.x does not support CSS positioning directly for all<br />

document objects. In Navigator 4.x positioning of objects is enabled by<br />

embedding the objects in Netscape Layers, which can be moved through<br />

positioning. Before an object like a picture can be moved, the picture needs to<br />

be inserted into a tag which can be turned into a layer. Only container<br />

objects like and can be treated as layers.<br />

To create a Netscape Layer from a SPAN<br />

1 In the Normal view of the HTML editor, select the object(s) to be inserted<br />

into a layer. For example, to insert a picture, click on the picture.<br />

2 From the main toolbar, select Insert > Span....<br />

The Insert SPAN dialog appears.<br />

253


Chapter 10: Working with Client-side Scripts<br />

3 Click on the Properties... button to set the Style property.<br />

254<br />

The Style Properties Page Editor appears. For more information about<br />

setting these properties, see Chapter 12, “Cascading Style Sheets,” in the<br />

<strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>.<br />

4 Select the Positioning tab of the Style Properties editor.<br />

5 Set the Position to relative. Setting the Position attribute of the Style<br />

Properties to relative or absolute makes the SPAN into a Netscape Layer.<br />

6 Click OK.<br />

7 Type a value for the SPAN tag into the ID field of the Insert Span dialog.<br />

8 Click OK.


Chapter 10: Working with Client-side Scripts<br />

JavaScript example for browser-independent DHTML<br />

As a result of creating a Netscape layer from the SPAN object, there are two<br />

representations of the SPAN object, depending on which browser DOM you<br />

are using:<br />

The IE 4.x DOM represents the SPAN object as<br />

window.document.all.SPAN1.<br />

The Navigator 4.x DOM represents the SPAN object as<br />

window.document.layers.SPAN1.<br />

The DOM Objects window shows the different representations of the SPAN<br />

object.<br />

To reference these objects in client-side scripts, you must use syntax specific to<br />

the object model. The following script is a JavaScript script that is bound to<br />

the onClick event of the button labeled Up in the example. When the user<br />

clicks on the ‘Up’ button, the image will move up 10 pixels.<br />

JavaScript attached to the Up button<br />

if (bIsNS4) {<br />

moveElement(document.SPAN1, 0, -10);<br />

}<br />

else if (bIsIE4) {<br />

moveElement(document.all["SPAN1"], 0, -10);<br />

}<br />

255


Chapter 10: Working with Client-side Scripts<br />

This example script uses two JavaScript code pages, BrowserVersion.js and<br />

MoveObject.js. The first file, BrowserVersion.js, sets the page scope<br />

variables bIsNS4 (browser is Navigator4) and bIsIE4 (browser is IE4), which<br />

are used to determine which DOM will be used. The second file,<br />

MoveObject.js, contains the function moveElement() that moves the object<br />

on the page.<br />

BrowserVersion.js<br />

var sAgent = navigator.userAgent;<br />

var bIs95NT = sAgent.indexOf("Windows 95") > -1 || sAgent.indexOf(<br />

"Windows NT") > -1 || sAgent.indexOf("Win32") > -1;<br />

var bIsIE4 = sAgent.indexOf("IE 4") != -1;<br />

var appVer = navigator.appVersion;<br />

var bIsNS = (navigator.appName == 'Netscape');<br />

var bIsNS4 = bIsNS && (appVer.indexOf('4') != -1);<br />

256


MoveObject.js<br />

Chapter 10: Working with Client-side Scripts<br />

function moveElement( element, x, y, animate ) {<br />

if ( bIsNS4 ) {<br />

if ( element )<br />

element.moveBy( x, y );<br />

else<br />

alert( "MoveObject error: element is not a layer. Make<br />

sure STYLE=\"position:relative\" is set." );<br />

}<br />

}<br />

else if ( bIsIE4 ) {<br />

if ( element.style.position == "" )<br />

element.style.position = "relative";<br />

sLeft = element.style.left.substr( 0, element.style.left.<br />

indexOf( ‘px’ ));<br />

if ( isNaN( parseInt( sLeft )))<br />

sLeft = "0";<br />

element.style.left = parseInt( sLeft ) + x;<br />

sTop = element.style.top.substr( 0, element.style.top.<br />

indexOf( ‘px’ ));<br />

if ( isNaN( parseInt( sTop )))<br />

sTop = "0";<br />

element.style.top = parseInt( sTop ) + y;<br />

}<br />

return;<br />

These functions could be included as project files that are referenced as page<br />

functions or as script functions that are part of the HTML page. See “Writing<br />

script functions” on page 244 for more information on how to include page<br />

scope functions in your page.<br />

Scripts with server-side expressions<br />

You can use information from your application on the server in your<br />

client-side scripts by using embedded server-side expressions. In a HAHTtalk<br />

257


Chapter 10: Working with Client-side Scripts<br />

project, HAHTtalk Basic expressions can be embedded in client-side scripts. In<br />

a similar manner, Java projects allow server-side Java expressions to be<br />

embedded in client-side scripts.<br />

Inserting server-side expressions into a page causes that page to become a<br />

dynamic page. When a page containing scripts with embedded server-side<br />

expressions is requested by a browser, the Application Server executes the<br />

HAHTtalk or Java code and places evaluated expressions into the script before<br />

sending the page to the user’s browser. The server-side expressions are<br />

evaluated by the Application Server each time the page is requested by a<br />

browser.<br />

Embedded server-side expressions are marked using the following a<br />

begin-and-end syntax:<br />

258<br />

/*== marks the beginning of a server-side expression<br />

*/ marks the end of a server-side expression<br />

For example, the following code initializes the JavaScript variables<br />

pagesVisited and userName to values stored in the HAHTtalk Basic variables<br />

PagesVisited and LoginUser:<br />

var pagesVisited = /*== PagesVisited */;<br />

var userName = '/*== LoginUser */';<br />

When the page containing this code is requested, the Application Server<br />

evaluates the HAHTtalk Basic expressions and sends the following script to the<br />

browser:<br />

var pagesVisited = 10;<br />

var userName = 'Zachary';<br />

Note the single quotes around /*== LoginUser */. These quotes are required<br />

because LoginUser is a string variable. When string variables are evaluated,<br />

they need to be in quotes.<br />

The server-side Java expression equivalent to the above HAHTtalk Basic<br />

example would be:<br />

var pagesVisited = /*== com.haht.project.PagesVisited */;<br />

var userName = '/*== com.haht.project.Session.getUserName()*/':


Using HtmlOut<br />

Routines or the<br />

HtmlOut Class<br />

11<br />

Creating HTML at runtime...........................................................................260<br />

The HAHTtalk Basic HtmlOut library ..........................................................260<br />

Using the HAHTtalk Basic HtmlOut library ...........................................261<br />

HAHTtalk Basic example .........................................................................262<br />

The HtmlOut Java class ................................................................................264<br />

Java example ............................................................................................265<br />

259


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

Creating HTML at runtime<br />

You may have situations in your applications where you want to build HTML<br />

tags “on-the-fly” (at runtime). For example, dynamic pages often contain<br />

information that has been retrieved from a database system or from another<br />

software system. Both HAHTtalk Basic and Java provide database access using<br />

ODBC and support ActiveX, OLE automation, DLL calls, and other<br />

mechanisms for communicating with other software systems.<br />

Once you receive information from one of these systems, you must format the<br />

data and display it on a dynamic page. For example, you may want to retrieve<br />

the records from a database and display the data in an HTML table. To<br />

accomplish this, you need to generate HTML table tags at runtime. In most<br />

cases, you’ll use <strong>HAHTsite</strong>’s wizards and widgets to display the database data.<br />

However, there may be cases where you want to format data in special ways<br />

not supported by a wizard or widget.<br />

You can generate HTML tags with HAHTtalk Basic print statements or with<br />

Java calls to out.print() or out.println(). For example, the following<br />

HAHTtalk Basic print statement displays the value of the “LastName” variable<br />

in the cell of an HTML table:<br />

Print "" & LastName & ""<br />

You certainly wouldn’t want to write print statements each time that you want<br />

to create some dynamic HTML. Fortunately, <strong>HAHTsite</strong> includes both a library<br />

of HAHTtalk Basic HTML routines and a Java class, both called HtmlOut.<br />

The HAHTtalk Basic HtmlOut library<br />

The routines and their arguments are documented in the HtmlOut.hbs file,<br />

which is installed in <strong>HAHTsite</strong>InstallDir\scripts (where<br />

<strong>HAHTsite</strong>InstallDir is the directory into which <strong>HAHTsite</strong> was installed;<br />

C:\HAHTSITE, for example). In addition to this source file, the<br />

<strong>HAHTsite</strong>InstallDir\include directory contains the file HtmlOutDecl.hbh,<br />

an include file that contains the declarations for the HtmlOut routines.<br />

The HtmlOut library contains general-purpose routines that generate HTML<br />

tags. For example, you would use the htmlTableDataText routine to print the<br />

value of LastName in a cell of an HTML table:<br />

htmlTableDataText LastName,0,0,0<br />

260


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

The 0,0,0 arguments represent additional HTML parameters (alignment,<br />

column spanning, and row spanning) that aren’t used in this example.<br />

The HtmlOut routines include support for:<br />

line, paragraph, indenting, and ruler tags<br />

character formatting<br />

lists and numbered bullets<br />

links and bookmarks<br />

images<br />

forms and form fields<br />

tables<br />

frames<br />

headers<br />

Using the HAHTtalk Basic HtmlOut library<br />

To use HAHTtalk Basic HtmlOut routines in your project you have the option<br />

of including the library either globally (for all files in your project), or at the<br />

page level.<br />

Including the HAHTtalk Basic HtmlOut library at the page level<br />

1 Create in the project a code page and copy to it the contents of the<br />

HtmlOut.hbs file.<br />

For example:<br />

Create a code page named HtmlOutInclude.hbs.<br />

Copy the contents of the <strong>HAHTsite</strong>InstallDir\Scripts\HtmlOut.hbs<br />

file into your project’s HtmlOutInclude.hbs page.<br />

2 Include the HtmlOut declarations file (HtmlOutDecl.hbh) in each page<br />

that uses the HtmlOut routines or in each page of the project.<br />

3 If you are using the HtmlOut routines in only a few pages, you can include<br />

the declarations file in the pages. To do that:<br />

With the page that will use the HtmlOut routines open in the HTML<br />

editor, select View > Server-Side Code to display the page in server-side<br />

code view.<br />

Scroll to the top of the page to find the “Imports and includes”<br />

section.<br />

261


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

4 Type the following #include directive into the “Imports and includes”<br />

area.<br />

#Include <br />

262<br />

You can now call the HtmlOut subroutines from this page.<br />

Including the HAHTtalk Basic HtmlOut library for all pages in your project<br />

1 If you don’t already have a Globals.hbs page in your project, create one.<br />

2 In the Globals.hbs page, place the directive:<br />

#Include <br />

3 Call the HtmlOut subroutines from your project’s Web pages.<br />

HAHTtalk Basic example<br />

This example is provided as a way to demonstrate the features of some<br />

HAHTtalk Basic HtmlOut routines. Typically, you would build a table, like the<br />

one shown in this example, with the Report Wizard.<br />

Below is sample code that uses HtmlOut routines to create dynamically the<br />

rows of a table, based on how many records are in the Data Set “DataSet1.” The<br />

code displays a three-column table showing a record count, an employee’s first<br />

name, and last name.


HAHTtalk Basic<br />

Here is what the table looks like in a browser.<br />

Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

Dim NumFound As Integer, I As Integer<br />

Dim MatchingRec As String<br />

' Get the number of records in the Data Set.<br />

NumFound = DataSet1_RecordSet.DynaSet.RecordCount<br />

' Print the number of matching records.<br />

MatchingRec = " matching records."<br />

If NumFound = 1 Then<br />

MatchingRec = " matching record."<br />

End If<br />

Print "Found " & NumFound & MatchingRec<br />

' Start the table. 1=1-pixel border<br />

htmlTableStart 1,0,true,0,true,0,0<br />

' Start a row for the column headers. 0=left aligned row.<br />

htmlTableRowStart 0<br />

' Print the three column headers. 2=centered.<br />

htmlTableHeadingText "Record#",2,0,0<br />

htmlTableHeadingText "First Name",2,0,0<br />

htmlTableHeadingText "Last Name",2,0,0<br />

htmlTableRowEnd<br />

' Go through the Data Set and get records. Create a row for each<br />

' record and print the data for the three columns.<br />

For I = 1 to NumFound<br />

htmlTableRowStart 0<br />

htmlTableDataText format$(i),0,0,0<br />

htmlTableDataText<br />

DataSet1_RecordSet.DynaSet.fields("FirstName").value,0,0,0<br />

htmlTableDataText<br />

DataSet1_RecordSet.DynaSet.fields("LastName").value,0,0,0<br />

DataSet1_RecordSet.DynaSet.MoveNext<br />

htmlTableRowEnd<br />

Next I<br />

' End the table.<br />

htmlTableEnd<br />

263


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

The HtmlOut Java class<br />

The static member variables of the HtmlOut class are used to generate HTML.<br />

In the simplest case, you can use them directly (for example, the Bold and<br />

HorizontalRule members can be used to generate text between two<br />

horizontal rules and surrounded by boldface tags).<br />

HtmlOut.HorizontalRule.renderAsHtml();<br />

HtmlOut.Bold.text("Hello");<br />

264


HtmlOut.HorizontalRule.renderAsHtml();<br />

or, equivalently:<br />

HtmlOut.HorizontalRule.renderAsHtml();<br />

HtmlOut.Bold.start();<br />

// somehow emit the string "Hello"<br />

HtmlOut.Bold.end();<br />

HtmlOut.HorizontalRule.renderAsHtml();<br />

Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

HtmlOut class members can also be used as the starting point for more<br />

elaborate formatting control (e.g., the FontUp1 member variable creates the<br />

HTML tag that increases the font size by one step). Red text in this font<br />

size can be also be produced as follows:<br />

PairedTag myFont = HtmlOut.FontUp1.clone();<br />

myFont.setAttribute( "COLOR", "RED" );<br />

myFont.Text("Hello");<br />

HtmlOut also contains static member functions for creating the HTML tag<br />

objects for tables, forms, and other more complex HTML entities. Thus, the<br />

example above could also be coded as follows:<br />

PairedTag myFont = HtmlOut.makeFont( "", "+1", "RED" );<br />

myFont.text("Hello");<br />

Here, the call to makeFont creates a font object using the default font face, a<br />

font size one step larger, and with the color "RED".<br />

Certain arguments of the static member functions are specified as being<br />

optional. An optional String argument may be null or the empty string; an<br />

optional integer argument may be a negative number. These values cause the<br />

attribute in question not to be specified in the HTML, so that the browser will<br />

supply its default behavior as shown in the following sample lines of code:<br />

PairedTag myFont = HtmlOut.makeFont( "", "", "RED" );<br />

myFont.Text( "Hello" );<br />

causes the string “Hello” to be printed in red in the current font, while<br />

PairedTag myFont = HtmlOut.makeFont( "Arial", "1", "RED" );<br />

myFont.Text( "Hello" );<br />

causes the string “Hello” to be printed in red in Arial font.<br />

Java example<br />

The following is a simple example using the Java HtmlOut class to build and<br />

populate a simple HTML table.<br />

265


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

Java<br />

Here is what the table looks like in a browser.<br />

266<br />

PairedTag myTable = HtmlOut.makeTable(true, 6, 216, false, 99,<br />

true, 0, 0,"");<br />

PairedTag myTableHeader =<br />

HtmlOut.makeTableData("CENTER",1,1,"lightblue");<br />

myTable.start();<br />

HtmlOut.TableRow.start();<br />

myTableHeader.text("Delete Item");<br />

myTableHeader.text("Material Number");<br />

myTableHeader.text("Material Description");<br />

myTableHeader.text("Quantity");<br />

myTableHeader.text("Net Value");<br />

myTableHeader.text("Delivery Date");<br />

HtmlOut.TableRow.end();<br />

for(int i=1; i


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

267


Chapter 11: Using HtmlOut Routines or the HtmlOut Class<br />

268


Access Control<br />

12<br />

What is access control? ................................................................................270<br />

Granting privileges: the basics .....................................................................271<br />

Controlling access to a page ...................................................................271<br />

Controlling access to part of a page .......................................................274<br />

Displaying a custom error page ..............................................................275<br />

Granting privileges to logged-in users .........................................................276<br />

Authenticating users with the Login widget ..........................................277<br />

Authenticating users with the Authentication interface........................286<br />

Letting the Web server authenticate users..............................................288<br />

Granting privileges on a user-name basis....................................................289<br />

Using a Login widget and a database privilege repository ....................290<br />

Using a Login widget and a nondatabase privilege repository..............291<br />

Using the Server Object Model ...............................................................293<br />

Server Object Model methods ......................................................................296<br />

269


Chapter 12: Access Control<br />

What is access control?<br />

<strong>HAHTsite</strong> includes a security feature called access control that enables you to<br />

restrict a user’s access to any pages of your application served by the<br />

Application Server. That is, you can protect all dynamic and secure-static<br />

pages.<br />

270<br />

Note - Secure-static pages are static pages that you’ve chosen<br />

to publish to a <strong>HAHTsite</strong> Application Server — either for<br />

security reasons or to preserve a state ID.<br />

For additional security, you can place your Application Server behind a<br />

firewall.<br />

The access-control mechanism is based on the concept of privileges.<br />

Associated with each dynamic and secure-static page is a set of zero or more<br />

required privileges, which are strings that you define. In addition, each user<br />

session has associated with it a set of zero or more session privileges. At runtime,<br />

the <strong>HAHTsite</strong> Application Server determines whether a particular user session<br />

can access a page by comparing the required page privileges with the session<br />

privileges. If all of the page’s required privileges are in the session’s set of<br />

privileges, the Application Server grants the session access to the page.<br />

In the figure below, the Application Server will serve the page because the<br />

page’s required privileges are contained in the user’s session privileges.<br />

This access-control mechanism is very flexible and has many uses, but here is<br />

a simple example of how you could use it. Say that your Web site is a<br />

sports-news service, and that some articles are available for free, but others<br />

require that users subscribe to your service. You can protect the<br />

subscriber-only pages by assigning them the required privilege “Subscribed”<br />

and by initially giving each user session no session privileges. If a user later fills


Chapter 12: Access Control<br />

out a subscription form and submits it, you can assign the user’s session the<br />

session privilege “Subscribed.” The user will then be able to read all of the<br />

articles on your site.<br />

For additional information on implementing this type of security, see<br />

“Granting privileges: the basics” on page 271. This chapter also discusses<br />

increasingly complex uses of access control, including:<br />

how to have users log in to an application<br />

how to assign a set of privileges to users who successfully log in<br />

how to assign a user-specific set of privileges to each user who logs in<br />

The chapter concludes with some reference material concerning which classes<br />

and interfaces in the Server Object Model are useful for implementing access<br />

control.<br />

Granting privileges: the basics<br />

This section explains how to protect a page, or part of a page, from<br />

unauthorized access by:<br />

assigning a required privilege to a page (or checking for a privilege before<br />

displaying a page element)<br />

explicitly assigning (or not assigning) one or more session privileges to a<br />

user session, using the Session object’s addPrivilege or addPrivileges<br />

method<br />

The section also discusses how to display a custom error page when a user<br />

attempts to access a page that the he or she does not have the privileges to<br />

access.<br />

Controlling access to a page<br />

This chapter’s introduction (“What is access control?”) discussed in general<br />

terms how a sports-news Web site could control user access to a set of<br />

subscriber-only articles. This fictitious site allows general access to some<br />

articles, but only subscribers (who have a special session privilege) can access<br />

other pages.<br />

271


Chapter 12: Access Control<br />

How do you initially prevent a user from accessing the subscriber-only<br />

articles? And how can you later grant a user session the privilege it needs to<br />

access these articles? The following sections answer these questions.<br />

To prevent a user from accessing a page<br />

1 Configure the <strong>HAHTsite</strong> Application Server to enable access control, if<br />

necessary. By default, access control is enabled.<br />

272<br />

For detailed instructions on how to perform this task, see Chapter 3,<br />

“Performing administrative tasks,” in the <strong>HAHTsite</strong> Application Server<br />

Administration <strong>Guide</strong>. Basically, all you need to do, however, is to check an<br />

Enable Access Control check box.<br />

2 Add one or more privileges to your <strong>HAHTsite</strong> project. These become the<br />

privileges that you can assign to pages to limit access to them.<br />

You add these privileges to a project from the Privileges tab of the Project<br />

Properties dialog. For complete instructions on adding privileges to a<br />

project, see Chapter 3, “Managing Projects,” in the <strong>HAHTsite</strong> <strong>IDE</strong> and IP<br />

User’s <strong>Guide</strong>.<br />

The sports-news project has a single project privilege: “Subscribed.”


3 Assign one or more required privileges to each protected page.<br />

Chapter 12: Access Control<br />

You assign a privilege to a page using the Privileges tab of the Page<br />

Properties dialog. For detailed information about assigning a privilege to a<br />

page (or other project element), see Chapter 3, “Managing Projects,” in<br />

the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s <strong>Guide</strong>.<br />

In the sports-news project, the subscriber-only pages have been assigned<br />

the required privilege “Subscribed.”<br />

Once you’ve performed these steps, a protected page is inaccessible to a user<br />

who doesn’t have the “Subscribed” session privilege. If such a user clicks a link<br />

to a subscriber-only article at the sports-news Web site, the user’s browser will<br />

display an error page indicating that access to the article has been denied.<br />

For information on how to have your application display a more user-friendly<br />

error page, see “Displaying a custom error page” on page 275.<br />

To assign a session privilege to a session<br />

Have your application call the Session object’s addPrivilege or<br />

addPrivileges method.<br />

Here’s how the sports-news Web site assigns the “Subscribed” privilege to a<br />

session:<br />

1 The application’s initial page prompt’s the user to follow a link if the user<br />

wants to subscribe to the sports-news service. If the user selects this link,<br />

the user is taken to a subscription-form page.<br />

2 The user fills out the form and clicks a Submit button. The action<br />

associated with the form is to call a subroutine — a Java method or a<br />

HAHTtalk Basic subroutine.<br />

273


Chapter 12: Access Control<br />

3 The subroutine checks the data submitted and, if the data is OK, assigns<br />

the “Subscribed” privilege to the user’s session.<br />

274<br />

The code used to assign this privilege is shown below:<br />

Java<br />

Haht.getSession().addPrivilege("Subscribed");<br />

HAHTtalk Basic<br />

HahtSession.addPrivilege "Subscribed"<br />

4 The subroutine also runs the application’s initial page.<br />

The user can now follow a link to any article.<br />

Controlling access to part of a page<br />

From the <strong>IDE</strong>, you can set the required privileges for a page, or for a higher<br />

level object such as a folder. However, you might also want to limit access to<br />

just one or more elements on a page.<br />

As an example, the figures below show two versions of a page requested by a<br />

user of the sports-news Web site. The first figure illustrates what a user whose<br />

session does not have the “Subscribed” privilege would see:<br />

The figure below shows what a user whose session does have the “Subscribed”<br />

privilege would see:


Chapter 12: Access Control<br />

The conditional elements on a page are controlled by an if statement that<br />

determines whether the user’s session has a required privilege.<br />

Java<br />

if (Haht.getSession().hasPrivilege("Subscribed")) {<br />

// Conditional elements go here<br />

}<br />

HAHTtalk Basic<br />

If (HahtSession.hasPrivilege("Subscribed")) Then<br />

' Conditional elements go here<br />

End If<br />

Displaying a custom error page<br />

You can create a custom error page for the Application Server to display when<br />

a user tries to access a page for which he or she does not have the necessary<br />

session privileges. The figure below shows a simple access-denied page.<br />

275


Chapter 12: Access Control<br />

To create such a page, you:<br />

276<br />

copy a set of error-page templates (supplied with the Application Server)<br />

to a directory of your choosing<br />

edit the template named HS_access.html so that it contains the content<br />

you want to display<br />

set the Application Server’s Error Page Directory (on the Logging Options<br />

page) to the name of the directory that contains the copied templates<br />

stop and restart your server group<br />

Once you’ve performed these steps, the Application Server will display the<br />

new error page the next time an access violation occurs.<br />

This subject is explained in more detail in Appendix A of the <strong>HAHTsite</strong><br />

Application Server Administration <strong>Guide</strong>.<br />

Granting privileges to logged-in users<br />

“Granting privileges: the basics” on page 271 explained how to handle the<br />

situation where you give a user the privilege to access a protected page when<br />

the user visits another page. In particular, that section looked at an application<br />

that gives a user a privilege when the user fills out a subscription form.<br />

The first time the user visits such a site, the user gets a session privilege by<br />

submitting a form, but what about subsequent visits to the site? If the user is<br />

assigned a user name and password during the first visit, the site would likely<br />

require the user to log in to the application to get his or her privilege on a<br />

second or subsequent visit. This section explains how <strong>HAHTsite</strong> supports<br />

assigning users privileges when they log in to an application.<br />

There are several ways to handle this situation in <strong>HAHTsite</strong>:


Chapter 12: Access Control<br />

One way is to use the <strong>HAHTsite</strong>’s Login widget in your application. When<br />

a user loads a page containing this widget, the widget displays a page<br />

containing a login form, which generally contains user-name, password,<br />

and (optionally) Windows NT domain text boxes. When the user fills out<br />

and submits this form, the widget attempts to authenticate the user using<br />

authentication information maintained by the operating system or in a<br />

user-defined location. If the user is authenticated, the widget assigns the<br />

user one or more session privileges and calls a success page. If the user is<br />

not authenticated, the user does not receive any privileges, and the<br />

widget calls a failure page.<br />

The Login widget is implemented using calls to Server Object Model<br />

methods; therefore, it’s possible for you to authenticate users and assign<br />

privileges to them by calling these same methods directly.<br />

If you want a Web server to authenticate users, you can simply configure<br />

your Web server’s authentication mechanism appropriately. If a user logs<br />

in successfully, your application can assign the user privileges using the<br />

Session class’s addPrivilege or addPrivileges method.<br />

Authenticating users with the Login widget<br />

When you use the Login widget in your application, you can authenticate<br />

users against authentication information maintained:<br />

by the operating system<br />

in another (“user-defined”) location, such as an LDAP directory or a<br />

database<br />

The procedures for the two types of applications are very similar. The only<br />

difference is that <strong>HAHTsite</strong> includes a Java class that performs<br />

operating-system authentication. To authenticate users against information<br />

stored elsewhere, you must write the Java class that performs this<br />

authentication. You’ll find more information on this subject in “To perform<br />

user-defined authentication” on page 285.<br />

To illustrate how to assign a privilege to a user when the user successfully logs<br />

in to an application, this section shows how an application that uses this<br />

strategy was put together. The example is a variation on the sports-news Web<br />

site discussed earlier. In this version of the example, when a subscriber goes to<br />

the site, the user does not have the privileges to read feature articles. The user<br />

must elect to log in to the application against information maintained by the<br />

operating system. If the user logs in successfully, the application grants the<br />

user the privilege “Subscribed,” which enables the user to read protected<br />

pages.<br />

277


Chapter 12: Access Control<br />

The main steps involved in adding the authentication feature to the<br />

application are:<br />

278<br />

adding to your project a login page — which contains a form that<br />

requests login information — and success and failure pages<br />

adding the Login widget to the application<br />

In addition, it may be necessary to change the configuration of the<br />

Application Server.<br />

You will find detailed information about how these steps were performed in<br />

the following sections.<br />

To add the pages required by the Login widget<br />

1 Add to your project a page that will be used by the Login widget to present<br />

a login form to the user.<br />

The easiest way to perform this task is to use the application-login-page<br />

template supplied with <strong>HAHTsite</strong>. To use this template:<br />

From the File menu, select New > Page....<br />

From the list of templates in the New Page dialog, choose the User<br />

Login Page template, and click the OK button. The page shown below<br />

is opened.<br />

Customize the login page if you want to.<br />

Give the page a name, and save the page.<br />

From the Publish tab of the Page Properties dialog, promote the page<br />

to dynamic or secure static so that the page will be published to the<br />

Application Server.


Chapter 12: Access Control<br />

Of course, you can also create your login form by hand. The form should<br />

include a User Name text box, a Password text box, a Domain text box (if<br />

appropriate), and a Submit button.<br />

Note - The form can also be placed on the page that contains<br />

the Login widget.<br />

The table below shows how you should name the text fields in the form to<br />

minimize the number of attributes you will need to customize in the<br />

Login widget itself.<br />

Text box label Text field name<br />

User Name txtUserName<br />

Password txtUserPassword<br />

Domain txtUserDomain<br />

The action you associate with this form should have the following<br />

attributes:<br />

Type: Project Item<br />

Path: None. (Leave this field blank.)<br />

If you supply these values, submitting the form will cause the application<br />

to load the previous page. In the present case, the application will load the<br />

page containing the Login widget.<br />

One last point. Make sure that the login page is dynamic or secure static so<br />

that it will be published to the Application Server.<br />

2 Create a success page. This page will be loaded if the user successfully logs<br />

in.<br />

Note - The success (or failure) page can also be the same as the<br />

page that contains the Login widget.<br />

Set this page’s properties to make the page dynamic or secure static.<br />

3 Create a failure page. This page will be loaded if the user login is<br />

unsuccessful.<br />

Set this page’s properties to make the page dynamic or secure static.<br />

To add the Login widget<br />

1 Create a blank page to hold the Login widget.<br />

279


Chapter 12: Access Control<br />

280<br />

When the application calls the page containing the Login widget, the<br />

widget will cause the login page (the page containing the login form) to be<br />

displayed.<br />

2 Drag a Login widget from the Project window to the page.<br />

3 Set the widget’s properties.<br />

The following four tables explain what information you need to supply on<br />

the four tabs of the Login Properties dialog.<br />

The first tab of the dialog, labeled General, enables you supply a name for<br />

the widget and to specify some general characteristics of the widget’s<br />

behavior.<br />

Form field Description<br />

Name Type the name of the Login widget here.<br />

Reset session privileges on<br />

successful login check box<br />

When a user’s session loads a page<br />

containing a Login widget, the user may<br />

already have some session privileges. If this<br />

check box is checked, the user’s current<br />

privileges are taken away, and the user is<br />

assigned the privileges indicated on the<br />

Privileges tab of the Login Properties dialog.<br />

If the check box is not checked, the user<br />

receives the privileges indicated on the<br />

Privileges tab in addition to any current<br />

privileges.


Form field Description<br />

Remember successful login<br />

check box<br />

Only one login per session<br />

check box<br />

Chapter 12: Access Control<br />

This option enables you to specify whether<br />

the user must log in each time the user goes<br />

to the page containing the Login widget<br />

(unchecked) or whether the user must log in<br />

only the first time the user goes to that page<br />

(checked).<br />

An application may contain more than one<br />

Login widget. If this check box is checked,<br />

the user will be prompted to log in only<br />

once per session.<br />

The Navigation tab of the Login Properties dialog enables you to indicate<br />

the pages the Login widget should call:<br />

to display a login form<br />

if the login succeeds<br />

if the login fails<br />

Form field Description<br />

Login page: Page containing<br />

widget<br />

Select this radio button if the page<br />

containing the Login widget also contains<br />

the login form the user fills out to log in.<br />

281


Chapter 12: Access Control<br />

282<br />

Form field Description<br />

Login page: Another page Select this radio button if the page<br />

containing the Login widget and the page<br />

containing the login form are different<br />

pages. In the example project, this is the<br />

case.<br />

Success page: Page containing<br />

widget<br />

Select this radio button if the page<br />

containing the Login widget is also your<br />

success page.<br />

Success page: Another page Select this radio button if the page<br />

containing the Login widget and your<br />

success page are different pages. In the<br />

example project, this is the case.<br />

Failure page: Page containing<br />

widget<br />

Select this radio button if the page<br />

containing the Login widget is also your<br />

failure page.<br />

Failure page: Another page Select this radio button if the page<br />

containing the Login widget and your failure<br />

page are different pages. In the example<br />

project, this is the case.<br />

The Login tab of the Login Properties dialog enables you to indicate the<br />

names of the text boxes in which the Login widget will look for login<br />

information:


Form field Description<br />

Chapter 12: Access Control<br />

User Name The name of the text box in the login form<br />

in which the user enters a user name.<br />

User Password The name of the text box in the login form<br />

in which the user enters a password.<br />

User Domain The name of the text box in the login form<br />

in which the user enters a Windows NT<br />

domain name. This information is only used<br />

if the user is logging on against<br />

authentication information maintained by<br />

Windows NT.<br />

Note - If you create your login page as described in “To add the<br />

pages required by the Login widget” on page 278, you won’t<br />

have to modify the Login tab of the dialog.<br />

On the Privileges tab of the Login Properties dialog, you indicate whether<br />

a logged-in user should receive a predefined set of privileges or whether<br />

the Login widget should look up the user’s privileges in a privilege<br />

repository. The current example is using the former option: a user receives<br />

the “Subscribed” privilege upon logging in. For information on looking up<br />

privileges in a privilege repository, see “Granting privileges on a user-name<br />

basis” on page 289.<br />

283


Chapter 12: Access Control<br />

To configure the Application Server<br />

284<br />

Form field Description<br />

Use privilege repository radio<br />

button<br />

Grant privileges on login radio<br />

button<br />

Select this button to indicate that the widget<br />

should read the user’s privileges from a<br />

database or some other repository.<br />

Select this button to indicate that a user who<br />

successfully logs in should receive the<br />

privileges shown in the list. You can add<br />

privileges to and remove privileges from the<br />

list by using the Add... and Remove buttons.<br />

Set the access-control properties of your Application Server so that the<br />

Authentication Type is either Operating System or User Defined. (By<br />

default, this property is set to Operating System.) For specific instructions<br />

on how to configure this property, see Chapter 3, “Performing<br />

administrative tasks,” in the <strong>HAHTsite</strong> Application Server Administration<br />

<strong>Guide</strong>.<br />

If you select Operating System authentication, the Login widget will use a<br />

Java class called OSAuthentication to authenticate users. This is the<br />

scenario in the sample project.<br />

The OSAuthentication class, which implements the Authentication<br />

interface, uses the operating system’s login mechanism to authenticate<br />

user logins. This authentication is performed on the <strong>HAHTsite</strong> Background<br />

Host on which the <strong>HAHTsite</strong> session is running. Before you use the<br />

OSAuthentication class with <strong>HAHTsite</strong>, you should be aware of the<br />

following platform-specific requirements:<br />

Windows NT requires that a process hold a Windows NT privilege<br />

named “Act as a part of the Operating System” in order to validate a<br />

user login. The <strong>HAHTsite</strong> Background Service that performs this<br />

validation runs as the System Account by default. This account has<br />

the required privilege. Therefore, you should not change the user<br />

account for the <strong>HAHTsite</strong> Background Service if you want to use<br />

operating-system authentication.<br />

The Developer’s Edition of the <strong>HAHTsite</strong> Application Server cannot<br />

actually perform operating-system authentication because it runs as a<br />

desktop application. Consequently, when you’re running the<br />

Developer’s Edition, the method used to authenticate users always<br />

returns true unless the user name is “InvalidUser,” the password is<br />

“InvalidPassword,” or the domain value is “InvalidDomain.” This


Chapter 12: Access Control<br />

arrangement enables you to test success cases with different user<br />

names without knowing the corresponding passwords, and to test<br />

failure cases with the Developer’s Edition.<br />

For <strong>HAHTsite</strong> Background Hosts running on UNIX, you can use<br />

OSAuthentication only if a root installation of the Application Server<br />

has been performed.<br />

If you select User Defined authentication, you must write and add to your<br />

project a Java class that performs the authentication. You must also write<br />

code that will set a variable of your application’s Application object at<br />

runtime. This variable must contain the name of the authentication class<br />

you’ve written. For further information about implementing a custom<br />

authentication class, see “To perform user-defined authentication” below.<br />

To perform user-defined authentication<br />

1 In your project’s Packages folder, create a Java source file and write your<br />

authentication class. This class must implement the Authentication<br />

interface and, thus, must define a method named authorizeUser:<br />

boolean authorizeUser(String aUserID, String aPassword, String<br />

aDomain)<br />

This method should return true if the user is authenticated, and false<br />

otherwise. Appendix C, “Code Examples,” presents a sample<br />

authentication class that authenticates users against information stored in<br />

a database.<br />

2 Add to your project the code that will enable your application to<br />

determine at runtime which Java class it should use for user-defined<br />

authentication. This task differs somewhat between Java and HAHTtalk<br />

Basic projects.<br />

Java projects. Modify your project’s HahtApplication class by editing the<br />

source file HahtApplication.java. Add to the class’s onStart method<br />

code to identify your custom authentication class. You do this by calling<br />

the method setAuthenticationClassByName.<br />

Java<br />

public void onStart(com.haht.project.ApplicationEvent anEvent)<br />

{<br />

this.setAuthenticationClassByName("CustomAuthentication");<br />

}<br />

285


Chapter 12: Access Control<br />

286<br />

HAHTtalk Basic projects. Add a code page to your project, and in this file<br />

define a public function called HahtSessionOnStart. This function should<br />

call the Application object’s setAuthenticationClassByName method to<br />

identify the name of the user-defined class that will perform the<br />

authentication.<br />

HAHTtalk Basic<br />

Public function HahtSessionOnStart As Boolean<br />

Dim AuthSuccess As Boolean<br />

AuthSuccess = _<br />

HahtApplication.setAuthenticationClassByName _<br />

("CustomAuthentication")<br />

HahtSessionOnStart = AuthSuccess<br />

End Function<br />

Caution - In a Java project, a publish operation does<br />

not place your custom authentication class in the<br />

!<br />

Application Server’s default Java Class Directory or<br />

in a default directory on the System Java Class Path.<br />

Before running your application, either move your class file to<br />

a directory where the Application Server can find it, or change<br />

your System Java Class Path to include the directory where<br />

your class file resides.<br />

Tip - While debugging a custom authentication class, turn on<br />

the project property “Run each app instance in separate<br />

process.” This setting will cause the Application Server to<br />

reload your authentication class each time you run your<br />

application.<br />

Authenticating users with the Authentication interface<br />

The Login widget authenticates users by calling:<br />

the authorizeUser method of a class that implements the<br />

Authentication interface<br />

the Session class’s addPrivilege or addPrivileges method<br />

Since you also have access to these methods, you can call the methods directly,<br />

instead of using the Login widget.


Chapter 12: Access Control<br />

For example, assume that you wanted to modify the sports-news project so<br />

that it did not use the Login widget. You could have users who want to log in<br />

go not to a page containing a Login widget, but directly to the page containing<br />

the login form. You could then change the action of the form so that the form<br />

calls one of the subroutines shown below.<br />

Java<br />

package AccessCtrlJava1;<br />

import com.haht.*;<br />

import com.haht.project.*;<br />

class AuthenticateUser {<br />

public void run(Request aRequest, Response aResponse) {<br />

/* Authenticate the user and assign the user<br />

the privilege Subscribed if the authentication<br />

is successful. */<br />

String userName = aRequest.getURLField("txtUserName");<br />

String password = aRequest.getURLField("txtUserPassword");<br />

String domain = aRequest.getURLField("txtUserDomain");<br />

boolean authenticated = Haht.getSession().<br />

getAuthentication().<br />

authorizeUser(userName, password, domain);<br />

if (authenticated == true) {<br />

Haht.getSession().addPrivilege("Subscribed");<br />

HAHTPage successPage = Haht.getSession().<br />

returnHAHTPageObject("AccessCtrlJava1.HsSuccess");<br />

successPage.run(aRequest, aResponse);<br />

}<br />

else {<br />

HAHTPage failurePage = Haht.getSession().<br />

returnHAHTPageObject("AccessCtrlJava1.HsFailure");<br />

failurePage.run(aRequest, aResponse);<br />

}<br />

}<br />

}<br />

287


Chapter 12: Access Control<br />

HAHTtalk Basic<br />

Sub AuthenticateUser<br />

Dim aRequest As Object<br />

Dim userName As String<br />

Dim password As String<br />

Dim domain As String<br />

Dim authenticated As Boolean<br />

Set aRequest = Haht.getRequest()<br />

userName = aRequest.getURLField("txtUserName")<br />

password = aRequest.getURLField("txtUserPassword")<br />

domain = aRequest.getURLField("txtUserDomain")<br />

authenticated = HahtSession.getAuthentication(). _<br />

authorizeUser(userName, password, domain)<br />

If (authenticated = True) Then<br />

HahtSession.addPrivilege "Subscribed"<br />

HS_Success<br />

Else<br />

HS_Failure<br />

End If<br />

End Sub<br />

Generally, it’s preferable to use the Login widget in your application because<br />

this approach requires less coding and gives you more features. But<br />

occasionally you may need to authenticate users using the Server Object<br />

Model methods.<br />

Letting the Web server authenticate users<br />

In addition to authenticating users against information maintained by the<br />

operating system or information in a user-defined location, you may want to<br />

authenticate users against information maintained by your Web server. In this<br />

case, you don’t use the Login widget or methods defined in the Server Object<br />

Model. You just configure your Web server so that URLs requesting dynamic<br />

or secure-static pages from a <strong>HAHTsite</strong> Application Server cause the Web server<br />

to send an authentication request to the browser.<br />

To use your Web server’s authentication mechanism<br />

1 Configure your Web server to authenticate a user who requests a dynamic<br />

or secure-static page.<br />

288


Chapter 12: Access Control<br />

2 After the user is authenticated, assign the user one or more privileges using<br />

the Session class’s addPrivilege or addPrivileges method.<br />

3 Configure your Application Server’s access-control properties so that its<br />

Authentication Type is None.<br />

Note - If you need a user’s user name for any reason — for<br />

example, you may want to look up a user’s privileges in a<br />

database — you can get it by calling the Request class’s<br />

getServerVariable method to obtain the value of the<br />

environment variable REMOTE_USER. For information about<br />

looking up user privileges in a privilege repository, see<br />

“Granting privileges on a user-name basis” on page 289.<br />

Granting privileges on a user-name basis<br />

The preceding section explained how to require a user to log in to an<br />

application and to grant a user a set of privileges upon a successful login. In<br />

this arrangement, everyone who logs in to the application gets the same<br />

privileges. This approach may work fine for the sports-news project, but other<br />

applications may require that different users get different privileges. For<br />

example, consider any application that accesses a database. Some users should<br />

not be able to access the database at all (no privileges), some people should<br />

have read-only access to the database (“User” privilege), and some people<br />

should be able to read from and write to the database (“User” and “Admin”<br />

privileges). Building on the information presented in earlier sections, this<br />

section explains how to grant privileges on a user-by-user basis.<br />

For this type of scheme to work, you must first create a privilege repository. This<br />

repository can be a database table, but need not be. It could also be an LDAP<br />

directory or a regular file. The only hard-and-fast rule is that the privilege<br />

repository must specify the privileges to be given to a user with a particular<br />

user name.<br />

Once you’ve decided how to implement your privilege repository, there are<br />

several scenarios to consider:<br />

Your application uses a Login widget, and your privilege repository is a<br />

database table.<br />

Your application uses a Login widget, and your privilege repository is not<br />

a database table.<br />

Your application does not use a Login widget.<br />

289


Chapter 12: Access Control<br />

The upcoming sections explain how to handle each of these situations.<br />

Using a Login widget and a database privilege<br />

repository<br />

If you have an application — like the sports-news project described in<br />

“Granting privileges to logged-in users” on page 276 — that assigns all users<br />

who log in the same set of privileges, there are three tasks you’ll have to<br />

perform to have the application assign each user a custom set of privileges read<br />

from a database:<br />

290<br />

Create a database table that contains information about each user’s<br />

privileges.<br />

Configure the Login widget to look up a user’s privileges in a privilege<br />

repository.<br />

Configure the Application Server to look for a user’s privileges in your<br />

database.<br />

The following sections explain in detail how to perform these tasks.<br />

To create the database privilege repository<br />

1 Create a database table named hsSecurityPrivileges.<br />

2 In this table, create the fields shown in the table below.<br />

Field name Description Data type<br />

hsUserid The user’s user ID. This ID does not have<br />

to be unique.<br />

hsPrivilege The name of a privilege belonging to<br />

the user.<br />

Each row in the table specifies one privilege belonging to a user. The Login<br />

widget reads the entire table to obtain a list of a user’s privileges.<br />

3 Enter user names and privileges in the table, one user name and privilege<br />

per row.<br />

If a user has three privileges, you should add three rows to the table for<br />

that user.<br />

To configure the Login widget<br />

1 Open the Login Properties dialog for the Login widget.<br />

String<br />

String


2 Go to the Privileges tab.<br />

3 Select the radio button labeled “Use privilege repository.”<br />

Chapter 12: Access Control<br />

When you choose this setting, the Login widget behaves as follows: After<br />

authenticating a user, the widget opens a connection to a database known<br />

to the Application Server (the database containing the table<br />

hsSecurityPrivileges) and reads the user’s privileges from the appropriate<br />

table using a method of the DBUserProfile class. It then assigns those<br />

privileges to the user’s session.<br />

To configure the Application Server<br />

1 Change your Application Server’s access-control properties so that the<br />

Privilege Repository Type is Database.<br />

2 Supply a DB Privilege Repository Connect String.<br />

If you’re not sure how to write the connection string, you might want to<br />

use the <strong>IDE</strong> to create an ADO connection to the privilege database. When<br />

you create this connection, if you use the <strong>IDE</strong>’s Connection Browser to<br />

point to your database, the <strong>IDE</strong> will create a connection string for you.<br />

You can copy this connection string and paste in into the DB Privilege<br />

Repository Connect String text box.<br />

Using a Login widget and a nondatabase privilege<br />

repository<br />

It’s also possible to use the Login widget with a nondatabase version of the<br />

privilege repository to assign privileges to users. However, to make this work,<br />

you must write a Java class that contains a method that takes a user name as<br />

an argument and returns a set of privileges. This subject is discussed in more<br />

detail in “To create a Java class and make it known to your application” on<br />

page 292.<br />

There are three basic tasks you must perform to have your application assign<br />

each user a custom set of privileges read from a user-defined location:<br />

Configure the Login widget to look up a user’s privileges in a privilege<br />

repository.<br />

Configure the Application Server to look for a user’s privileges in a<br />

user-defined location.<br />

Write a custom user-profile class containing a lookupPrivileges method<br />

that returns a list of privileges for a particular user. And make this class<br />

known to your application.<br />

291


Chapter 12: Access Control<br />

The following sections explain in detail how to perform these tasks.<br />

To configure the Login widget<br />

1 Open the Login Properties dialog for the Login widget.<br />

2 Go to the Privileges tab.<br />

3 Select the radio button labeled “Use privilege repository.”<br />

292<br />

When you choose this setting, the Login widget behaves as follows: After<br />

authenticating a user, the widget checks an Application Server property to<br />

determine whether your privilege repository is in a database or elsewhere.<br />

When it determines that your repository is not in a database, the widget<br />

calls the lookupPrivileges method of a class you’ve written and made<br />

known to your application. (You must write this method since you’re the<br />

only one who knows where and in what format your privileges data is<br />

stored.) Finally, the widget assigns the privileges it retrieves to the user’s<br />

session.<br />

To configure the Application Server<br />

Change your Application Server’s access-control properties so that the<br />

Privilege Repository Type is User Defined.<br />

To create a Java class and make it known to your application<br />

1 In your project’s Package folder, create a Java source file and write your<br />

custom user-profile class. This class must implement the UserProfile<br />

interface and, thus, must define a method lookupPrivileges:<br />

Privileges lookupPrivileges(String aUserID)<br />

The Privileges object returned by this method is a container for a set of<br />

privileges. For more information about the Privileges class, see<br />

“Privileges class” on page 298.<br />

2 Add to your project the code that will enable your application to<br />

determine at runtime which Java class it should use for user-defined<br />

privilege lookup. This task differs to a degree between Java and HAHTtalk<br />

Basic projects.<br />

Java projects. Modify your project’s HahtApplication class by editing the<br />

source file HahtApplication.java. Add to the class’s onStart method<br />

code to identify your custom privilege-lookup class. You do this by calling<br />

the method setUserProfileClassByName.


Java<br />

Chapter 12: Access Control<br />

public void onStart(com.haht.project.ApplicationEvent anEvent)<br />

{<br />

this.setUserProfileClassByName("CustomUserProfile");<br />

}<br />

HAHTtalk Basic projects. Add a code page to your project, and in this file<br />

define a public function called HahtSessionOnStart. This function should<br />

call the Application object’s setUserProfileClassByName method to<br />

identify the name of the user-defined class that will perform the privilege<br />

lookup.<br />

HAHTtalk Basic<br />

Public function HahtSessionOnStart As Boolean<br />

Dim ProfSuccess As Boolean<br />

ProfSuccess = HahtApplication.setUserProfileClassByName _<br />

("CustomUserProfile")<br />

HahtSessionOnStart = ProfSuccess<br />

End Function<br />

Using the Server Object Model<br />

You don’t have to use <strong>HAHTsite</strong>’s Login widget to look up a user’s privileges in<br />

a privilege repository and assign them to the user’s session. Your application<br />

can call the lookupPrivileges method (of a class that implements the<br />

UserProfile interface) and the Session class’s addPrivileges method<br />

directly to accomplish the very same thing. This would be a useful approach<br />

to take if you were using your Web server to perform user authentication, for<br />

example.<br />

The list of steps you must perform to look up and assign privileges in this way<br />

is as follows:<br />

1 Create your privilege repository.<br />

If you want to store information about users and their privileges in a<br />

database table, follow the directions in “To create the database privilege<br />

repository” on page 290. If you choose to store the information elsewhere,<br />

just remember that the Java method that looks up privileges takes a user<br />

name as its argument and returns an object of type Privileges, which<br />

contains a list of privileges. Since you must implement this method<br />

293


Chapter 12: Access Control<br />

294<br />

yourself (if your privilege repository is not a database table), you can store<br />

the data in any format you choose.<br />

2 Configure your Application Server’s Privilege Repository Type and supply<br />

a database connection string, if necessary.<br />

If your privilege repository is a database table, choose a Privilege<br />

Repository Type of Database, and enter the connection string the<br />

Application Server will need to establish a connection with your database.<br />

If your privilege repository is not a database, choose a Privilege Repository<br />

Type of User Defined.<br />

3 If your privilege repository is not a database, implement a custom<br />

user-profile class, and modify your project so that it will know about your<br />

user-profile class at runtime.<br />

See “To create a Java class and make it known to your application” on page<br />

292 for more information about how to perform this step.<br />

4 Add to your application code that calls the lookupPrivileges and<br />

addPrivileges methods.<br />

The example below shows how your application might make these calls.<br />

The example assumes that the user fills in a login form and that the form’s<br />

action is to call a subroutine that authenticates the user and looks up his<br />

or her privileges. The lines highlighted in the subroutine are the ones that<br />

have to do specifically with looking up privileges and assigning them to a<br />

user session.


Java<br />

package AccessCtrlJava1;<br />

import com.haht.*;<br />

import com.haht.project.*;<br />

import com.haht.access.*;<br />

Chapter 12: Access Control<br />

class AuthenticateUser {<br />

public void run(Request aRequest, Response aResponse) {<br />

String userName = aRequest.getURLField("txtUserName");<br />

String password = aRequest.getURLField<br />

("txtUserPassword");<br />

String domain = aRequest.getURLField("txtUserDomain");<br />

Privileges privs = new Privileges();<br />

Session sess = Haht.getSession();<br />

boolean authenticated = sess.getAuthentication().<br />

authorizeUser(userName, password, domain);<br />

if (authenticated == true) {<br />

UserProfile prof = sess.getUserProfile();<br />

try {<br />

privs = prof.lookupPrivileges(userName);<br />

}<br />

catch (com.haht.HahtException except) {<br />

}<br />

String privStrings[] = privs.getStringArray();<br />

sess.addPrivileges(privStrings);<br />

HAHTPage successPage = Haht.getSession().<br />

returnHAHTPageObject("AccessCtrlJava1.HsSuccess");<br />

successPage.run(aRequest, aResponse);<br />

}<br />

else {<br />

HAHTPage failurePage = Haht.getSession().<br />

returnHAHTPageObject("AccessCtrlJava1.HsFailure");<br />

failurePage.run(aRequest, aResponse);<br />

}<br />

}<br />

}<br />

295


Chapter 12: Access Control<br />

Server Object Model methods<br />

<strong>HAHTsite</strong>’s Server Object Model contains a number of classes that define<br />

methods relating to access control: Session, Privileges, and Application.<br />

The model also defines two interfaces — Authentication and UserProfile —<br />

that you make use of when implementing user-defined authentication or<br />

user-defined privilege lookup. The following pages list the relevant methods<br />

of these classes and interfaces.<br />

296<br />

HAHTtalk Basic<br />

Sub AuthenticateUser<br />

Dim aRequest As Object<br />

Dim prof As Object<br />

Dim privs As Object<br />

Dim sessionPrivs As Object<br />

Dim userName As String<br />

Dim password As String<br />

Dim domain As String<br />

Dim authenticated As Boolean<br />

Set aRequest = Haht.getRequest()<br />

userName = aRequest.getURLField("txtUserName")<br />

password = aRequest.getURLField("txtUserPassword")<br />

domain = aRequest.getURLField("txtUserDomain")<br />

authenticated = HahtSession.getAuthentication(). _<br />

authorizeUser(userName, password, domain)<br />

If (authenticated = True) Then<br />

Set prof = HahtSession.getUserProfile()<br />

Set privs = prof.lookupPrivileges(userName)<br />

Set sessionPrivs = HahtSession.getPrivileges()<br />

If (sessionPrivs.merge(privs)) Then<br />

' Check for error here.<br />

End If<br />

HS_Success<br />

Else<br />

HS_Failure<br />

End If<br />

End Sub


Session class<br />

Chapter 12: Access Control<br />

A Session object keeps track of information related to the state of an<br />

application with respect to a single user. The methods of the Session class that<br />

relate to access control are listed below.<br />

Method Description<br />

addPrivilege adds a single privilege to a user’s session<br />

addPrivileges adds a set of privileges to a user’s session.<br />

Available in Java projects only.<br />

getAuthentication gets a reference to the session’s<br />

authentication object. This object may have<br />

been instantiated from the<br />

OSAuthentication class or from a<br />

user-defined authentication class.<br />

getAuthenticationType returns a constant indicating the type of<br />

the session's authentication object: OS<br />

authentication, user-defined<br />

authentication, or none<br />

getPrivileges returns the set of privileges that have been<br />

granted to the current session<br />

getUserProfile gets a reference to the session’s user-profile<br />

object. This object may have been<br />

instantiated from the DBUserProfile class<br />

of from a user-defined class.<br />

hasPrivilege returns true if the user’s session has a<br />

specific privilege<br />

hasPrivilegesForItem returns true if a session has all of the<br />

privileges required to access a particular<br />

project item<br />

removePrivilege removes a privilege from the set of<br />

privileges held by the user’s session<br />

removePrivileges removes some or all of the privileges<br />

associated with the user’s session. Available<br />

in Java projects only.<br />

297


Chapter 12: Access Control<br />

Privileges class<br />

A Privileges object is a container for a set of privileges. The methods listed<br />

below make up the interface to objects of this type.<br />

Method Description<br />

add adds a privilege to a list of privileges<br />

clear removes from a Privileges object all the<br />

privileges it contains at the time of the call<br />

getStringArray returns the privileges contained in a<br />

Privileges object as an array of strings.<br />

Available in Java projects only.<br />

hasAll returns true if the Privileges object<br />

being used to access this method includes<br />

all of the privileges contained in another<br />

Privileges object<br />

hasOne returns true if the Privileges object<br />

being used to access this method includes<br />

any one of the privileges contained in<br />

another Privileges object<br />

has returns true if the Privileges object<br />

being used to access this method contains a<br />

specific privilege<br />

merge merges the contents of two Privileges<br />

objects<br />

remove removes a privilege from a Privileges<br />

object<br />

setStringArray adds to a Privileges object all of the<br />

privileges contained in an array of strings.<br />

Available in Java projects only.<br />

Application class<br />

The Application class provides methods that enable you to set or read the<br />

name of:<br />

298<br />

a user-defined authentication class<br />

a user-defined privilege lookup class


Method Description<br />

Authentication interface<br />

Chapter 12: Access Control<br />

setAuthenticationClassByName enables you to specify the name of the<br />

user-defined authentication class to be<br />

used by the application<br />

setUserProfileClassByName enables you to specify the name of the<br />

user-defined privilege lookup class to be<br />

used by the application<br />

An object instantiated from a class that implements the Authentication<br />

interface is responsible for authenticating a user who is attempting to log in to<br />

an application. The object takes a user ID, a password, and possibly a Windows<br />

NT domain name as input and compares that information with the<br />

information in a user name/password repository. The interface to this object<br />

is shown below.<br />

Method Description<br />

authorizeUser authenticates a user by comparing the user’s<br />

login information with information in a<br />

user name/password repository<br />

UserProfile interface<br />

An object instantiated from a class that implements the UserProfile interface<br />

holds information about the session privileges associated with a particular<br />

user. It gets its information from a database table or a user-defined repository.<br />

The interface to this type of object is shown below.<br />

Method Description<br />

lookupPrivileges reads a repository to determine what<br />

session privileges are to be granted to a<br />

particular user and returns those privileges<br />

as an object of type Privileges<br />

299


Chapter 12: Access Control<br />

300


Connecting to COM<br />

Objects<br />

13<br />

Introduction..................................................................................................302<br />

Calling DLLs .................................................................................................302<br />

Declaring a DLL in HAHTtalk Basic........................................................302<br />

Example DLL declarations.......................................................................303<br />

Mapping HAHTtalk Basic types to DLL data types ................................304<br />

Using COM objects with HAHTtalk Basic ...................................................305<br />

The CreateObject function......................................................................305<br />

A COM Server example ................................................................................306<br />

Background ..............................................................................................307<br />

HAHTMem methods................................................................................307<br />

301


Chapter 13: Connecting to COM Objects<br />

Introduction<br />

If your Web server is running on a Windows NT machine, you can extend the<br />

functionality of your <strong>HAHTsite</strong> applications by connecting the applications to<br />

DLLs and COM objects. (A DLL is a dynamic link library. COM stands for<br />

Component Object Model.) In a <strong>HAHTsite</strong> application, DLLs and COM servers<br />

run as server-side objects (in contrast to client-side objects such as JavaScript<br />

and VBScript).<br />

This chapter explains how to call DLLs and connect to COM/DCOM objects<br />

in a <strong>HAHTsite</strong> Basic project. You can accomplish the same thing in a Java<br />

project using native methods; consult the documentation for your Java<br />

compiler or the <strong>HAHTsite</strong> knowledge base at www.haht.com.<br />

Calling DLLs<br />

The method for calling a DLL from a HAHTtalk Basic application is the same<br />

as calling a DLL from a Visual Basic application:<br />

1 Obtain, from the author of the DLL, the number of DLL functions and<br />

parameters.<br />

2 Use the HAHTtalk Basic Declare statement to declare, typically in the<br />

application’s globals.hbs file or in an include file, the DLL as a HAHTtalk<br />

Basic function or subroutine. In many cases, the DLL’s author will provide<br />

a Basic file with the DLL’s functions and subroutines already declared in<br />

the Basic syntax.<br />

3 Call the function or subroutine from a HAHTtalk Basic code page or HTML<br />

page.<br />

Declaring a DLL in HAHTtalk Basic<br />

The syntax for the HAHTtalk Basic Declare statement is described completely<br />

in the <strong>HAHTsite</strong> on-line help. Here is a summary:<br />

Declare {Sub | Function} name[TypeChar] [CDecl | Pascal ] _<br />

[Lib "LibName$" [Alias "AliasName$"]] _<br />

[([ParameterList])] [As Type]<br />

302


Item Description<br />

Chapter 13: Connecting to COM Objects<br />

Sub | Function If the DLL function is void (the function returns no value),<br />

use “Sub.” If the DLL function returns a value, use<br />

“Function.”<br />

name The name of the DLL function. If the function is called<br />

CalcSalesTax in C/C++, use the same name in the HAHTtalk<br />

Basic declaration.<br />

Cdecl | Pascal Order in which parameters are passed between the calling<br />

program and the DLL. The default ordering is Pascal, which<br />

passes parameters starting from the first parameter. If the<br />

DLL function explicitly uses the Cdecl keyword in its<br />

definition, use the Cdecl keyword in your declaration.<br />

Lib "LibName" “Lib” specifies that the DLL is external to the calling<br />

program.<br />

“LibName” is the name of the DLL (in quotes). “LibName”<br />

can include a path and need not include the .DLL extension.<br />

Alias<br />

"AliasName"<br />

Note - HAHTtalk Basic does not support DLL functions that<br />

return the following data types: Currency, Variant, fixedlength<br />

strings, user-defined types, or COM objects. For more<br />

information, see the Declare topic in <strong>HAHTsite</strong>’s on-line help.<br />

Example DLL declarations<br />

Use an alias when the name of an external routine conflicts<br />

with the name of a HAHTtalk Basic internal routine or when<br />

the external routine name contains invalid characters. The<br />

AliasName parameter must appear within quotes.<br />

ParameterList Any parameters, and their types, sent to the DLL. See<br />

“Mapping HAHTtalk Basic types to DLL data types” on page<br />

304.<br />

As Type If the DLL is void (returns no value) and is declared as a Sub,<br />

do not include this item. If the DLL is declared as a<br />

Function, include the type. The valid return types are:<br />

Integer, Long, String, Single, Double, Date, Boolean, and data<br />

objects.<br />

Here is a the API of a sample DLL written in C, followed by the HAHTtalk Basic<br />

declaration for the DLL.<br />

float __declspec(dllexport) CalcSalesTax(float SaleAmount, _<br />

303


Chapter 13: Connecting to COM Objects<br />

304<br />

float TaxAmount)<br />

Declare Function CalcSalesTax Cdecl Lib "SalesTax" _<br />

(ByVal SaleAmount As Single, _<br />

ByVal TaxAmount as Single) As Single<br />

Here are other examples of HAHTtalk Basic DLL declarations. These DLL calls<br />

are used in the XtremeCatalog module of the Xtreme_Demo in the <strong>HAHTsite</strong><br />

introduction project.<br />

Declare Function LogonUser Lib "advapi32" _<br />

Alias "LogonUserA" (ByVal lpszUsername As String, _<br />

ByVal lpszDomain As String, ByVal lpszPassword As String, _<br />

ByVal dwLogonType As Long, ByVal dwLogonProvider As Long, _<br />

phToken As Long) As Long<br />

Declare Function CloseHandle Lib "kernel32" _<br />

Alias "CloseHandle" (ByVal hObject As Long _<br />

As Long<br />

Mapping HAHTtalk Basic types to DLL data types<br />

Many DLLs are written in C or C++. The next table shows the relationship<br />

between C/C++ data types and HAHTtalk Basic data types.<br />

C Data Type HAHTtalk Basic Data Type<br />

short (16-bit integer) ByVal Integer<br />

long (32-bit integer) ByVal Long<br />

short * (ptr to 16-bit integer) ByRef Integer<br />

long * (ptr to 32-bit integer) ByRef Long<br />

float ByVal single<br />

double ByVal double


C Data Type HAHTtalk Basic Data Type<br />

Chapter 13: Connecting to COM Objects<br />

char * ByVal string<br />

If the DLL is writing to the string, you must preallocate<br />

the string space in HAHTtalk Basic. One<br />

way to do this is:<br />

TheStr = String$(TheMaximumLen,0)<br />

Where TheStr is the string you are passing and<br />

TheMaximumLen is the maximum length to<br />

which the string could be populated.<br />

The String$ function populates the string with<br />

null bytes, which is compatible with the C<br />

language convention for string termination.<br />

structure * ByRef structure_type<br />

Each element in the HAHTtalk Basic structure<br />

must be explicitly defined, for example<br />

TheStr As String*20<br />

Additionally, the DLL must have been built on<br />

single-byte alignment.<br />

Using COM objects with HAHTtalk Basic<br />

You create a COM object (an instance of a COM Server) with the HAHTtalk<br />

Basic function CreateObject function. You can then access the object’s<br />

methods and properties from your HAHTtalk Basic code<br />

Once you have a COM object in a HAHTtalk Basic variable of type Object, you<br />

access the object’s properties and methods using the "." syntax.<br />

The CreateObject function<br />

Syntax<br />

Function CreateObject(COMObjectName) As Object<br />

Description<br />

Creates an instance of the COM Server specified in the COMObjectName<br />

parameter. The supplier of the COM Server is responsible for providing<br />

you with the methods and properties of the server.<br />

305


Chapter 13: Connecting to COM Objects<br />

You must register the COM Server with the Windows Regsvr32 utility, or with<br />

a similar facility such as HAHTtalk Basic’s DLLRegisterServer function.<br />

<strong>HAHTsite</strong> locates ActiveX/COM objects by looking in the registry on the<br />

<strong>HAHTsite</strong> Application Server’s machine. For example, if you use the function<br />

CreateObject("Excel.Application"), <strong>HAHTsite</strong> looks up<br />

Excel.Application in the system registry to find the binary file for that<br />

object.<br />

Parameters<br />

Parameter Type Description<br />

COMObjectName String Registered COM object name<br />

Example<br />

The following subroutine creates a COM Server object called cObj from the<br />

COM Server HAHTMem.<br />

Sub DemoHAHTMem()<br />

Dim cObj As Object<br />

306<br />

' Create an instance of the COM server<br />

Print "Creating An Instance to the HAHTMem Server...";""<br />

Set cObj = CreateObject("HAHTMem.cMemMgr")<br />

'<br />

' Code to use the COM Server.<br />

'<br />

End Sub<br />

A COM Server example<br />

This section describes a simple example of connecting <strong>HAHTsite</strong> to a COM<br />

Server called HAHTMem. The HAHTMem COM Server provides for shared-memory<br />

workspaces among multiple instances of a <strong>HAHTsite</strong> application running on<br />

the same Windows machine.<br />

Note - A project that contains the HAHTMem COM Server is<br />

available online in the HAHT Software knowledge base<br />

(www.haht.com).


Background<br />

Chapter 13: Connecting to COM Objects<br />

One of the features of the <strong>HAHTsite</strong> Application Server is its ability to maintain<br />

state. At a conceptual level, there are different kinds of state you might want<br />

to maintain:<br />

state that is "per-instance" of a <strong>HAHTsite</strong> application. This is the kind of<br />

state you get when you declare a global HAHTtalk Basic variable. Each<br />

StateId (i.e., user) gets his or her own per-instance state. Any global<br />

variables (defined in globals.hbs) are part of that user’s per-instance state.<br />

A change that “User A” makes to his global variable “MyVariable” does<br />

not affect what “User B” gets when she accesses her “MyVariable” global<br />

variable.<br />

state that is shared across all instances of the same application running<br />

on the same machine. For example, information kept in a database table<br />

to which the application attaches falls into this category. However<br />

getting and setting cross-instance values in a database carries the<br />

overhead of accessing the database.<br />

Another approach to sharing state across instances of an application is to<br />

allocate memory that can be accessed by all instances of the application.<br />

In the simplest case, you might simply keep a count of the number of copies<br />

of the application that were active— the number application instances. Or,<br />

you could keep more sophisticated usage statistics.<br />

Another example might be a “chat room” or “bulletin board” application in<br />

which you need to keep a list of currently active users so that all users could<br />

see what other users were logged in. This is what the HAHTMem COM Server<br />

provides—each instance of an application can attach to the COM Server and<br />

get access to a common shared memory area.<br />

HAHTMem methods<br />

Here is a description of the methods provided by the HAHTMem COM Server.<br />

OpenWorkspace — HATHMem manages named workspaces that contain<br />

one or more variables. If an OpenWorkspace command uses a workspace<br />

name that doesn’t exist, the workspace is created. If the workspace<br />

already exists, the in-use count for that workspace is incremented.<br />

OpenWorkspace returns to the caller an ID which is used by the caller for<br />

all subsequent operations against the workspace.<br />

CloseWorkspace — detaches the caller from the workspace. The<br />

workspace's in-use count is decremented by 1. If the workspace in-use<br />

count reaches 0, the workspace is deleted.<br />

307


Chapter 13: Connecting to COM Objects<br />

308<br />

OpenVar — opens a variable in an existing workspace. All variables are<br />

referred to in the syntax of Workspace:Variable, where Workspace is the<br />

workspace name and Variable is the variable name (for example,<br />

FileLocks.MainLogFile). All workspace variables are stored as HAHTtalk<br />

Basic Variant data types in the HAHTMem COM Server.<br />

CloseVar — closes a variable in a workspace.<br />

WriteVar —writes a value to a variable in a workspace.<br />

ReadVar — reads the value of a variable in a workspace.<br />

LockVar — locks access to a workspace variable to the current caller.<br />

Returns True or False depending whether the lock request was successful.<br />

If the lock request returns False, another application currently has the<br />

variable locked, the application should perform an OS Sleep() and then<br />

try again to lock the variable.<br />

UnlockVar — unlocks exclusive access to a workspace variable.<br />

LockWorkspace — locks a workspace for exclusive access by the current<br />

application. Returns True or False depending if Lock request was<br />

successful.<br />

UnlockWorkspace — unlocks a workspace for exclusive access by the<br />

current application.


<strong>HAHTsite</strong> CORBA<br />

Capabilities<br />

14<br />

Overview .......................................................................................................310<br />

Using CORBA with the <strong>HAHTsite</strong> <strong>IDE</strong> .........................................................311<br />

<strong>HAHTsite</strong> as a CORBA client ........................................................................315<br />

<strong>HAHTsite</strong> as a traditional CORBA server .....................................................318<br />

CORBA and the <strong>HAHTsite</strong> Server Object Model .........................................321<br />

Other Information ........................................................................................328<br />

References......................................................................................................330<br />

309


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Overview<br />

<strong>HAHTsite</strong> gives you the ability to integrate Web applications with objects<br />

created using CORBA, the Common Object Request Broker Architecture.<br />

Among other things, this flexible mechanism can be used to:<br />

310<br />

integrate <strong>HAHTsite</strong> Web applications with large-scale and legacy systems<br />

provide a direct connection between a client and the Application Server,<br />

bypassing the Web server<br />

allow external programmatic control over the operation of the<br />

Application Server, including the initiation of <strong>HAHTsite</strong> application<br />

sessions<br />

While <strong>HAHTsite</strong> can be used to create sophisticated Web applications, many<br />

customers already have complex computing environments built over many<br />

years. Often, a major reason for providing Web capabilities is the exposure of<br />

parts of these systems to the external world via the Internet, or access by the<br />

enterprise through an intranet. Integration with CORBA allows <strong>HAHTsite</strong> to<br />

connect new Web applications with a wide variety of existing enterprise<br />

systems.<br />

What is CORBA?<br />

This chapter assumes familiarity with CORBA programming. CORBA (the<br />

Common Object Request Broker Architecture) is the leading method for<br />

building large-scale, distributed objects and applications. It is defined by the<br />

Object Management Group, a consortium of over 800 companies. More<br />

information is available from the OMG Web site: http://www.omg.org.<br />

What does <strong>HAHTsite</strong>/CORBA interoperation mean?<br />

The software bundled with <strong>HAHTsite</strong> includes Inprise (formerly Visigenic)<br />

VisiBroker for Java. <strong>HAHTsite</strong> applications written using the <strong>HAHTsite</strong> Server<br />

Object Model can incorporate calls to the VisiBroker interfaces and thereby act<br />

as standard CORBA objects. Using CORBA’s built-in capabilities, they can<br />

communicate with and become part of an enterprise built of distributed<br />

CORBA objects.<br />

Information from remote CORBA systems, such as mainframes, can be<br />

obtained by these CORBA-enhanced <strong>HAHTsite</strong> applications. This data can<br />

then be used in any manner within the <strong>HAHTsite</strong> application, providing a<br />

flexible, complete method to present enterprise information on the Web.


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

In addition to this peaceful coexistence, there are several extensions to the<br />

<strong>HAHTsite</strong> Server Object Model that provide CORBA interfaces, allowing<br />

CORBA systems to operate directly on some <strong>HAHTsite</strong> server objects. This level<br />

of integration allows an external, non-<strong>HAHTsite</strong> application to connect as a<br />

CORBA client to a CORBA-enabled <strong>HAHTsite</strong> application acting as a CORBA<br />

server. Such a client can initiate and control a <strong>HAHTsite</strong> session, making use<br />

of session capabilities such as automatic timeout.<br />

CORBA can also provide a Java applet running in a browser the ability to<br />

communicate with a <strong>HAHTsite</strong> application without the overhead of the HTTP<br />

protocol. For applets requiring substantial or very dynamic data from the<br />

server, this can be very beneficial.<br />

Outside the support in <strong>HAHTsite</strong> for writing CORBA-enabled applications,<br />

<strong>HAHTsite</strong> is not built on and does not directly depend on CORBA. If you have<br />

no need to develop CORBA-based applications, you need not install VisiBroker<br />

for Java.<br />

Using CORBA with the <strong>HAHTsite</strong> <strong>IDE</strong><br />

The <strong>HAHTsite</strong> <strong>IDE</strong> can be used to build VisiBroker-enhanced <strong>HAHTsite</strong><br />

applications, handling the details of compilation of Java and CORBA code,<br />

and putting the compiled classes in the proper location for use. In order to<br />

accomplish this, the <strong>IDE</strong> provides a number of configuration points.<br />

Handling CORBA projects<br />

If the Application and Session objects are to be exposed as CORBA objects,<br />

the check box “Expose Session and Application Objects to CORBA” must be<br />

selected from the project’s Edit > Properties dialog box. Setting this check box<br />

causes the <strong>IDE</strong> to generate CORBA-enabled HahtApplication and<br />

HahtSession classes when the project is built, using the VisiBroker TIE<br />

mechanism. This is not required if the application represents a CORBA client<br />

or a straightforward CORBA server that creates its own objects.<br />

You add an IDL file to the project in the same way that you add other file types.<br />

File > New > IDL will create a new IDL file that can be added to the project, or<br />

you can import an existing IDL file from the main File menu or by<br />

right-clicking in the Project view.<br />

When you publish a CORBA-enabled project, the IDL compiler produces a<br />

number of Java files in the staging directory. These files are compiled, and the<br />

311


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

resulting classes are stored on the Web server or Application Server, depending<br />

on how the <strong>IDE</strong> is configured. As with other file types, individual IDL files may<br />

be selected and compiled by using the IDL > Build menu.<br />

312<br />

Note - The Visibroker IDL compiler is not included with<br />

<strong>HAHTsite</strong>.<br />

Setting options for CORBA<br />

The addition of CORBA capabilities adds several dialogs to the <strong>IDE</strong><br />

configuration. A new Java file type is created for CORBA projects. The <strong>IDE</strong><br />

distinguishes Java code that is to be run on the Application Server from code<br />

that is to be run elsewhere, and different Java compilers may be specified for<br />

the two types of Java files. Under the Tools > Options... > Java > Add dialog, a<br />

Java compiler may be added for Java files that are part of CORBA projects. The<br />

setup of the default Java compiler profile for CORBA-generated Java files sets<br />

up the proper Java compiler switches and places the necessary Visigenic JAR<br />

files (vbjapp.jar and vbjorb.jar) in the compiler’s Class Path argument.<br />

There is a new dialog under Tools > Options... > CORBA that allows IDL<br />

compilers to be configured. Different IDL compilers may be specified<br />

depending on whether the output code is to be run on the Application Server<br />

or elsewhere. As with the Java compilers, different compiler options may be set<br />

on an IDL compiler using the Add or Modify buttons. A typical use might be<br />

to instruct the IDL compiler to produce ORB-independent code if the<br />

application stubs and skeletons are to be compiled with compilers from more<br />

than one ORB vendor.


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Note - For detailed instructions on how to add or modify an<br />

IDL compiler profile, see Chapter 2, “Using the <strong>IDE</strong>/IP’s<br />

Windows and Toolbars,” in the <strong>HAHTsite</strong> <strong>IDE</strong> and IP User’s<br />

<strong>Guide</strong>.<br />

For an individual project, the Edit > Properties > CORBA Compilers dialog<br />

allows you to override the IDL compiler defaults just described. By choosing<br />

an IDL compiler (the default one is the IDL-to-Java Visibroker compiler) and<br />

clicking Modify, you can change which compiler is used to translate IDL files<br />

to Java. You can also modify the settings used for the IDL compilation process,<br />

such as the root directory and options to the compiler<br />

313


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

.<br />

By default, the VisiBroker IDL compiler generates several Java files for each<br />

CORBA interface, placing them in the staging directory. The following class<br />

files are generated when these files are compiled with the CORBA Java<br />

compiler.<br />

File Name File Type<br />

module_name\interface_name.class Both<br />

module_name\_st_interface_name.class Stub<br />

module_name\_tie_interface_name.class Both<br />

module_name\interface_nameImplBase.class Skeleton<br />

module_name\interface_nameHelper.class Stub<br />

module_name\interface_nameHolder.class Skeleton<br />

module_name\interface_nameOperations.class Skeleton<br />

module_name\_example_interface_name Skeleton<br />

Not all classes are necessarily generated for each IDL interface, depending on<br />

the settings of the IDL compiler options.<br />

For each IDL file, properties may be set to determine where the compiled Java<br />

classes will be placed. Right-click on the IDL file and choose Properties to bring<br />

up the IDL Properties dialog. By default, all classes are placed in the<br />

Application Server’s staging directory. The interface may be used to specify<br />

314


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

whether the stub classes (those required for a CORBA client) are compiled to<br />

the Application Server, the Web server, or both. The same choices are available<br />

for the skeleton classes (those required for a CORBA server).<br />

<strong>HAHTsite</strong> as a CORBA client<br />

<strong>HAHTsite</strong> allows you to build CORBA clients in the <strong>IDE</strong> and to run those<br />

clients in the Application Server. The CORBA IDL files for a particular project<br />

may be imported or created using the <strong>HAHTsite</strong> <strong>IDE</strong> editor. IDL files are<br />

recognized by the <strong>IDE</strong>. When the project is published, the IDL compiler is<br />

invoked to produce the Java client stubs and server skeletons. <strong>HAHTsite</strong> places<br />

the compiled stub classes in their appropriate location in the <strong>HAHTsite</strong><br />

directory hierarchy.<br />

A common, straightforward use of CORBA within <strong>HAHTsite</strong> applications is to<br />

provide a Web “front-end” for data from enterprise CORBA applications. Such<br />

data might be a customer’s order information, normally residing on a<br />

mainframe. In this case, the <strong>HAHTsite</strong> Application Server runs code that acts<br />

as a CORBA client, connecting to a CORBA server object outside of <strong>HAHTsite</strong>.<br />

315


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Example: Building a <strong>HAHTsite</strong> CORBA client<br />

Imagine a legacy system containing a database with customer names and<br />

addresses, with access keyed to an account number. Typically, if the system is<br />

wrapped using CORBA, an IDL file will already exist describing the interfaces<br />

exposed by the system. In our simple example, the IDL file might look like<br />

this:<br />

Java<br />

module CustomerDB {<br />

interface Customer {<br />

attribute string last_name;<br />

attribute string first_name;<br />

attribute string address1;<br />

attribute string address2;<br />

};<br />

interface DB {<br />

Customer getCustomerFromAcct(in string account);<br />

string getInfoBanner();<br />

};<br />

};<br />

In practice, the IDL file would be much larger than the one defined here, but<br />

somewhere in it would be fields like the name and address for a customer, and<br />

a method to get the customer object from the database.<br />

Imagine a simple <strong>HAHTsite</strong> project containing a single Web page that allows<br />

the user to type in the account number and have the customer name and<br />

address displayed on the page.<br />

316


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Initialization of the CORBA ORB in the client can occur at any time; a<br />

convenient place to put the CORBA code is in Application.onSessionStart.<br />

All you have to do at this point is to bind to the server object. The Java<br />

application might contain code similar to this:<br />

Java<br />

// Make customer_database available through Application<br />

CustomerDB.DB customer_database;<br />

public void onSessionStart(com.haht.project.SessionEvent anEvent)<br />

{<br />

try {<br />

// Initialize the ORB<br />

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();<br />

// Create the DB object - Example1 is the name of the<br />

// database server<br />

customer_database = CustomerDB.DBHelper.bind("Example1");<br />

}<br />

catch(org.omg.CORBA.SystemException e) {<br />

System.err.println(e);<br />

}<br />

}<br />

Normally, one would probably obtain the customer account number as an<br />

input on the Web page — this can be done via JavaScript or from an applet. In<br />

this example, you might simply generate a random account number from a list<br />

of available ones. The code to do this is in the application as well.<br />

Java<br />

public java.lang.String getRandomAcct() {<br />

java.lang.String account_numbers[] =<br />

{"A09133F6", "B72553Z9", "C29943I7", "D28473W2",<br />

"E27723E6", "F23884K8", "G23847B2", "H23847O6",<br />

"I23984O2", "J29348W9", "K84724Z3", "L99283F9",<br />

"M73624G6", "N22731A1", "O88247Y2", "P83472P1",<br />

"Q24257Z0", "R82634D1", "S23523S9", "T23487U6"};<br />

Random random = new Random();<br />

int randval = random.nextInt();<br />

if (randval < 0) randval = -randval;<br />

randval = randval % account_numbers.length;<br />

return account_numbers[randval];<br />

}<br />

317


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

In order to get the information on the page, you place a server-side statement<br />

in the page.<br />

Java<br />

Assuming the <strong>HAHTsite</strong> Application Server is running, and that the example<br />

CORBA server and Smart Agent are running, the first read of the page in this<br />

project will cause the session to be initiated, calling the CORBA client<br />

initialization code. Each read of the page will use the reference to the customer<br />

database to get the customer information, placing the information into the<br />

page.<br />

<strong>HAHTsite</strong> as a traditional CORBA server<br />

<strong>HAHTsite</strong> applications can also act as CORBA servers. Using CORBA,<br />

server-side applications can make callbacks into client applets, or send events<br />

that clients are registered to receive so that clients can be notified of changes<br />

in application status without requiring any action by the user or the overhead<br />

of polling by the applet.<br />

There are two basic methods that may be used to initiate a CORBA server<br />

within the <strong>HAHTsite</strong> Application Server. The traditional method — discussed<br />

in this section — follows the standard CORBA paradigm where the CORBA<br />

server is started by the <strong>HAHTsite</strong> application, initializing its objects. CORBA<br />

clients bind to objects in this server using a well-known name via the Naming<br />

Service or Smart Agent. The other method, in which the CORBA server uses<br />

the capabilities of a <strong>HAHTsite</strong> session, is discussed in “CORBA and the<br />

<strong>HAHTsite</strong> Server Object Model” on page 321.<br />

318<br />

// First, print out today’s banner from the database server<br />

Application app = com.haht.Haht.getApplication();<br />

out.println(app.customer_database.getBanner()+"");<br />

out.println(app.getRandomAcct());<br />

out.println(app.customer_database.getName());<br />

out.println(app.customer_database.getAddress1());<br />

out.println(app.customer_database.getAddress2()+"");


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

CORBA servers written in this traditional fashion are identical to everyday<br />

CORBA servers, with a few exceptions:<br />

The CORBA server doesn’t have a main method, since it’s started in the<br />

<strong>HAHTsite</strong> application in the Session.onStart method.<br />

You can use the <strong>HAHTsite</strong> <strong>IDE</strong> to build and publish the server.<br />

Server control is handled via the <strong>HAHTsite</strong> Application Server<br />

administration.<br />

The CORBA server inherits automatic restart and failover capabilities<br />

by running as part of the <strong>HAHTsite</strong> application.<br />

Like most simple CORBA systems, many clients bind to a single server object.<br />

Clients can be applets, CORBA client applications, or any CORBA-enabled<br />

<strong>HAHTsite</strong> applications.<br />

Example: Using CORBA to hold <strong>HAHTsite</strong> global state<br />

A simple use for a CORBA server running in <strong>HAHTsite</strong> is the storage of<br />

information to be shared between multiple invocations of the <strong>HAHTsite</strong><br />

application. Such a server might store long-term user information, or<br />

cross-project data, acting as a “service object.” Here, both the CORBA server<br />

and client are running as applications in the <strong>HAHTsite</strong> Application Server.<br />

Because of CORBA, whether the client and server are located on the same<br />

Application Server is not important. This client looks essentially like the one<br />

in the previous example.<br />

Here, the server simply acts as a time accumulator for storing numbers of<br />

minutes on a per-customer basis. The IDL file is shown below.<br />

319


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Java<br />

module ServerStats {<br />

interface TimeRecord {<br />

void addMinutes(in string user, in long minutes);<br />

void resetMinutes(in string user);<br />

long getMinutes(in string user);<br />

};<br />

};<br />

When you implement this interface in the server, you must follow certain<br />

naming conventions and put your source files in the correct folder. First, create<br />

a subfolder in the Packages folder and give it the name of your module. Then<br />

put your source files in this subfolder, and give them names of the form<br />

interfaceNameImpl.java. For example, the source code for the<br />

TimeRecordImpl class should be placed in TimeRecordImpl.java.<br />

The client code also looks similar that shown in the last example.<br />

Java<br />

public void onSessionStart(com.haht.project.SessionEvent anEvent)<br />

{<br />

// Initialize the ORB<br />

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();<br />

// Bind to the Superglobal time record<br />

ServerStats.TimeRecord record =<br />

ServerStats.TimeRecord.bind(orb, "Example2");<br />

// Get the number of minutes of usage for this user from the<br />

// user<br />

long minutes = record.getMinutes(user_id);<br />

// Get the customer information from the Database<br />

}<br />

Put the CORBA server part in the application’s onSessionStart routine, and<br />

create the new TimeRecord class that implements the IDL interface:<br />

320


Java<br />

Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

public void onSessionStart(com.haht.project.SessionEvent anEvent)<br />

{<br />

orb = org.omg.CORBA.ORB.init();<br />

boa = orb.BOA_init();<br />

timeRecord = new TimeRecordImpl("Example2");<br />

boa.obj_is_ready(timeRecord);<br />

}<br />

To start this CORBA server, you should configure the Applications Server to<br />

run the CORBA server as a service when a particular Server Group is started.<br />

For information on performing this configuration, see Chapter 3 in the<br />

<strong>HAHTsite</strong> Application Server Administration <strong>Guide</strong>.<br />

Note - You should not run the CORBA server and a <strong>HAHTsite</strong><br />

application that is a client of that server in the same server<br />

process. A simple way to prevent this from happening is to<br />

establish a Server Group dedicated running to CORBA-server<br />

services.<br />

One other point. By default, a CORBA service can time out. You can prevent<br />

this from happening by setting the server’s timeout value to -1.<br />

CORBA and the <strong>HAHTsite</strong> Server Object<br />

Model<br />

In addition to the simple CORBA clients and server discussed so far, it’s<br />

possible to create CORBA servers that provide clients with access to <strong>HAHTsite</strong><br />

Server Object Model objects and clients that take advantage of those services.<br />

The following subsections discuss this type of client and server further.<br />

Using the <strong>HAHTsite</strong> Server Object Model in a <strong>HAHTsite</strong><br />

CORBA server<br />

“<strong>HAHTsite</strong> as a traditional CORBA server” on page 318 discussed one type of<br />

CORBA server. A second type of CORBA server may be written by using the<br />

capabilities of the <strong>HAHTsite</strong> session. Such a “session-oriented” CORBA server<br />

differs from the type described earlier in that it is initiated as part of a<br />

321


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

<strong>HAHTsite</strong> session. Since each session has its own private set of objects, each<br />

CORBA server created in this manner has an independent set of objects as well.<br />

A CORBA server constructed in this fashion may be started in two ways. The<br />

initial HTTP reference to a page representing this session will cause the session<br />

to be invoked via the standard hsrun mechanism. The second method allows<br />

a CORBA client to initiate the session through use of a predefined<br />

ServerGroup object.<br />

You must include an IDL file describing the CORBA interface for each Java<br />

class you wish to expose via CORBA. If the session is to be accessible from<br />

CORBA, the project property must be set to indicate that the Session object is<br />

to be exposed as a CORBA object whenever a session of the application is<br />

initiated.<br />

When a method in a Java class in a <strong>HAHTsite</strong> application is invoked via<br />

CORBA, it is not running a <strong>HAHTsite</strong> dynamic page, and therefore does not<br />

have access to the <strong>HAHTsite</strong> Page, Request, and Response objects. However, it<br />

could have access to the Application and Session objects if they were passed<br />

to the object as arguments of a method.<br />

The methods of the Session class shown below enable you to register a server<br />

object as a visible CORBA object and to deactivate a CORBA object.<br />

Method Description<br />

Corba_obj_is_ready Call this instead of obj_is_ready on the BOA,<br />

and the session will manage the object,<br />

deactivating it when the session is done. It<br />

makes calls to initialize the ORB and BOA the<br />

first time it is called within an application.<br />

Corba_deactivate_obj This method removes the object from control of<br />

the session.<br />

Accessing the <strong>HAHTsite</strong> Server Object Model from a<br />

CORBA client<br />

A CORBA client of any type can reference the <strong>HAHTsite</strong> Application, Session,<br />

and ServerGroup classes of a <strong>HAHTsite</strong> CORBA server as CORBA objects. The<br />

set of methods available to perform on these objects from a CORBA<br />

application is defined in terms of CORBA IDL. It can be compiled into<br />

applications in any CORBA-supported language.<br />

The IDL describing the methods and classes available to CORBA programs<br />

resides in the file <strong>IDE</strong>InstallDir\scripts\HSCorbaInterface.idl.<br />

322


HSCorbaInterface.idl<br />

module com<br />

{<br />

module haht<br />

{<br />

module corba<br />

{<br />

interface Application<br />

{<br />

string getName();<br />

void writeLog (<br />

in string aMessage);<br />

Object getCORBAObject(<br />

in string varName);<br />

string getString(<br />

in string varName);<br />

void putString(<br />

in string varName,<br />

in string varValue);<br />

void remove(<br />

in string varName);<br />

void lock();<br />

void unlock();<br />

};<br />

interface Session<br />

{<br />

string getStateId();<br />

string getServerGroupName();<br />

string getHostName();<br />

string createPageURL(<br />

in string aURL,<br />

in string aSubSiteName);<br />

string createMapURL(<br />

in string aURL,<br />

in string aSubSiteName);<br />

string createFileURL(<br />

in string aURL,<br />

in string aSubSiteName);<br />

Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

323


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

HSCorbaInterface.idl<br />

};<br />

324<br />

};<br />

};<br />

};<br />

string createStaticURL(<br />

in string aURL,<br />

in string aSubSiteName);<br />

string getURL(<br />

in string projectId,<br />

in string defaultStr,<br />

in string queryStr);<br />

string getStaticURL();<br />

boolean hasPrivilege(<br />

in string aPrivilege);<br />

Object getCORBAObject(<br />

in string varName);<br />

string getString(<br />

in string varName);<br />

void putString(<br />

in string varName,<br />

in string varValue);<br />

void remove(<br />

in string varName);<br />

void lock();<br />

void unlock();<br />

void setUsername(<br />

in string aUsername);<br />

string getUsername();<br />

void keepAlive();<br />

void setTimeout(<br />

in long Timeout);<br />

long getTimeout();<br />

Application getCORBAApplication();<br />

interface ServerGroup<br />

{<br />

Session createApplicationSession(in string<br />

ApplicationPath);<br />

};


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

These interfaces contain a subset of the methods available in the analogous<br />

classes in the Server Object Model. The behavior of the methods described in<br />

the interfaces is identical to their counterparts in the com.haht.project<br />

package.<br />

Client/server communication<br />

The com.haht.project.Session and com.haht.project.Application classes<br />

define a few additional CORBA-related methods. These methods facilitate<br />

client/server communication.<br />

Method Description<br />

getCORBAApplication returns the Application object that has been<br />

exposed to CORBA. This convenience function<br />

allows a CORBA client to get a reference to the<br />

Application object from the Session<br />

reference.<br />

getCORBAObject returns a handle to a CORBA object. Can be<br />

called in the client to obtain a reference to a<br />

CORBA server object (posted with the put<br />

command) without having to bind the object in<br />

the server.<br />

put posts an arbitrary Java object (in this case, a<br />

CORBA object) associated with a name. This<br />

object can be retrieved from the client side.<br />

putString posts a Java String associated with a name<br />

getString returns a string posted with the putString<br />

command<br />

By using these interfaces, CORBA applications can pass CORBA objects<br />

between the client and server without having to contact the Naming Service<br />

or SmartAgent. CORBA must be enabled in the project for these routines to<br />

work properly.<br />

Example: Using CORBA in a session initiated via HTTP<br />

CORBA can be used as a convenient way to set up a non-HTTP connection<br />

between the Web client and the Application Server. See the figure below.<br />

325


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Once the <strong>HAHTsite</strong> application is initiated, a Java applet on the dynamic page<br />

can be connected back to the Session object via CORBA by performing the<br />

following steps:<br />

1 The dynamic HTML page should use the Session.getStateId method to<br />

obtain the session’s State ID.<br />

2 JavaScript on the page can pass the state ID as an argument to a method of<br />

an applet on the page.<br />

3 The applet can make the CORBA calls to initialize the ORB and bind to the<br />

Session object on the server. This returns an object reference to the<br />

application’s session object.<br />

The code for the applet method would look something like:<br />

Java<br />

public void connectToSession(String StateId) {<br />

// Initialize the ORB<br />

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);<br />

// Bind to the Session<br />

Session session =<br />

com.haht.corba.SessionHelper.bind(orb,StateId);<br />

// Retrieve a CORBA object for use in the applet<br />

MyCorbaObject my_corba_object =<br />

(MyCorbaObject)session.getCorbaObject("my_corba_object");<br />

// Get another object using the bind() technique<br />

MyOtherCorbaObject my_other_corba_object =<br />

MyOtherCorbaObjectHelper.bind<br />

(orb,"my_other_corba_object");<br />

...<br />

326


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Example: Initiating a <strong>HAHTsite</strong> application session with<br />

CORBA<br />

A <strong>HAHTsite</strong> application session can also be initiated by a CORBA client. See the<br />

figure below.<br />

In order to accomplish this, the client must follow the steps:<br />

1 Initialize the CORBA ORB and bind to the ServerGroup object. This<br />

requires you to know the name of the ServerGroup object. Usually, the<br />

name is generated during the <strong>HAHTsite</strong> installation process. It should be<br />

available from the <strong>HAHTsite</strong> system administrator.<br />

2 Invoke the createApplicationSession method on the ServerGroup<br />

object. This starts a session of the specified application and returns a<br />

CORBA reference to the new application Session object.<br />

The code for such a CORBA client might contain something like:<br />

327


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

Java<br />

public void createSession() {<br />

// Initialize the ORB<br />

org.omg. CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);<br />

// Bind to the <strong>HAHTsite</strong> ServerGroup object<br />

com.haht.corba.ServerGroup servergroup =<br />

com.haht.corba.ServerGroupHelper.bind(orb, "webapps");<br />

// Create the appliation session and get a reference to it<br />

Project1.HAHTSession session =<br />

servergroup.createApplicationSession<br />

("Project1/Project1.html");<br />

...<br />

}<br />

328<br />

Note - In order for this method to work, the <strong>HAHTsite</strong> system<br />

administrator must enable application sessions to be started<br />

using CORBA. By default, this capability is disabled,<br />

preventing a session from being initiated.<br />

Other Information<br />

This section presents some miscellaneous information about <strong>HAHTsite</strong>’s<br />

CORBA capabilities. It discusses:<br />

using the VisiBroker ORB with other ORBs<br />

using CORBA in HAHTtalk Basic projects<br />

installing and configuring VisiBroker<br />

VisiBroker’s SmartAgent and the CORBA Naming Service<br />

VisiBroker’s GateKeeper software<br />

Interoperability with other ORBS<br />

<strong>HAHTsite</strong> applications built using VisiBroker can connect to and exchange<br />

data with applications built using any CORBA 2.0 ORB. The communication<br />

protocol used to connect the ORBS (Internet Inter-Object Protocol - IIOP) is<br />

standardized and allows interworking between different vendors’ ORBs. The<br />

VisiBroker IDL compiler idl2java must be run with the -strict


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

command-line option in order to generate stubs that will work with other<br />

ORBs.<br />

Using CORBA with HAHTtalk Basic<br />

Although CORBA services are not directly available from HAHTtalk BASIC, it<br />

is still possible to link with CORBA-enabled systems from these applications.<br />

Using the CreateJavaObject call in HAHTtalk, you can create a Java class that<br />

can in turn make CORBA calls exactly as described above. Using this<br />

technique, it is possible to make CORBA clients and servers in HAHTtalk Basic<br />

applications.<br />

VisiBroker installation and configuration<br />

The setup for the Application Server allows you to install VisiBroker for Java as<br />

a custom installation option.<br />

In order for <strong>HAHTsite</strong> applications to act as CORBA clients, VisiBroker for Java<br />

must be installed on the Background Host. In a distributed configuration, it<br />

must be installed on each Background Host, although the osagent (if used)<br />

need only run on one Background Host. If <strong>HAHTsite</strong> applications are to be<br />

started as CORBA servers by external CORBA clients, VisiBroker for Java must<br />

also be installed on each of the Foreground Hosts.<br />

By default, the VisiBroker runtime .jar files are included on the System Java<br />

Classpath for the Server Group. They are required for CORBA operation and<br />

should not be removed from the classpath.<br />

VisiBroker SmartAgent and the CORBA Naming Service<br />

The VisiBroker for Java software includes the Inprise implementation of the<br />

standard CORBA Naming Service. It also includes a simple object registry<br />

called osagent or SmartAgent. Licenses for both are included with <strong>HAHTsite</strong>.<br />

The <strong>HAHTsite</strong> Application Server allows the use of either Naming Service or<br />

SmartAgent, but the <strong>HAHTsite</strong> Server Object Model objects such as<br />

Application and Session are only available to the programmer through the<br />

SmartAgent.<br />

VisiBroker GateKeeper<br />

The Java “sandbox” security model allows an unsigned Java applet to connect<br />

only to the server from which it was invoked. The VisiBroker GateKeeper<br />

software permits applets to connect to other servers. If your <strong>HAHTsite</strong> system<br />

is configured with separate Foreground and Background Hosts, you will need<br />

329


Chapter 14: <strong>HAHTsite</strong> CORBA Capabilities<br />

to employ the VisiBroker GateKeeper to allow CORBA connection between<br />

CORBA-enabled applets and the <strong>HAHTsite</strong> servers. This is true even if no<br />

firewall exists between the applets and application. The VisiBroker GateKeeper<br />

software and license are included with <strong>HAHTsite</strong>.<br />

References<br />

These two documents are available with the VisiBroker software and are also<br />

available for download from the Inprise Web page:<br />

330<br />

VisiBroker for Java Programmer’s <strong>Guide</strong><br />

VisiBroker for Java Reference Manual


Debugging<br />

Server-side Code<br />

15<br />

Introduction..................................................................................................332<br />

Requirements for debugging ........................................................................332<br />

Starting a debugging session ........................................................................333<br />

To start a debugging session....................................................................333<br />

To begin debugging at a static page........................................................334<br />

To stop a debugging session....................................................................335<br />

Debugging a code page.................................................................................336<br />

Executing code in the debugger..............................................................336<br />

Single-stepping.........................................................................................337<br />

Procedure-stepping ..................................................................................338<br />

Using breakpoints....................................................................................338<br />

The debug windows......................................................................................340<br />

Debug output panel.................................................................................341<br />

Variable window ......................................................................................341<br />

Watch window.........................................................................................343<br />

Call Stack window ...................................................................................344<br />

Threads window ......................................................................................345<br />

331


Chapter 15: Debugging Server-side Code<br />

Introduction<br />

This chapter explains how to use the <strong>IDE</strong>/IP debugger to find errors in<br />

<strong>HAHTsite</strong> server-side code. Debugging of both Java and HAHTtalk Basic<br />

projects is supported. In addition to debugging locally, in the development<br />

environment, <strong>HAHTsite</strong> supports remote debugging of dynamic Web pages,<br />

allowing you to debug dynamically created Web pages in the deployed<br />

environment.<br />

Requirements for debugging<br />

You can debug a project’s dynamic code pages (server-side code) running in<br />

the <strong>HAHTsite</strong> Application Server from any Internet-connected client, using<br />

the <strong>IDE</strong>/IP. Projects can also be debugged locally in the Application Server:<br />

Developer Edition. The following requirements must be met:<br />

332<br />

The pages to be debugged must have been published.<br />

The Application Server (or the Application Server: Developer Edition)<br />

must be running.<br />

The Application Server must have at least one debug process enabled.<br />

In the Application Server, accounts and privileges must be set up to<br />

permit debugging and to control the number of active debug sessions<br />

allowed. You must have an account and debugging privileges on the<br />

server machine to start a debug session. When you are debugging using<br />

the Application Server: Developer Edition, account privileges are not<br />

required.<br />

For information on enabling debug processes and administering accounts<br />

and privileges, refer to the <strong>HAHTsite</strong> Application Server Administration <strong>Guide</strong>,<br />

Chapter 3, “Performing Administrative Tasks.”<br />

Java projects must have been built in debug mode.<br />

Note - Debugging is not supported for server-side Java code in<br />

a HAHTtalk Basic project. The debugger treats invocations of<br />

Java methods as a single HAHTtalk Basic statement.


Chapter 15: Debugging Server-side Code<br />

A special case: debugging HAHTtalk Basic stand-alone<br />

programs<br />

A HAHTtalk Basic code page with a main subroutine can be debugged without<br />

being published. This type of code page does not represent a dynamic HTML<br />

page, but is a stand-alone program.<br />

Starting a debugging session<br />

Debugging sessions may be run against a local site, using the Application<br />

Server: Developer Edition during project development. Debugging sessions<br />

may also be run against a remote site, using the Application Server. This<br />

configuration allows debugging in a deployment situation.<br />

To start a debugging session<br />

1 Open the project that you want to debug.<br />

2 Select Project > Debug From Site, or select the Start button from the<br />

Code and Scripts Tools toolbar. The Debug From Site dialog appears.<br />

333


Chapter 15: Debugging Server-side Code<br />

3 Enter your user name, domain and password. If the Application Server is<br />

installed on a UNIX system, leave the domain field blank. If “Allow<br />

Anonymous Debug” is set on the Application Server, or you are using the<br />

Application Server: Developer Edition, you can leave all three fields blank.<br />

The Application Server: Developer Edition does not support<br />

authentication.<br />

4 Specify an unused IP port on your system. The debugger uses two<br />

consecutive ports (7000 and 7001 are the defaults.) If you are accessing the<br />

Application Server through a firewall, be sure to specify a port that is<br />

configured to route back to your system.<br />

5 Select the page to use as a starting point for the debug session. You can<br />

select any page in the project.<br />

6 Click OK.<br />

334<br />

As the <strong>IDE</strong> establishes a connection with the server, status messages are<br />

displayed in the Output window.<br />

To begin debugging at a static page<br />

1 If you select a static page as the start page, the browser displays a page that<br />

prompts you to start the debugging process. The URL of the page indicates<br />

the page is being run by a debug process of the Application Server.


Chapter 15: Debugging Server-side Code<br />

2 Click the link labeled Click Here to Debug to start the debugging session.<br />

Clicking on this link notifies the Application Server to start the debugger<br />

when a dynamic page is executed.<br />

The static page selected as the starting point for the debug session will be<br />

displayed in the browser.<br />

3 Navigate through the Web site to the dynamic page that you want to<br />

debug.<br />

When a dynamic page is requested by the browser, the execution of the<br />

Application Server program is paused immediately before the first<br />

statement of the code page.<br />

To stop a debugging session<br />

While in a debug session, click the End button on the Code and<br />

Scripts Tools toolbar.<br />

Tip - If the End button is activated, you are in a debug session.<br />

If the End button is not activated, you are not in a debug<br />

session. When the buttons to single-step and procedure-step<br />

are active, you are in a debugging session and program<br />

execution is paused. If you are in a debug session and the<br />

single-step and procedure-step buttons are not activated, the<br />

program is running.<br />

335


Chapter 15: Debugging Server-side Code<br />

Debugging a code page<br />

The Server-side Code view of the HTML editor displays the code used to<br />

generate the HTML page. In a debugging session, you can run the application<br />

until a breakpoint is encountered as well as step through the code as it is<br />

executed. When you step through a code page, the HTML editor displays a<br />

yellow arrow to the left of the next line of code that will be executed.The<br />

debugger allows you to step through code pages using single-step, using<br />

procedure-step and by setting breakpoints.<br />

The debug commands are available in the Debug menu on the main toolbar.<br />

The Debug menu is visible only when the HTML editor is in the Server-side<br />

Code view, when you’re viewing a code page, and when a debug session is<br />

active. Each of the commands in the Debug menu is also represented by a<br />

button on the Code and Scripts Tools toolbar. .<br />

Executing code in the debugger<br />

When a debugging session is started, (see “Starting a debugging session” on<br />

page 333) the execution of the Application Server program is paused<br />

immediately before the first statement of the code page of the first dynamic<br />

page is executed. The Debug > Start command will cause the application to<br />

continue executing statements until one of the following conditions occurs:<br />

336<br />

a statement having a breakpoint is encountered,<br />

the code page is completed and sent to the browser, or<br />

a run-time error in the code is encountered.<br />

If the page is completed, the page will be visible in the browser. The debugging<br />

session will be continued when another dynamic page is requested by the


Chapter 15: Debugging Server-side Code<br />

browser. If any of the other conditions occur, the application execution pauses<br />

and the debug windows will contain updated information about the state of<br />

the application.<br />

Note - The debugger will not automatically pause the<br />

application at the beginning of each dynamic page it<br />

encounters. Only the first dynamic page encountered in the<br />

session will be paused, and only for the first time through that<br />

page. To cause the debugger to pause the application at the<br />

beginning of a dynamic page, set a breakpoint at the<br />

beginning of that page.<br />

To start code execution<br />

While in a debug session, click the Start button on the Code and<br />

Script Tools toolbar.<br />

Single-stepping<br />

Single-stepping is the process of executing one statement at a time. You can<br />

see the effect of each statement by looking at the browser window, the Serverside<br />

Code window, and the Variable, Watch, Call Stack and Threads windows.<br />

When a method or subroutine is encountered in a statement, the single-step<br />

command steps into the method or subroutine, following the execution path<br />

of the program.<br />

Note - The debugger does not step into code whose source<br />

code is not part of the published project. For instance, the<br />

source code for the Application Server and language libraries<br />

are not accessible by the debugger.<br />

To single-step through code<br />

While in a debug session, click the Single-step button on the Code and<br />

Script Tools toolbar.<br />

To step out of a method or subroutine<br />

1 In the Call Stack window, double-click on the previous call level. This will<br />

be the line immediately below the top line.<br />

2 Set a breakpoint on the statement following the current statement in the<br />

calling method or subroutine, as indicated by a yellow arrow.<br />

3 Click the Start button.<br />

The program execution will continue through the method or subroutine<br />

and stop at the statement after the method or subroutine has returned.<br />

337


Chapter 15: Debugging Server-side Code<br />

Procedure-stepping<br />

Procedure-stepping is like single-stepping, except that you step over methods<br />

or subroutines. The Procedure-step command executes a statement containing<br />

a method or subroutine as a unit, then steps to the next statement in the<br />

current method or subroutine.<br />

To use procedure-stepping<br />

338<br />

While in a debug session, click the Procedure-step button on the Code<br />

and Script Tools toolbar.<br />

Using breakpoints<br />

Breakpoints pause an application before the line of code that the breakpoint is<br />

set on is executed. Variables and the call stack can be examined when the<br />

application is paused. Threads can also be monitored in Java projects. After<br />

pausing at a breakpoint, you can continue program execution by clicking on<br />

the start button, or you can step through and monitor critical sections of the<br />

code.<br />

When you are in a debugging session, you can set or remove breakpoints on<br />

any published dynamic page or code page in the project. Breakpoints can be<br />

set when the execution is paused in a dynamic page or when the Application<br />

Server is waiting for browser input between dynamic pages.<br />

When you are not in a debugging session, you can set or remove breakpoints<br />

at any location in the server-side code. Breakpoints which are set while not in<br />

a debugging session will not take effect in the next debugging session. Pages<br />

do not need to be re-published for breakpoints to take effect.<br />

Breakpoints are stored in the project and are remembered between <strong>IDE</strong>/IP<br />

sessions.<br />

To set or remove breakpoints<br />

1 In the Server-side Code view of the HTML editor, position the cursor on a<br />

statement to set or remove a breakpoint.<br />

2 From the main toolbar, select Debug > Toggle Break Point, or click the<br />

Toggle Breakpoint button on the Code toolbar.<br />

When a line has a breakpoint, a red circle is displayed next to the line.<br />

The following example shows a subroutine that has one breakpoint, indicated<br />

by a (red) circle to the left of the statement. The (yellow) arrow indicates the<br />

next line of code to be executed.


Chapter 15: Debugging Server-side Code<br />

Once breakpoints are set in the code, select Debug > Start, or click the Start<br />

button on the Code and Scripts toolbar to cause the program to continue<br />

execution until it reaches a statement containing a breakpoint.<br />

Note - In a debugging session, you can edit the source code<br />

using the Server-side Code view of the HTML editor, and save<br />

your changes. You must stop the current debug session, then<br />

build and publish the pages containing the changes before<br />

your edits will take effect.<br />

As a convenient way to manage multiple breakpoints, the Breakpoint Manager<br />

allows you to remove selected breakpoints, and remove, enable and disable all<br />

breakpoints in a single operation.<br />

To use the Breakpoint Manager<br />

From the main toolbar, select Edit > Breakpoints... The Breakpoint<br />

Manager dialog appears.<br />

339


Chapter 15: Debugging Server-side Code<br />

The Breakpoint Manager dialog displays a list of all breakpoints in the<br />

project.Check marks in the checkboxes next to the breakpoints indicate<br />

enabled breakpoints.<br />

.<br />

Button Action<br />

Remove Removes the breakpoints that have been selected. Selected<br />

breakpoints are highlighted.<br />

RemoveAll Removes all breakpoints.<br />

EnableAll Turns all breakpoints on. Check marks in the checkboxes<br />

indicate enabled breakpoints.<br />

DisableAll Turns all breakpoints off. The breakpoints will still exist, but will<br />

not cause the program to pause at that point.<br />

340<br />

Shortcut - You can also remove all breakpoints by selecting<br />

Debug > Clear All Break Points from the main toolbar.<br />

The debug windows<br />

When the Application Server encounters a dynamic page during a debug<br />

session, the HTML editor switches to the Server-side Code view and displays<br />

the code for that page.<br />

Several other windows provide debug information and control during a debug<br />

session.<br />

Output window, Debug panel<br />

Variable window<br />

Watch window<br />

Threads window<br />

The visibility of these windows is controlled through the View menu on the<br />

main tool bar during the debug session. If the windows are visible, the <strong>IDE</strong>/IP<br />

switches to the Debug panel of the Output window and opens the Watch, Call<br />

Stack, Variable and Threads windows. The Threads window is only used in<br />

debugging Java projects. These windows are updated each time the program<br />

execution is paused.


Debug output panel<br />

Chapter 15: Debugging Server-side Code<br />

The Debug panel of the Output window displays a trace of the server requests<br />

and responses during the debug session. Click on the plus signs (+) to expand<br />

the messages. Information displayed for each HTTP request includes the<br />

environment variable settings and the HTTP response stream created for the<br />

page. This window is updated each time the program is paused after hitting a<br />

breakpoint.<br />

Note - Informational messages from the debugger are sent to<br />

the Output panel of this window during the debug session.<br />

Variable window<br />

The Locals panel of the Variables window displays all local variables and their<br />

values. This window is updated each time the program execution is paused at<br />

a breakpoint. The values of these variables can be modified at runtime by<br />

changing the data in the value field of this variable. Variable arrays, structures<br />

and Java objects in this window can be expanded by clicking on the (+) next<br />

to the name. Individual values of the fields can be viewed and/or modified.<br />

341


Chapter 15: Debugging Server-side Code<br />

In Java projects, this panel of the Variable window is used to display the class<br />

instance that contains the current statement. When you’re debugging Java<br />

projects, the Variable window shows the superclass hierarchy of all objects and<br />

displays the member variables for the class and the superclasses. The values in<br />

the panel can be modified in the same manner as the local variables.<br />

342<br />

Note - The value of certain variables, such as pointers, cannot<br />

be modified.<br />

To modify a local variable<br />

1 Click on a variable name in the Locals panel of the Variable window. The<br />

Modify Variable dialog appears.<br />

2 Type the new value of the variable in the Value field.<br />

3 Optionally, you can check the box labeled Add to watch window. If this<br />

option is selected, the variable will be added to the list of watched<br />

variables in the watch window.


4 Click the OK button.<br />

Chapter 15: Debugging Server-side Code<br />

Shortcut - Variable values can also be changed by simply<br />

clicking on the value in the Variable window and typing in the<br />

new value.<br />

Watch window<br />

The Watch window allows you to select variables that you want to monitor<br />

during a debug session. The Watch window displays the name and value of all<br />

of the variables you are currently watching. In HAHTtalk Basic projects, the<br />

watch window displays the value of the variable’s scope. The value of watched<br />

variables can also be changed from the watch window (see “To modify a local<br />

variable” on page 342.)<br />

To add a watch variable<br />

1 From the main toolbar, select Debug > Add Watch, or click the Add Watch<br />

button on the Code and Scripts Tools toolbar. The Add Watch dialog<br />

appears.<br />

2 Type the name of the variable into the Variable Name field.<br />

Shortcut - You can drag-and-drop variables into the watch<br />

window from the Server-side Code view of the HTML editor.<br />

343


Chapter 15: Debugging Server-side Code<br />

In addition, you can substitute a different variable in the watch list by<br />

selecting Debug > Edit Watch, and you can change the value of a watched<br />

variable by selecting Debug > Modify Watch.<br />

To remove a watched variable<br />

344<br />

Select the variable from the list in the Watch window and press Delete.<br />

In Basic projects, the Watch window has a context field. The context field<br />

controls the context or scope used to determine the value of the variable. The<br />

‘any’ context in the Basic project watches follows the Basic scoping rules.<br />

Selecting another context displays variables using that context.<br />

Watches on Java variables always follow the scoping rules of Java.<br />

Watches remain set between debugging sessions, but do not persist across<br />

invocations of the <strong>IDE</strong>/IP.<br />

Call Stack window<br />

The Call Stack window is used to trace the execution of a page as it enters and<br />

returns from methods or subroutines. The Call Stack window displays a list of<br />

all of the methods or subroutines that the application has entered but not<br />

returned to the invoking method or subroutine. The window displays the<br />

earliest active subroutine at the bottom of the list and adds subsequent calls to<br />

the top of the list. You can double-click any entry in the Call Stack window to<br />

change the context of the other windows to the display values at that call<br />

level. The selected call level is indicated in the Call Stack window by a yellow<br />

triangle.<br />

The variables in the Watch and Variable window reflect their state at the<br />

selected call level. The Server-side Code editor marks the corresponding<br />

execution point at the selected call level with a yellow arrow.<br />

Shortcut - To make the Call Stack Window visible, click the<br />

Call Stack button .


Threads window<br />

Chapter 15: Debugging Server-side Code<br />

The Threads window is only used when debugging a Java project. When a<br />

<strong>HAHTsite</strong> Basic project is being debugged, this window is not available. When<br />

a program is paused, the Threads window contains the list of active threads,<br />

their names, and the class and method the thread is in at the current execution<br />

point. The Threads window controls display context like the Call Stack<br />

window. When you click on a thread, the Server-side Code window displays<br />

the source code for the location in that thread. All windows are updated to<br />

contain information in the context of the call stack for the selected thread. If<br />

you click on a thread that has no available source code to display, the Thread<br />

window indicates that the current line number is zero and all the windows are<br />

updated, except for the code window.<br />

345


Chapter 15: Debugging Server-side Code<br />

346


<strong>HAHTsite</strong> 3.x WebApp<br />

Methods and<br />

Properties<br />

A<br />

Introduction..................................................................................................348<br />

WebApp properties .......................................................................................348<br />

WebApp methods .........................................................................................350<br />

Pseudo-methods.......................................................................................352<br />

347


Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

Introduction<br />

This appendix lists the WebApp properties and methods (from <strong>HAHTsite</strong> 3.x)<br />

and their equivalent functionality in the <strong>HAHTsite</strong> Server Object Model. The<br />

WebApp properties and methods are still supported for legacy code and can be<br />

intermixed with Server Object Model classes and methods. However, for new<br />

projects it is highly recommended that you use only the <strong>HAHTsite</strong> Server<br />

Object Model.<br />

WebApp properties<br />

This table lists the WebApp properties from <strong>HAHTsite</strong> 3.x and the equivalent<br />

methods in the <strong>HAHTsite</strong> Server Object Model.<br />

WebApp Server Object Model<br />

Property Definition Class Method<br />

DirName The directory<br />

containing the<br />

HAHTtalk Basic<br />

executable program.<br />

The ‘root’ of this path<br />

is the configured<br />

application root<br />

directory, so this path<br />

does not typically<br />

represent a real<br />

operating system path.<br />

DynamicURL The URL of the Web<br />

server’s CGI-BIN<br />

directory.<br />

HAHTMapPrefix The URL prefix-string<br />

for references to<br />

dynamic image maps<br />

on the default subsite.<br />

HAHTPagePrefix The URL prefix-string<br />

for references to<br />

dynamic pages on the<br />

default subsite.<br />

348<br />

Application getDirName<br />

Application getAppData (index,<br />

"DynamicURL")<br />

Session createMapURL("")<br />

Session createPageURL<br />

(pagename,<br />

subsitename)


Hostname The hostname of the<br />

current machine<br />

HTXName The simple name<br />

(without a suffix) of<br />

the executable file.<br />

InHeaders Whether or not the<br />

page being generated<br />

is still in the HTTP<br />

headers section.<br />

NewApp Whether or not this is<br />

a new instance of the<br />

application.<br />

PageName The entry-point name<br />

of the currently<br />

executing dynamic<br />

page.<br />

Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

WebApp Server Object Model<br />

Property Definition Class Method<br />

PathName The combination of<br />

DirName and<br />

HTXName.<br />

ServerName The name of the<br />

server group serving<br />

the application.<br />

Session getHostName<br />

Application getName<br />

Response inHeaders<br />

Session isNewApp<br />

Page getName<br />

Application getPathName<br />

Session getServerGroupName<br />

StateId The StateId value. Session getStateId<br />

StaticROOT Operating systemdependent<br />

path to the<br />

Web server’s staticpage<br />

directory on the<br />

default subsite.<br />

StaticURL URL to the Web<br />

server’s static-page<br />

directory on the<br />

default subsite.<br />

Timeout The application<br />

timeout value in<br />

seconds.<br />

Application getStaticRoot<br />

and<br />

getAppData(index,<br />

"StaticROOT")<br />

Session getStaticURL<br />

and<br />

getAppData(index,<br />

"StaticURL")<br />

Session getTimeout<br />

349


Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

WebApp methods<br />

This table lists the methods of the WebApp object and the corresponding<br />

method in the <strong>HAHTsite</strong> Server Object Model.<br />

.<br />

WebApp Server Object Model<br />

Property Definition Class Method<br />

UserROOT Operating-system<br />

dependent path to the<br />

Web server’s initial<br />

working directory on<br />

the default subsite.<br />

UsingCookies Whether or not the<br />

application was<br />

published to place the<br />

StateId into cookies.<br />

350<br />

Application getUserRoot<br />

and<br />

getAppData(index,<br />

"UserROOT")<br />

Application isUsingCookies<br />

WebApp Server Object Model<br />

Method Definition Class Method<br />

EndHeaders Writes the End-of-<br />

Headers mark and sets<br />

InHeaders to False.<br />

Environ$ Returns the value of an<br />

environment variable.<br />

GetAppData Returns information<br />

about the application.<br />

GetMapPrefix$ Returns the URL for an<br />

image map<br />

GetPagePrefix$ Returns the URL for a<br />

dynamic page<br />

GetStaticURL$ Returns the URL of the<br />

Web server’s static-page<br />

directory<br />

GetSubSiteCount Returns the number of<br />

subsites defined for the<br />

application.<br />

Response endHeaders<br />

Request getServerVariable<br />

Application getAppData<br />

Session createMapURL<br />

Session createPageURL<br />

Session createStaticURL<br />

Application getSubSiteCount


Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

WebApp Server Object Model<br />

Method Definition Class Method<br />

GetSubSite$ Returns the name of<br />

the subsite associated<br />

with the value of the<br />

(zero-based) Index<br />

argument.<br />

GetURL$ Locates a project item<br />

by its unique ProjectID<br />

and returns a string<br />

with either a full or<br />

relative URL for that<br />

item.<br />

HeaderField Writes the string as a<br />

partial header line.<br />

HeaderLine Writes the string as a<br />

complete header line,<br />

supplying the<br />

terminating <br />

pair.<br />

HeaderMark Writes the <br />

line mark after a series<br />

of HeaderField calls.<br />

URLAttachment$ Returns the name of<br />

the temporary file used<br />

for the attachment<br />

associated with the URL<br />

field name String.<br />

URLAttachmentCount Returns the total<br />

number of attachments.<br />

URLAttachmentExists Returns True or False,<br />

indicating whether an<br />

attachment exists for<br />

the URL field name<br />

String.<br />

URLAttachmentType$ Returns the Content-<br />

Type of the attachment<br />

associated with the URL<br />

field name "String."<br />

Application getSubSite<br />

Session getURL<br />

n.a.<br />

Response addHeaderLine<br />

n.a.<br />

Request getURLAttachment<br />

Request getURLAttachmentCount<br />

Request getURLAttachmentExist<br />

s<br />

Request getURLAttachmentType<br />

351


Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

URLField$ Returns the value of a<br />

field on the URL or in a<br />

form.<br />

Pseudo-methods<br />

Pseudo-methods are place-holders that you can override with a function or<br />

subroutine. This table summarizes the WebApp pseudo-methods and lists the<br />

corresponding methods in <strong>HAHTsite</strong>’s Server Object Model. If a project calls<br />

both the "old" Webapp pseudo-method and the new Server Object Model<br />

pseudo-method, the newer method will run first. (Note that these pseudomethods<br />

apply only to HAHTtalk projects. Java projects should use the<br />

Session class’s onStart and onEnd methods.)<br />

HahtSessionOnStart should be declared as a function returning a boolean<br />

value (for success or failure). HahtSessionOnEnd should be declared as a<br />

subroutine. Neither routine takes any arguments.<br />

352<br />

WebApp Server Object Model<br />

Method Definition Class Method<br />

URLFieldCount Returns the total<br />

number of URL fields.<br />

URLFieldExists Tests whether the<br />

named field is in the<br />

URL.<br />

WhoAmI$ Returns the name of<br />

the current page or<br />

HAHTtalk Basic<br />

subroutine.<br />

WhoCalledMe$ Returns the name of<br />

the page or HAHTtalk<br />

Basic subroutine that<br />

called the object on<br />

which the method is<br />

located (“me").<br />

WriteLog Writes a string to the<br />

Application Server’s log<br />

file.<br />

Request getURLField<br />

Request getURLFieldCount<br />

Request getURLFieldExists<br />

Session whoAmI<br />

Session whoCalledMe<br />

Application writeLog


Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

WebApp WebApp Server Object Model<br />

Pseudo-method Definition Pseudo-method<br />

Initiate<br />

(WebApp_Initiate)<br />

TimeUp<br />

(WebApp_TimeUp)<br />

Terminate<br />

(WebApp_Terminate)<br />

The session was just<br />

initiated.<br />

The Timeout value has<br />

elapsed.<br />

The session is about to<br />

be terminated.<br />

HahtSessionOnStart<br />

No equivalent. Do not use.<br />

HahtSessionOnEnd<br />

353


Appendix A: <strong>HAHTsite</strong> 3.x WebApp Methods and Properties<br />

354


<strong>HAHTsite</strong> 3.x Data<br />

Management<br />

B<br />

Introduction..................................................................................................356<br />

DataSets and data agents..............................................................................356<br />

Accessing and changing DataSet properties at runtime.........................356<br />

DataSet control functions........................................................................357<br />

Writing user-defined DataSet functions..................................................358<br />

Accessing and changing form-control properties at runtime .....................358<br />

Connection-manager functions ...................................................................359<br />

355


Appendix B: <strong>HAHTsite</strong> 3.x Data Management<br />

Introduction<br />

This appendix summarizes the ways in which programming database<br />

applications differs between <strong>HAHTsite</strong> 3.x and <strong>HAHTsite</strong> 4.0. In general, the<br />

objects with which you interacted in <strong>HAHTsite</strong> 3.x—DataSets, form controls,<br />

and the connection manager—are now represented by classes in the Server<br />

Object Model (or by ActiveX Data Object classes). The correspondence<br />

between a 3.x object and a Server Object Model object is not always<br />

one-to-one, and the 4.0 methods may behave differently than their 3.x<br />

counterparts. Note, too, that the <strong>HAHTsite</strong> 4.0 release offers much greater<br />

functionality than is represented in this appendix.<br />

The 3.x properties and functions will continue to be supported in legacy<br />

projects, but any new projects should be developed using the Server Object<br />

Model. You can mix both models within the same project, but not on the same<br />

page.<br />

DataSets and data agents<br />

DataSets in <strong>HAHTsite</strong> 3.x have been replaced by data agents. These objects are<br />

similar; however, data agents are only responsible for populating form fields<br />

on a page with data read from an ADO recordset. Separate command handlers<br />

perform the actions associated with form buttons.<br />

The sections below explain how the DataSet programming tasks covered in the<br />

3.x documentation are handled in <strong>HAHTsite</strong> 4.0.<br />

Accessing and changing DataSet properties at runtime<br />

<strong>HAHTsite</strong> 3.x maintained several DataSet record structures — DataSet_Widget,<br />

DataSet_RecordSet, and DataSet_BoundWidget — and enabled you to set<br />

properties of these structures. These record structures are not used in <strong>HAHTsite</strong><br />

4.0. The table below guides you to the Server Object Model classes that contain<br />

data similar to that stored in the 3.x record structures.<br />

Record structure Server Object Model classes<br />

DataSet_Widget<br />

The properties of this structure enabled<br />

you set such attributes as the DataSet’s<br />

name, filter, and default action.<br />

356<br />

DataAgent<br />

This class has member variables that<br />

give you access to similar data.


DataSet_RecordSet<br />

The DynaSet property enabled you to<br />

read or write the name of the DataSet’s<br />

dynaset.<br />

DataSet_BoundWidget<br />

The properties of this structure enabled<br />

you to read or change attributes of<br />

form controls bound to the DataSet.<br />

DataSet control functions<br />

Appendix B: <strong>HAHTsite</strong> 3.x Data Management<br />

Record structure Server Object Model classes<br />

DataAgent<br />

You can get or set a data agent’s<br />

recordset using the methods<br />

getRecordset and setRecordset.<br />

(To work with a recordset, you use<br />

methods of the ADO Recordset class.)<br />

FormField and its subclasses<br />

In <strong>HAHTsite</strong> 4.0, form fields are<br />

represented by subclasses of the SOM<br />

class FormField. You set form-field<br />

attributes using methods of these<br />

subclasses. (Note that some of the<br />

bound-widget properties you could<br />

read or set in 3.x are no longer<br />

applicable.)<br />

<strong>HAHTsite</strong> 3.x provided a small set of DataSet-control functions. These<br />

functions and their 4.0 counterparts are listed in the table below.<br />

DataSet-control function Server Object Model classes<br />

DataSet_GetBoundWidgetIndex This function does not have a<br />

counterpart in 4.0.<br />

DataSet_GetBoundWidgetValue Subclasses of FormField<br />

You get the value of a form field using<br />

the method getValue, which is<br />

inherited from FormField.<br />

DataSet_SetBoundWidgetValue Subclasses of FormField<br />

You set the value of a form field using<br />

the method setValue.<br />

DataSet_Close DataAgent<br />

The close method closes all of a data<br />

agent’s open resources.<br />

357


Appendix B: <strong>HAHTsite</strong> 3.x Data Management<br />

Writing user-defined DataSet functions<br />

In <strong>HAHTsite</strong> 3.x, DataSets perform standard <strong>HAHTsite</strong> database actions (such<br />

as Insert) on behalf of a form button, and you have the option of overriding a<br />

standard event. In <strong>HAHTsite</strong> 4.0, the actions are performed by command<br />

handlers that are generated by <strong>HAHTsite</strong>. You have the option of modifying<br />

these command handlers by adding event handlers to the generated code.<br />

Accessing and changing form-control<br />

properties at runtime<br />

In <strong>HAHTsite</strong> 3.x, you could read and set properties of the following form<br />

controls:<br />

358<br />

Text boxes<br />

Text areas<br />

Check boxes<br />

Radio buttons<br />

Combo boxes<br />

List boxes<br />

Static text<br />

<strong>HAHTsite</strong> maintained a set of record structures for each form control —<br />

ControlName_Widget, ControlName_BoundWidget, ControlName_ExtAttr, and<br />

in some cases ControlName_List — and you changed a form control’s<br />

attributes using properties of these structures. In <strong>HAHTsite</strong> 4.0, form fields are<br />

represented by Server Object Model classes, and you modify the attributes of<br />

a form field using get and set methods.<br />

The table below shows the correspondence between the types of form fields<br />

and the relevant Server Object Model classes.<br />

Note - The FormField class is relevant in each case because<br />

FormField is the superclass of all the specific form-field classes,<br />

and all of these classes inherit methods from FormField.<br />

Form control Server Object Model class<br />

Text box Textbox


Form control Server Object Model class<br />

Text area TextArea<br />

Check box Checkbox<br />

Radio button Radiobutton<br />

Combo box Combobox<br />

List box Listbox<br />

Static text StaticText<br />

Appendix B: <strong>HAHTsite</strong> 3.x Data Management<br />

The Server Object Model also includes classes for form buttons (Button) and<br />

File Upload fields (FileUpload).<br />

Connection-manager functions<br />

<strong>HAHTsite</strong> 3.x provided a set of functions for working with the Connection<br />

Manager. In <strong>HAHTsite</strong> 4.0, the counterpart of the Connection Manager is an<br />

instance of the Server Object Model’s DMConnectionManager class. The table<br />

maps the 3.x open- and close-connection functions to the appropriate<br />

methods of the DMConnectionManager class.<br />

Connection Manager functions DMConnectionManager methods<br />

GetConnection getSharedConnectionByID<br />

getSharedConnectionByName<br />

openConnection<br />

openPrivateConnectionByID<br />

openPrivateConnectionByName<br />

CloseConnection closeAllConnections<br />

closePrivateConnection<br />

359


Appendix B: <strong>HAHTsite</strong> 3.x Data Management<br />

360


Code Examples<br />

C<br />

Calling a subroutine as a form action .........................................................362<br />

Modifying a command handler ...................................................................370<br />

Writing a custom authentication class ........................................................373<br />

361


Appendix C: Code Examples<br />

Calling a subroutine as a form action<br />

“Calling a subroutine from a form” on page 134 explains how to have your<br />

application invoke a Java method or HAHTtalk Basic subroutine when a form<br />

is submitted. The example presented in that section assumes that the user of<br />

the application enters the path to an image in a file-upload field. Then, when<br />

the form is submitted, a subroutine reads the filename from a URL and writes<br />

the contents of the file to a field in a database.<br />

The subroutine is shown below in both its Java and HAHTtalk Basic flavors.<br />

Java<br />

package FileUploadJava;<br />

import com.haht.*;<br />

import com.haht.project.*;<br />

import com.haht.ado.Abstract.*;<br />

import java.io.*;<br />

class StuffAPictureInAccess extends Object<br />

implements HAHTPage<br />

{<br />

static final int BUFSIZE = 1024;<br />

362<br />

public void run (Request aRequest, Response aResponse)<br />

{<br />

// For success, failure<br />

HsMessage_Page myMsgPage = new HsMessage_Page();<br />

// Check to see if they've sent the data<br />

//<br />

if (aRequest.getURLFieldExists("txtName")<br />

&& aRequest.getURLAttachmentExists("uplPicture"))<br />

{<br />

// Get shared connection, open NameAndPict table<br />

// to get recordset<br />

Connection myConn;<br />

try<br />

{


Java<br />

Appendix C: Code Examples<br />

myConn = Haht.getSession().getConnectionManager().<br />

getSharedConnectionByName("NameAndPict");<br />

}<br />

catch (com.haht.HahtException e)<br />

{<br />

myMsgPage.setErrorMessage<br />

("Unable to open connection: " +<br />

e.toString());<br />

myMsgPage.run (aRequest, aResponse);<br />

return;<br />

}<br />

Recordset myRS =<br />

new com.haht.ado.Recordset();<br />

if (myRS == null)<br />

{<br />

myMsgPage.setErrorMessage<br />

("Unable to create recordset");<br />

myMsgPage.run (aRequest, aResponse);<br />

return;<br />

}<br />

myRS.setActiveConnection(myConn);<br />

// So we can Insert/Update/Delete<br />

myRS.setCursorType<br />

(com.haht.ado.CursorTypeEnum.adOpenKeyset);<br />

myRS.setLockType<br />

(com.haht.ado.LockTypeEnum.adLockOptimistic);<br />

try<br />

{<br />

myRS.open("NameAndPict");<br />

}<br />

catch (java.lang.Exception e)<br />

{<br />

myMsgPage.setErrorMessage<br />

("Opening NameAndPict table failed");<br />

myMsgPage.run (aRequest, aResponse);<br />

return;<br />

}<br />

363


Appendix C: Code Examples<br />

Java<br />

364<br />

// Get filename of uploaded image, open it, and<br />

// prepare to appendChunk it into the recordset<br />

// field.<br />

java.io.File pictureFile = new java.io.File<br />

(Haht.getApplication().getUserRoot() +<br />

'/' + aRequest.getURLAttachment("uplPicture"));<br />

FileInputStream pictureStream;<br />

Field pictureFld;<br />

try<br />

{<br />

pictureStream = new FileInputStream<br />

(pictureFile);<br />

}<br />

catch (java.io.FileNotFoundException e)<br />

{<br />

myMsgPage.setErrorMessage<br />

("Unable to open uploaded file");<br />

myRS.close();<br />

myMsgPage.run (aRequest, aResponse);<br />

return;<br />

}<br />

// Add new record to recordset to put picture in,<br />

// assign name to it, and get picture field to<br />

// append data to.<br />

myRS.addNew ();<br />

myRS.getField("Name").setString<br />

(aRequest.getURLField("txtName"));<br />

pictureFld = myRS.getField("Picture");<br />

// Allocate a buffer and read until we're done<br />

//<br />

byte [] pictureBuf = new byte[BUFSIZE];<br />

int nBytesRead;<br />

int nBytesTotal = 0;


Java<br />

Appendix C: Code Examples<br />

do<br />

{<br />

try<br />

{<br />

nBytesRead = pictureStream.read(pictureBuf);<br />

nBytesTotal += nBytesRead;<br />

if (nBytesRead > 0)<br />

{<br />

pictureFld.appendChunk<br />

(pictureBuf, nBytesRead);<br />

}<br />

}<br />

catch (java.io.IOException e)<br />

{<br />

myMsgPage.setErrorMessage<br />

("Error while reading file");<br />

myRS.close();<br />

myMsgPage.run (aRequest, aResponse);<br />

try<br />

{<br />

pictureStream.close();<br />

}<br />

catch (java.io.IOException e2)<br />

{<br />

}<br />

return;<br />

}<br />

}<br />

while (nBytesRead > 0);<br />

// Finish inserting the record by updating the<br />

// recordset<br />

myRS.update();<br />

365


Appendix C: Code Examples<br />

Java<br />

}<br />

366<br />

}<br />

// Close up shop, call Results page<br />

try<br />

{<br />

pictureStream.close();<br />

}<br />

catch (java.io.IOException e)<br />

{<br />

}<br />

myRS.close();<br />

myMsgPage.setMessage ("Copied " +<br />

String.valueOf(nBytesTotal) +<br />

" bytes to record for " +<br />

aRequest.getURLField("txtName"));<br />

myMsgPage.run (aRequest, aResponse);<br />

}<br />

else<br />

{<br />

myMsgPage.setErrorMessage<br />

("Picture name or file missing");<br />

myMsgPage.run (aRequest, aResponse);<br />

}


HAHTtalk Basic<br />

#include <br />

#include <br />

Const BLKSIZE = 1024<br />

Appendix C: Code Examples<br />

Public Sub StuffAPictureInAccess<br />

Dim myConnMgr As Object, mySession As Object<br />

Dim sPictureFileName As String<br />

Dim aRequest As Object<br />

Dim pictureFld As ADODB.Field, nameFld As ADODB.Field<br />

Dim fRead As Long<br />

Dim fLen As Long<br />

Dim nBlkSize As Long, nBytesTotal As Long<br />

Dim sBuf As String<br />

Dim nullObj As Object<br />

Dim myRS As New ADODB.Recordset<br />

Dim myConn As ADODB.Connection<br />

'<br />

' Check to see if they've sent the data<br />

'<br />

Set aRequest = Haht.getRequest()<br />

Set nullObj = Nothing<br />

If (aRequest.getURLFieldExists("txtName") _<br />

And aRequest.getURLAttachmentExists("uplPicture")) Then<br />

'<br />

' Get shared connection, open NameAndPict table to<br />

' get recordset<br />

'<br />

Set myConn = getSharedConnectionByName _<br />

("NameAndPicture")<br />

set myRS.ActiveConnection = myConn<br />

myRS.CursorType = adOpenKeyset<br />

myRS.LockType = adLockOptimistic<br />

myRS.open "NameAndPict"<br />

367


Appendix C: Code Examples<br />

HAHTtalk Basic<br />

368<br />

'<br />

' Get filename of uploaded image, open file, and prepare<br />

' to appendChunk image into the recordset field<br />

'<br />

sPictureFileName = HahtApplication.getUserRoot() & "/" & _<br />

& aRequest.getURLAttachment("uplPicture")<br />

Set pictureFld = myRS.Fields("Picture")<br />

Set nameFld = myRS.Fields("Name")<br />

fRead = FreeFile()<br />

Open sPictureFileName for Binary Access Read As #fRead<br />

'<br />

' Add new record to Recordset to put picture in, add<br />

' data to it<br />

'<br />

myRS.addNew<br />

nameFld.Value = aRequest.getURLField("txtName")<br />

fLen = FileLen(sPictureFileName)<br />

nBlkSize = IIF(fLen < BLKSIZE, fLen, BLKSIZE)<br />

sBuf = String$(nBlkSize, 0)<br />

nBytesTotal = 0<br />

While fLen > 0<br />

Get #fRead,,sBuf<br />

nBytesTotal = nBytesTotal + nBlkSize<br />

pictureFld.AppendChunk sBuf<br />

fLen = fLen - nBlkSize<br />

If ( fLen < nBlkSize ) AND ( fLen > 0 ) Then<br />

nBlkSize = fLen<br />

sBuf = String$(nBlkSize,0)<br />

End If<br />

Wend<br />

'<br />

' Close file, continue<br />

'<br />

Close #fRead<br />

myRS.update


HAHTtalk Basic<br />

Appendix C: Code Examples<br />

'<br />

' Close up shop, call Results page<br />

'<br />

myRS.close<br />

Set myRS = Nothing<br />

Set myConn = Nothing<br />

Set myConnMgr = Nothing<br />

gMessageText = "Copied " & CStr(nBytesTotal) & _<br />

" to record for " & aRequest.getURLField("txtName")<br />

Set aRequest = Nothing<br />

goto StuffAPictureInAccess_Exit<br />

Else<br />

gMessageText ="Picture name or file missing"<br />

goto StuffAPictureInAccess_Exit<br />

End If<br />

StuffAPictureInAccess_Exit:<br />

HS_Message_Page<br />

Exit Sub<br />

StuffAPictureInAccess_Errors:<br />

' Dump any errors we want to here<br />

gMessageText = "Error " & Str$(Err) & " - " & Error & _<br />

" occurred processing picture"<br />

Resume StuffAPictureInAccess_Exit<br />

End Sub<br />

369


Appendix C: Code Examples<br />

Modifying a command handler<br />

This section presents an example of how you might customize a command<br />

handler’s prebind method. Suppose that you have a form that contains a File<br />

Upload form field. When a user runs your application, he or she will enter the<br />

path to an image file in the File Upload text field. When the user clicks the<br />

Insert button, you want to take this pathname, open the image file, and write<br />

the contents of the file to a BLOB field in your database. (The record<br />

containing the image will also contain a picture name that you can use to<br />

identify the image.)<br />

Since <strong>HAHTsite</strong> doesn’t generate code for inserting a large binary object into a<br />

database, you must add code similar to the following to a command handler<br />

to insert this object in your database.<br />

HAHTtalk Basic<br />

370<br />

'<br />

' Get the filename of an uploaded image, open the file,<br />

' and copy its contents into a record field that holds<br />

' binary data.<br />

'<br />

Dim aRequest As Object<br />

Dim sPictureFileName As String<br />

Dim pictureFld As Object, nameFld As Object<br />

Dim fRead As Long<br />

Dim fLen As Long<br />

Dim nBlkSize As Long<br />

Dim sBuf As String<br />

On Error GoTo onBind_ErrorHandler<br />

Set aRequest = Haht.getRequest()<br />

sPictureFileName = HahtApplication.getUserRoot() & "/" _<br />

& aRequest.getURLAttachment("upload1")


HAHTtalk Basic<br />

Appendix C: Code Examples<br />

'<br />

' The command handler has already added a new record to<br />

' the recordset, so we can get references to the Name<br />

' and Picture fields in that record. Write the name<br />

' me to the Name field.<br />

'<br />

Set pictureFld = daNameAndPict.getRecordset(). _<br />

getField("Picture")<br />

Set nameFld = daNameAndPict.getRecordset().getField("Name")<br />

nameFld.setString aRequest.getURLField("txtName")<br />

'<br />

' Open the image file, read chunks of data into a buffer,<br />

' and copy the data to the record's Picture field.<br />

'<br />

fRead = FreeFile()<br />

Open sPictureFileName for Binary Access Read As #fRead<br />

fLen = FileLen(sPictureFileName)<br />

nBlkSize = IIF(fLen < BLKSIZE, fLen, BLKSIZE)<br />

sBuf = String$(nBlkSize, 0)<br />

While fLen > 0<br />

Get #fRead,,sBuf<br />

pictureFld.AppendChunk sBuf<br />

fLen = fLen - nBlkSize<br />

If ( fLen < nBlkSize ) AND ( fLen > 0 ) Then<br />

nBlkSize = fLen<br />

sBuf = String$(nBlkSize, 0)<br />

End If<br />

Wend<br />

'<br />

' Close the file.<br />

'<br />

Close #fRead<br />

onBind_ExitHandler:<br />

Exit Sub<br />

371


Appendix C: Code Examples<br />

HAHTtalk Basic<br />

onbind_ErrorHandler:<br />

'<br />

' Dump any errors we want to here<br />

'<br />

aHandlerInfo.setProceedAction _<br />

DMConstants_PROCEED_DO_FAILURE_PAGE<br />

Resume onBind_ExitHandler<br />

372


Appendix C: Code Examples<br />

Writing a custom authentication class<br />

This section presents the implementation of a Java class that authenticates<br />

users against information stored in an Access database. The table used for<br />

authentication contains two columns: UserName and Password.<br />

Java<br />

import com.haht.ado.Abstract.*;<br />

import com.haht.access.*;<br />

public class CustomAuthentication implements Authentication<br />

{<br />

public boolean authorizeUser(String aUserName,<br />

String aPassword, String aDomain)<br />

{<br />

Connection conn = new com.haht.ado.Connection();<br />

Recordset rs = new com.haht.ado.Recordset();<br />

// Open a connection to the database.<br />

try<br />

{<br />

conn.open("Provider=HSODBC;DSN=Authentication;" +<br />

"DBQ=C:\\Stan\\Authentication.mdb;" +<br />

"DriverId=25;FIL=MS Access;MaxBufferSize=512;" +<br />

"PageTimeout=5;");<br />

}<br />

catch(java.lang.Exception e) {}<br />

// Get the record containing the user name and password.<br />

rs.setActiveConnection(conn);<br />

String commandText = "SELECT Password FROM Authentication"<br />

+ " WHERE UserName = '" + aUserName + "'";<br />

try<br />

{<br />

rs.open(commandText);<br />

}<br />

catch (java.lang.Exception e) {}<br />

373


Appendix C: Code Examples<br />

Java<br />

}<br />

374<br />

}<br />

// Determine whether user should be authenticated.<br />

if (!(rs.getBOF() == true && rs.getEOF() == true))<br />

{<br />

Field fld = rs.getField("Password");<br />

if (fld.getString().equals(aPassword))<br />

{<br />

rs.close();<br />

conn.close();<br />

return true;<br />

}<br />

rs.close();<br />

conn.close();<br />

return false;<br />

}<br />

rs.close();<br />

conn.close();<br />

return false;


ADO Primer<br />

D<br />

What’s in this appendix ...............................................................................376<br />

Connections..................................................................................................376<br />

Opening a connection.............................................................................376<br />

Executing a command against a connection .........................................378<br />

Closing a connection...............................................................................379<br />

Recordsets......................................................................................................380<br />

Creating a recordset.................................................................................380<br />

Iterating through the records in a recordset ..........................................381<br />

Finding a specific record in a recordset ..................................................382<br />

Reading a record ......................................................................................382<br />

Updating a record....................................................................................383<br />

Inserting a record.....................................................................................383<br />

Deleting a record .....................................................................................384<br />

Closing a recordset ..................................................................................385<br />

375


Appendix D: ADO Primer<br />

What’s in this appendix<br />

This appendix provides a very brief introduction to ADO programming by<br />

presenting short examples of how to perform common ADO operations in<br />

<strong>HAHTsite</strong> applications. For example, the appendix illustrates how to:<br />

376<br />

open a connection<br />

create a recordset<br />

add a record to a recordset<br />

Each example is shown using both Java and HAHTtalk Basic syntax.<br />

A note for Java programmers: The Java ADO classes you use are not in the<br />

package com.ms.wfc.data (as they would be in a Microsoft ADO program), but<br />

are in the package com.haht.ado or com.haht.ado.Abstract. You use the<br />

abstract classes in com.haht.ado.Abstract when you declare a variable that<br />

will hold a reference to an ADO object. And you use the classes in<br />

com.haht.ado — or in a package of user-defined ADO classes — when you<br />

instantiate an ADO object. Generally, <strong>HAHTsite</strong> Java projects import<br />

com.haht.ado.Abstract.* and fully qualify the names of classes in the<br />

package com.haht.ado or in a user-defined package.<br />

Connections<br />

An ADO Connection object represents a connection to a data source — usually<br />

a relational database. For information on how to perform common operations<br />

using a Connection object, see the following sections:<br />

“Opening a connection” on page 376<br />

“Executing a command against a connection” on page 378<br />

“Closing a connection” on page 379<br />

Opening a connection<br />

In a <strong>HAHTsite</strong> project, you can open a connection in one of two ways:<br />

by calling a Connection object’s open method<br />

by calling a Java method or HAHTtalk Basic function that returns a<br />

Connection.<br />

Both ways of opening a connection are illustrated below.


Using an ADO method<br />

Appendix D: ADO Primer<br />

The code below shows how to open a connection by instantiating a<br />

Connection object and calling that object’s open method. This open method is<br />

an overloaded method and may take zero or more of the following parameters:<br />

Parameter Data type Description<br />

A connection string String A data source name or a connection<br />

string containing a series of name/value<br />

pairs.<br />

A user name String The user name to be used for a database<br />

login.<br />

A password String The corresponding password.<br />

These examples use a connection string that specifies a provider and a data<br />

source.<br />

Java<br />

import com.haht.ado.Abstract.*;<br />

...<br />

myConn = new com.haht.ado.Connection();<br />

myConn.open("provider=hsodbc;dsn=Employees");<br />

HAHTtalk Basic<br />

Dim myConn As new ADODB.Connection<br />

myConn.open "provider=hsodbc;dsn=Employees"<br />

Note that the Java example creates a connection object of type<br />

com.haht.ado.Connection and that the HAHTtalk Basic example creates one<br />

of type ADODB.Connection.<br />

Using a <strong>HAHTsite</strong> method or function<br />

<strong>HAHTsite</strong> includes a set of Java methods and HAHTtalk Basic functions that<br />

you can use to open, or get a reference to, a connection. For detailed<br />

information about these methods and functions, see Chapter 9,<br />

“<strong>Programming</strong> with the Connection Manager.”<br />

The Java methods are methods of the DMConnectionManager class:<br />

377


Appendix D: ADO Primer<br />

378<br />

getSharedConnectionByID<br />

getSharedConnectionByName<br />

openPrivateConnectionByID<br />

openPrivateConnectionByName<br />

There are four HAHTtalk Basic functions of the same names. The Java methods<br />

return objects of type com.haht.ado.Connection, and the HAHTtalk Basic<br />

functions return objects of type ADODB.Connection.<br />

Calling a method or function that creates a private connection is comparable<br />

to calling a Connection object’s open method. A new connection is created.<br />

The shared-connection methods and functions enable you to create a<br />

connection that can be used on a number of pages in an application. You can<br />

also share such a connection with <strong>HAHTsite</strong> data agents.<br />

The following examples get a reference to a shared connection by calling<br />

getSharedConnectionByName. The one argument to this method/function is<br />

the name of an ADO connection that you’ve created using the <strong>IDE</strong>.<br />

Java<br />

import com.haht.*;<br />

import com.haht.ado.Abstract.*;<br />

...<br />

Connection myconn;<br />

try<br />

{<br />

myConn = Haht.getSession().getConnectionManager().<br />

getSharedConnectionByName("EmployeesConn");<br />

}<br />

catch(HahtException e) {}<br />

HAHTtalk Basic<br />

Dim myConn As ADODB.Connection<br />

Set myConn = getSharedConnectionByName("EmployeesConn")<br />

Executing a command against a connection<br />

Once you’ve opened a connection (or obtained a reference to an open<br />

connection), you can execute a command against that connection using the<br />

Connection object’s execute or executeUpdate (Java only) method. The first<br />

— and sometimes only — argument to this method is a string representing the


Appendix D: ADO Primer<br />

command to execute against the connection. This command can be a SQL<br />

statement, the name of a table, or the name of a stored procedure.<br />

In the example below, the command is a SQL statement that inserts a record<br />

into a database table.<br />

Java<br />

String insertCmd;<br />

int recordsAffected;<br />

...<br />

insertCmd =<br />

"INSERT INTO NAMES (FirstName, LastName)<br />

VALUES ('Jane', 'Doe')";<br />

recordsAffected = myConn.executeUpdate(insertCmd);<br />

HAHTtalk Basic<br />

Dim myRS As ADODB.Recordset<br />

Dim insertCmd As String<br />

...<br />

insertCmd = _<br />

"INSERT INTO NAMES (FirstName, LastName) VALUES ('Jane', 'Doe')"<br />

Set myRS = myConn.execute(insertCmd)<br />

Closing a connection<br />

A connection is closed automatically when the object representing it goes out<br />

of scope; however, it’s a good idea to close connections explicitly. You close a<br />

connection using the Connection object’s close method.<br />

Java<br />

myConn.close();<br />

myConn = null;<br />

HAHTtalk Basic<br />

myConn.close<br />

Set myConn = Nothing<br />

379


Appendix D: ADO Primer<br />

Recordsets<br />

The ADO Recordset object is a container for a group of records returned as the<br />

result of a query. For information about common actions performed against<br />

recordsets, see the following sections:<br />

380<br />

“Creating a recordset” on page 380<br />

“Iterating through the records in a recordset” on page 381<br />

“Finding a specific record in a recordset” on page 382<br />

“Reading a record” on page 382<br />

“Updating a record” on page 383<br />

“Inserting a record” on page 383<br />

“Deleting a record” on page 384<br />

“Closing a recordset” on page 385<br />

Creating a recordset<br />

You can create a recordset in a number of ways. For example, both the<br />

Connection and Command objects have execute methods that can return a<br />

recordset. The example below, however, creates a recordset containing data by<br />

instantiating a Recordset object and calling that object’s open method. The<br />

first argument to this method specifies the source of the data; in this case, the<br />

data will be read from a database table called Names. This first argument can<br />

be a SQL statement, a table name, or the name of a stored procedure. The<br />

second argument is the name of a previously established Connection.<br />

Notice that the Java code returns an object of type com.haht.ado.Recordset,<br />

while the HAHTtalk Basic code returns an object of type ADODB.Recordset.<br />

Java<br />

import com.haht.ado.Abstract.*;<br />

...<br />

Recordset myRS = new com.haht.ado.Recordset();<br />

...<br />

myRS.open("SELECT * FROM Names", myConn);


HAHTtalk Basic<br />

Dim myRS As New ADODB.Recordset<br />

...<br />

myRS.open "SELECT * FROM Names", myConn<br />

Iterating through the records in a recordset<br />

Appendix D: ADO Primer<br />

Once you’ve created a recordset, you’ll need to be able to navigate it. One<br />

common requirement is to be able to look at each record in order. The<br />

following examples show you how to do this (assuming you opened your<br />

recordset using the default cursor type, forward-only).<br />

When you open the recordset (using the default cursor type), the current<br />

record is the first record in the recordset. The while statement checks to make<br />

sure that the current record pointer is not pointing beyond the last record in<br />

the recordset. As long as this condition is true, you want to process the record<br />

and then move to the next record.<br />

Java<br />

while (!myRS.getEOF())<br />

{<br />

...<br />

myRS.moveNext();<br />

}<br />

HAHTtalk Basic<br />

while (not myRS.EOF)<br />

...<br />

myRS.moveNext<br />

wend<br />

Note - If you opened your recordset using a cursor type other<br />

than the default — that is, using a static cursor or a dynamic<br />

cursor — you should call the recordset’s moveFirst method to<br />

move the current record pointer to the first record of the<br />

recordset before you begin iterating through the records.<br />

381


Appendix D: ADO Primer<br />

Finding a specific record in a recordset<br />

In addition to iterating through the records in a recordset, you’ll often want<br />

to find a particular record in a recordset. You can find a record that meets a<br />

specific criterion using the Recordset’s find method. This method takes three<br />

arguments. The first is a string that specifies the criterion that must be met.<br />

This criterion has the form fieldName operator value. The second argument<br />

is a Boolean value indicating whether the find operation should skip the<br />

current record. The third argument is a constant that dictates the direction of<br />

the search: forward or backward.<br />

Java<br />

myRS.find("FirstName = 'Jane'", 0,<br />

AdoEnums.SearchDirection.FORWARD);<br />

HAHTtalk Basic<br />

myRS.find "FirstName = 'Jane'", 0, adSearchForward<br />

Reading a record<br />

Each record in a recordset has associated with it a Fields collection, which<br />

contains the individual fields that make up the record. You read a record by<br />

making it the current record and then reading the individual fields in the<br />

record. You can access a field either by its name or by its position in the record.<br />

Java<br />

String firstName;<br />

String lastName;<br />

...<br />

firstName = myRS.getField("FirstName").getString();<br />

lastName = myRS.getField("LastName").getString();<br />

382


HAHTtalk Basic<br />

Dim firstName As String<br />

Dim lastName As String<br />

...<br />

firstName = myRS.Fields(0)<br />

lastName = myRS.Fields(1)<br />

Updating a record<br />

Appendix D: ADO Primer<br />

To update a record, you write data to one or more of the record’s fields and<br />

then call the Recordset’s update method. If you forget to update the record<br />

before you move the recordset’s record pointer, your changes will be lost.<br />

Java<br />

myRS.open("SELECT * FROM Names", myConn,<br />

AdoEnums.CursorType.KEYSET, AdoEnums.LockType.OPTIMISTIC);<br />

...<br />

myRS.getField("LastName").setString("Smith");<br />

myRS.update();<br />

HAHTtalk Basic<br />

myRS.open "SELECT * FROM Names", myConn, adOpenKeyset, _<br />

adLockOptimistic<br />

...<br />

myRS.Fields("LastName") = "Smith"<br />

myRS.Update<br />

Inserting a record<br />

To insert a new record in a recordset, you perform the following steps:<br />

1 Add a new record to the recordset by calling the Recordset’s addNew<br />

method.<br />

2 Write data to the new record.<br />

3 Update the recordset.<br />

383


Appendix D: ADO Primer<br />

Java<br />

myRS.open("SELECT * FROM Names", myConn,<br />

AdoEnums.CursorType.KEYSET, AdoEnums.LockType.OPTIMISTIC);<br />

myRS.addNew();<br />

myRS.getField("FirstName").setString("John");<br />

myRS.getField("LastName").setString("Smith");<br />

myRS.update();<br />

HAHTtalk Basic<br />

myRS.open "SELECT * FROM Names", myConn, adOpenKeyset, _<br />

adLockOptimistic<br />

myRS.AddNew<br />

myRS.Fields("FirstName") = "John"<br />

myRS.Fields("LastName") = "Smith"<br />

myRS.Update<br />

Deleting a record<br />

Deleting a record is simple. You just position the current record pointer<br />

appropriately and call the Recordset’s delete method.<br />

Java<br />

myRS.open("SELECT * FROM Names", myConn,<br />

AdoEnums.CursorType.KEYSET, AdoEnums.LockType.OPTIMISTIC);<br />

myRS.find("FirstName = 'Jane'", 0,<br />

AdoEnums.SearchDirection.FORWARD);<br />

myRS.delete();<br />

HAHTtalk Basic<br />

myRS.open "SELECT * FROM Names", myConn, adOpenKeyset, _<br />

adLockOptimistic<br />

myRS.find "FirstName = 'Jane'", 0, adSearchForward<br />

myRS.Delete<br />

384


Closing a recordset<br />

A recordset is closed if:<br />

Appendix D: ADO Primer<br />

you allow the variable being used to address it to go out of scope<br />

you call the Recordset’s close method<br />

The examples below illustrate how to call the close method.<br />

Java<br />

myRS.close();<br />

myRS = null;<br />

HAHTtalk Basic<br />

myRS.Close<br />

Set myRS = Nothing<br />

385


Appendix D: ADO Primer<br />

386


ADO Extensions<br />

E<br />

What’s in this appendix ...............................................................................388<br />

Extensions to the Java interface...................................................................388<br />

ADO tracing in Java projects...................................................................388<br />

Additional appendChunk methods ........................................................390<br />

The Variant data type ..............................................................................390<br />

Extensions to the HAHTtalk Basic interface ................................................391<br />

ADO tracing in HAHTtalk Basic projects................................................391<br />

Functions for managing connections .....................................................391<br />

387


Appendix E: ADO Extensions<br />

What’s in this appendix<br />

<strong>HAHTsite</strong>’s ADO interface matches the Microsoft interface almost exactly.<br />

However, a few extensions have been introduced to make debugging ADO<br />

code easier, to make sure that Java and HAHTtalk Basic projects have the same<br />

capabilities, and just to make programming easier.<br />

This appendix contains two mains sections: one on extensions to the Java<br />

interface and one on extensions to the Basic interface. See the appropriate<br />

subsection below:<br />

388<br />

“Extensions to the Java interface” on page 388<br />

“Extensions to the HAHTtalk Basic interface” on page 391<br />

Extensions to the Java interface<br />

The main extensions to the Java interface are the addition of an ADO tracing<br />

facility, additional appendChunk methods, and the definition of a <strong>HAHTsite</strong><br />

Variant class.<br />

For information on these extensions, see the sections listed below:<br />

“ADO tracing in Java projects” on page 388<br />

“Additional appendChunk methods” on page 390<br />

“The Variant data type” on page 390<br />

ADO tracing in Java projects<br />

To help you debug your ADO code, <strong>HAHTsite</strong> adds an ADO-tracing feature. If<br />

you turn tracing on in your program, information about ADO operations is<br />

written to a log file. A sample trace file is shown below.


ADO tracing in a Java project<br />

Appendix E: ADO Extensions<br />

[17:15:07.848, 00173, 00162] setTracing (1)<br />

[17:15:07.858, 00173, 00162] com.haht.ado.Abstract.Connection<br />

conn1<br />

[17:15:07.858, 00173, 00162] conn1 = new com.haht.ado.Connection<br />

()<br />

[17:15:07.858, 00173, 00162] conn1.setProvider ("HSODBC")<br />

[17:15:07.858, 00173, 00162] conn1.open ("Provider=HSODBC;<br />

DSN=Employees;DBQ=C:\Stan\Employees.mdb;DriverId=25;FIL=MS<br />

Access;MaxBufferSize=512;PageTimeout=5;")<br />

[17:15:08.369, 00173, 00162] rs2.open ("SELECT * FROM Names",<br />

conn1, CursorTypeEnum.adOpenKeyset, LockTypeEnum.adLock<br />

Optimistic)<br />

[17:15:08.399, 00173, 00162] rs2.find ("FirstName = 'Jane'", 0,<br />

SearchDirectionEnum.adSearchForward)<br />

[17:15:08.429, 00173, 00162] rs2.update ()<br />

This trace file is written to the root directory of the drive on which the<br />

Application Server is installed (Windows NT) or /tmp (UNIX systems). The file<br />

is given a name of the form trace_ado_stateID.log.<br />

To turn ADO tracing on in a Java project<br />

Call the static method com.haht.ado.Constants.setTracing.<br />

The single argument to this method is a constant — or the bitwise OR of<br />

two or more constants — that indicates the type of tracing you are<br />

requesting. The constants you can use are listed in the table below.<br />

Note - The constants are static variables of the Constants<br />

class, so you should prepend com.haht.ado.Constants. to<br />

each constant.<br />

Constant Meaning<br />

adGeneralTracing logs many (but not all) of the ADO calls and<br />

their arguments. This type of tracing uses<br />

relatively little overhead and should not affect<br />

performance severely, unlike ODBC tracing.<br />

adTimingTracing adds End trace entries so that you can see how<br />

long some ADO calls took to complete<br />

389


Appendix E: ADO Extensions<br />

To turn ADO tracing off in a Java project<br />

390<br />

Constant Meaning<br />

adColTimingTracing times calls to Field.finalize,<br />

Field.getString, and Field.isNull<br />

adGetValTracing traces getDataType operations for Field<br />

objects<br />

adSetValTracing traces setDataType operations for Field<br />

objects<br />

Call setTracing with an argument of 0.<br />

Additional appendChunk methods<br />

Four appendChunk methods have been added for writing binary or textual data<br />

to fields and parameters.<br />

Class Methods<br />

Field public void appendChunk(byte[] bytes, int nBytes)<br />

public void appendChunk(char[] chars, int nChars)<br />

Parameter public void appendChunk(byte[] bytes, int nBytes)<br />

public void appendChunk(char[] chars, int nChars)<br />

Often the last chunk of data you need to append to a field or parameter does<br />

not fill the byte or character array you’re using as a buffer. These methods let<br />

you specify exactly how many bytes or characters you want to append with<br />

your final call to appendChunk.<br />

The Variant data type<br />

<strong>HAHTsite</strong> ADO methods that take a Variant as an argument, or return a<br />

Variant, use objects of the class com.haht.com.Variant, instead of<br />

com.ms.com.Variant.


Appendix E: ADO Extensions<br />

Extensions to the HAHTtalk Basic interface<br />

The principal extensions to the HAHTtalk Basic interface are the addition of<br />

an ADO-tracing feature and the inclusion of Basic functions/methods for<br />

working with private and shared connections.<br />

For further information on these subjects, see the sections listed below:<br />

“ADO tracing in HAHTtalk Basic projects” on page 391<br />

“Functions for managing connections” on page 391<br />

ADO tracing in HAHTtalk Basic projects<br />

The ADO-tracing feature discussed in “ADO tracing in Java projects” on page<br />

388 is also available in HAHTtalk Basic projects. To turn tracing on, you call<br />

the function setADOTracing, which requires one argument: a constant<br />

indicating the type of tracing you’re requesting. The constants you can use are<br />

the same as the constants you use in Java projects.<br />

Note - The argument to setADOTracing can also be the bitwise<br />

OR of two or more constants.<br />

Functions for managing connections<br />

In Java projects, you can use methods of the DMConnectionManager class to:<br />

open a private connection<br />

get a reference to a shared connection<br />

close a private connection<br />

These method return, or take as an argument, an object of type<br />

com.haht.ado.Abstract.Connection. In HAHTtalk Basic projects, you’re<br />

usually working with objects of type ADODB.Connection. <strong>HAHTsite</strong> provides<br />

the following functions/methods to provide a comparable interface in<br />

HAHTtalk Basic projects. The four functions listed below return an object of<br />

type ADODB.Connection:<br />

getSharedConnectionByID<br />

getSharedConnectionByName<br />

getPrivateConnectionByID<br />

getPrivateConnectionByName<br />

In addition, the class ADODB.Connection defines a closePrivateConnection<br />

method that you can use to close private connections.<br />

391


Appendix E: ADO Extensions<br />

For further information about private and shared connections, see Chapter 9,<br />

“<strong>Programming</strong> with the Connection Manager.”<br />

392


Index<br />

A<br />

access control 270<br />

enabling 272<br />

access package (Java) 5<br />

Active Server Pages 3<br />

ActiveX Data Objects (ADO) 6<br />

closing connections 379<br />

closing recordsets 385<br />

creating recordsets 380<br />

deleting records 384<br />

executing commands against<br />

connections 378<br />

finding records in recordsets 382<br />

<strong>HAHTsite</strong> extensions to 387<br />

inserting records 383<br />

navigating recordsets 381<br />

opening connections 376<br />

primer 375<br />

reading records 382<br />

updating records 383<br />

addPrivilege (Session class) 274<br />

Application class 298<br />

editing (Java projects) 25<br />

application directories<br />

for HAHTtalk Basic projects 70<br />

for Java projects 39<br />

Application object 97<br />

method summary 102<br />

retrieving properties 100<br />

variables 98<br />

application root directory 71<br />

approot 40, 71<br />

array datatypes 72<br />

attachments<br />

retrieving 122<br />

authenticating users<br />

using a Web server 288<br />

using the Login widget 277<br />

using the Server Object Model 286<br />

authentication class<br />

OSAuthentication 284<br />

user-defined 285<br />

Authentication interface 284, 285, 299<br />

authorizeUser (Authentication<br />

interface) 286<br />

B<br />

Breakpoint Manager 339<br />

breakpoints 338<br />

browser compatibility issues 249<br />

built-in objects 90<br />

getting references 91<br />

Button class 165<br />

button form fields 165<br />

associating user code with 183<br />

C<br />

CAB files 28<br />

Call Stack window 344<br />

Cascading Style Sheets 252<br />

check box form fields 167<br />

Checkbox class 167<br />

class declaration (Java projects) 19<br />

class files 28<br />

Client Scripts view 238, 240, 248<br />

client-side scripts<br />

See scripts<br />

closePrivateConnection<br />

(DMConnectionManager class) 232<br />

code editor<br />

HAHTtalk Basic projects 67<br />

Java projects 37<br />

code examples<br />

calling a subroutine from a form 362<br />

custom authentication class 373<br />

modifying a command handler 370<br />

code pages<br />

adding to a project 60<br />

saving<br />

HAHTtalk Basic projects 61<br />

COM objects<br />

using with HAHTtalk Basic 305<br />

combo box form fields 168<br />

Combo class 168<br />

command handlers 189<br />

changing the flow of control in 225<br />

customizing 216<br />

examples of customized handlers 217<br />

structure of 212<br />

common files (Java) 27<br />

393


Index<br />

Common Object Request Broker<br />

Architecture (CORBA) 9, 310<br />

building clients 315<br />

building servers 318<br />

in HAHTtalk Basic projects 329<br />

Naming Service 329<br />

compiler<br />

HAHTtalk Basic 69<br />

finding compile-time errors 69<br />

Java 38<br />

debug option 39<br />

finding compile-time errors 39<br />

Connection class (ADO) 376<br />

connections<br />

closing 379<br />

executing commands against 378<br />

opening 230, 376<br />

constructor (Java projects) 19<br />

cookies<br />

cookie collections 121, 128<br />

multiple cookies with the same<br />

name 122<br />

retrieving cookie values 121<br />

setting 127<br />

corba package (Java) 5<br />

createFileURL (Session class) 111<br />

createMapURL (Session class) 111<br />

createPageURL (Session class) 111<br />

createStaticURL (Session class) 113<br />

custom Form Handler widgets 145<br />

creating 152<br />

writing the form-handler<br />

function 145<br />

D<br />

data agents 188<br />

enabling tracing 210<br />

filtering records 205<br />

getting a reference to a data agent’s<br />

connection 198<br />

getting a reference to a data agent’s<br />

recordset 200<br />

getting parameters to stored<br />

procedures 202<br />

getting the values of data-agent<br />

fields 196<br />

handling errors 210<br />

limiting the maximum number of<br />

records 199<br />

making a recordset read only 199<br />

performing an action 192<br />

394<br />

refreshing data 203<br />

setting a data agent’s command 190<br />

setting the values of data-agent<br />

fields 196<br />

sorting records 204<br />

data types<br />

C/C++and HAHTtalk Basic 304<br />

datamanager package (Java) 4<br />

datatypes<br />

arrays 72<br />

scalars 72<br />

debugger windows 340<br />

Call Stack window 344<br />

Output window, Debug tab 341<br />

Threads window 345<br />

Variable window 341<br />

Watch window 343<br />

debugging 10, 332<br />

compiling with debug option 39<br />

executing code 336<br />

procedure stepping 338<br />

requirements for 332<br />

single stepping 337<br />

starting a session 333<br />

using breakpoints 338<br />

directives, precompiler (HAHTtalk Basic<br />

projects) 64<br />

directories<br />

static root 70<br />

distributed-object applications 310<br />

DLLs<br />

datatype mapping 304<br />

DMConnectionManager class 230<br />

document object models 237, 250<br />

browsing 241<br />

Dynamic HTML 252<br />

dynamic pages<br />

calling from HAHTtalk Basic 65<br />

calling from Java 30<br />

E<br />

enabling access control 272<br />

endHeaders (Response class) 126<br />

environment variables<br />

retrieving 122<br />

error handler<br />

HAHTtalk Basic projects 60<br />

event handling<br />

in Java projects 31<br />

exception handler<br />

Java projects 23


exit handler<br />

HAHTtalk Basic projects 59<br />

expressions<br />

HAHTtalk Basic 49<br />

formatting 50<br />

in dialog boxes 50<br />

Java projects<br />

formatting 15<br />

in dialog boxes 15<br />

F<br />

File Upload class 168<br />

File Upload form fields 140, 168<br />

adding to a page 141<br />

files<br />

submitting with forms 140<br />

form<br />

method 117<br />

form fields 163<br />

buttons 165<br />

check boxes 167<br />

combo boxes 168<br />

File Upload 140, 168<br />

list boxes 169<br />

radio buttons 175<br />

setting properties of 156<br />

text areas 178<br />

text boxes 178<br />

form handler<br />

HAHTtalk Basic projects 56<br />

Java projects 23<br />

Form Handler widgets<br />

custom 145<br />

creating 152<br />

writing the form-handler<br />

function 145<br />

form handlers 212<br />

form package (Java) 4<br />

FormField class 163<br />

forms<br />

calling subroutines from 134<br />

submitting files with 140<br />

G<br />

GateKeeper 329<br />

GET and POST methods 117<br />

getAppData (Application class) 100<br />

getBOF (Recordset class) 159<br />

getCookie (Request class) 121<br />

getDirName (Application class) 40, 71<br />

Index<br />

getEOF (Recordset class) 159<br />

getError (DataAgent class) 210<br />

getErrorCount (DataAgent class) 210<br />

getRecordset (DataAgent class) 200<br />

getServerVariable (Request class) 122<br />

getServerVariableCount (Request<br />

class) 122<br />

getSharedConnectionByName<br />

(DMConnectionManager class) 231<br />

getStaticRoot (Application class) 40, 70<br />

getStaticURL (Session class) 40, 70<br />

getURL (Session class) 109<br />

getURLAttachment (Request class) 144<br />

getURLAttachmentCount (Request<br />

class) 122<br />

getURLAttachmentExists (Request<br />

class) 122, 143<br />

getURLAttachmentType (Request<br />

class) 122<br />

getURLField (Request class) 119<br />

getURLFieldCount (Request class) 119<br />

getURLFieldExists (Request class) 119<br />

getUserRoot (Application class) 40, 71<br />

getValue (FormField class) 182<br />

getWriter (Response class) 129<br />

Globals.hbs 63, 64<br />

H<br />

HahtApplication.java 25<br />

HahtSession.java 25<br />

<strong>HAHTsite</strong> Server Object Model, See<br />

Server Object Model 89<br />

HAHTtalk Basic 2<br />

compared to Visual Basic 72<br />

compiling 69<br />

data types 72<br />

editing code 67<br />

error handling 73<br />

file I/O 73<br />

help for keywords 69<br />

naming conventions 72<br />

subroutines and functions 73<br />

syntax checking 69<br />

using COM objects 305<br />

variable scope 72<br />

HAHTtalk Basic projects<br />

adding code pages to a project 60<br />

and server-side code view 52<br />

calling dynamic pages 65<br />

calling external logic 47<br />

code editor 67<br />

395


Index<br />

error handler 60<br />

event handling 66<br />

exit handler 59<br />

generated code for a page 53<br />

Globals.hbs 63<br />

include files 53, 63<br />

in-line code 48<br />

naming conventions 62<br />

page entry point 57<br />

precompiler directives 64<br />

server-side code 46<br />

working with 46<br />

headers<br />

adding content information 127<br />

testing for "in headers" 127<br />

writing 126<br />

hsSecurityPrivileges database table 290<br />

HTML<br />

writing 129<br />

HTML Tags view 246<br />

HtmlOut 260<br />

HAHTtalk Basic example 262<br />

HAHTtalk Basic include files 260<br />

HAHTtalk Basic routines 261<br />

Java class 264<br />

Java example 265<br />

HtmlWriter 129<br />

I<br />

IDL compiler 311<br />

IDL files 311<br />

import statements (Java projects) 19<br />

include files<br />

and HAHTtalk Basic projects 53<br />

external includes (HAHTtalk Basic<br />

projects) 63<br />

in HAHTtalk Basic projects 63<br />

project includes (HAHTtalk Basic<br />

projects) 63<br />

inHeaders (Response class) 127<br />

in-line code<br />

expressions<br />

Java projects 14<br />

in HAHTtalk Basic projects 48<br />

statements<br />

Java projects 15<br />

insertElementAt (Listbox class) 172<br />

Internet Explorer 249<br />

isMultiple (Listbox class) 172<br />

isNewApp (Session class) 113<br />

396<br />

J<br />

JAR files 28<br />

Java<br />

class files 28<br />

code editor 37<br />

compiling 38<br />

file types 27<br />

files<br />

adding to a project 26<br />

JAR files 28<br />

Java class directory 71<br />

Java projects<br />

application directories 39<br />

event handling 31<br />

exception handler 23<br />

form handler 23<br />

in-line code 13<br />

naming conventions 30<br />

page, generated code for 18<br />

server-side code 12<br />

server-side code view 17<br />

writing HTML output 23<br />

javaroot 71<br />

JavaScript 237, 238, 249<br />

L<br />

layers (Netscape) 252<br />

list box form fields 169<br />

adding elements to a list 171<br />

finding an item in a list 173<br />

getting and setting properties 173<br />

selecting an element in a list 172<br />

list elements<br />

creating 169<br />

getting and setting properties 171<br />

Listbox class 169<br />

ListElement class 169<br />

logging in to an application 276<br />

Login widget 277, 279<br />

lookupPrivileges (UserProfile<br />

interface) 292<br />

M<br />

methods<br />

calling from dialog boxes<br />

Java projects 17<br />

WebApp object 350


N<br />

naming conventions<br />

Java 30<br />

Naming Service 329<br />

Netscape Layers 252<br />

Netscapte Navigator 249<br />

O<br />

onEnd (Application class) 31<br />

onEnd (Session class) 31<br />

onSessionEnd (Application class) 31<br />

example 33<br />

onSessionStart (Application class) 31<br />

example 33<br />

onStart (Application class) 31<br />

onStart (Session class) 31<br />

openPrivateConnectionByName<br />

(DMConnectionManager class) 232<br />

out.print statement 129<br />

P<br />

package statement (Java projects) 19<br />

Packages folder (Java projects) 26<br />

page<br />

run method (Java projects) 20<br />

page structure<br />

HAHTtalk Basic projects 53<br />

Java projects 20<br />

performAction (DataAgent class) 193<br />

precompiler directives (HAHTtalk Basic<br />

projects) 64<br />

print 129<br />

printing<br />

Java projects 23<br />

private connections 230<br />

closing 232<br />

opening 232<br />

privilege repository 289<br />

privilege-lookup class<br />

DBUserProfile 291<br />

user-defined 292<br />

privileges 270<br />

adding to a project 272<br />

assigning to a page 273<br />

assigning to a session 273<br />

granting to users who log in to an<br />

application 276<br />

looking up in a database 290<br />

looking up in a nondatabase<br />

repository 291<br />

looking up using the Server Object<br />

Model 293<br />

required 270<br />

session 270<br />

Privileges class 5, 298<br />

project package (Java) 3<br />

pseudo methods, for WebApp<br />

object 352<br />

PUBLISH_OS 64<br />

PUBLISH_SERVERGROUP 64<br />

PUBLISH_SITENAME 64<br />

PUBLISH_WEBSERVER 64<br />

R<br />

radio button form fields 175<br />

Radiobutton class 175<br />

Recordset class (ADO) 380<br />

recordsets<br />

closing 385<br />

creating 380<br />

deleting records 384<br />

finding records in 382<br />

getting references to 200<br />

getting the values of fields in a<br />

record 196, 382<br />

inserting records 383<br />

limiting the maximum number of<br />

records 199<br />

making read only 199<br />

navigating 381<br />

performing actions against 192<br />

refreshing the data in 203<br />

setting the values of fields in a<br />

record 196<br />

sorting records 204<br />

updating records 383<br />

referred projects 93<br />

Request object 117<br />

attachments 122<br />

environment variables 122<br />

field values, retrieving 117<br />

method summary 123<br />

references to<br />

in HAHTtalk Basic projects 59<br />

in Java projects 22<br />

retrieving cookie values 121<br />

required privileges 270<br />

Response object 126<br />

cookies 127<br />

headers 126<br />

method summary 130<br />

Index<br />

397


Index<br />

references to<br />

in HAHTtalk Basic projects 59<br />

in Java projects 22<br />

writing HTML output 129<br />

Retrieving 117<br />

run method (Java projects) 20<br />

arguments 20<br />

S<br />

scalar datatypes 72<br />

script functions 238, 244<br />

scripts 8, 236<br />

choosing a language 238<br />

event handlers 238<br />

in-line 238, 243<br />

page-scope functions 238, 244<br />

with server-side expressions 257<br />

secure-static pages 270<br />

security 270<br />

Server Object Model 3, 89<br />

Application object 97<br />

built-in objects 90<br />

Request object 117<br />

Response object 126<br />

Session object 107<br />

server-side code view 52, 217<br />

Java projects<br />

17<br />

server-side Java<br />

called from HAHTtalk Basic 76<br />

case sensitvity 80<br />

CreateJavaObject function 77, 78<br />

CreateTypedJavaNull function 78<br />

differences between HAHTtalk Basic<br />

and Java 79<br />

GetJavaClass function 78<br />

locating objects 80<br />

mapping data types 83<br />

mapping parameter types 81<br />

runtime errors 84<br />

Session class 297<br />

editing (Java projects) 25<br />

Session object 107<br />

creating a static URL 113<br />

creating a URL 109, 111<br />

method summary 114<br />

state 107<br />

timeout 108<br />

variables 107<br />

session privileges 270<br />

398<br />

session state 107<br />

session timeout 108<br />

setAuthenticationClassByName<br />

(Application class) 285<br />

setCommand (DataAgent class) 190<br />

setCommandType (DataAgent class) 191<br />

setContentType (Response class) 127<br />

setCookie (Response class) 127<br />

setDisplayText (StaticText class) 176<br />

setInitialAction (DataAgent class) 195<br />

setLabel (FormField class) 160<br />

setMaxRecords (DataAgent class) 199<br />

setMultiple (Listbox class) 172<br />

setPictureURL (Button class) 166<br />

setPostSort (DataAgent class) 204<br />

setPreFilter (DataAgent class) 208<br />

setPreSort (DataAgent class) 204<br />

setReadOnly (DataAgent class) 199<br />

setStyle (Button class) 166<br />

setTracing (DataAgent class) 211<br />

setUserProfileClassByName (Application<br />

class) 292<br />

setValue (FormField class) 160, 182<br />

setVisible (FormField class) 159<br />

setWriter (Response class) 129<br />

shared connections 230<br />

opening or getting a reference to 231<br />

SmartAgent 329<br />

state 107<br />

statements<br />

HAHTtalk Basic 49<br />

static root directory 40, 70<br />

static URL 70<br />

StaticText class 176<br />

stored procedures<br />

getting the values of output<br />

parameters 202<br />

subroutines<br />

and dialog boxes 51<br />

as form actions 134<br />

T<br />

text area form fields 178<br />

text box form fields 178<br />

TextArea class 178<br />

Textbox class 178<br />

Threads window 345<br />

timeout 108<br />

tracing, enabling 210


U<br />

URL<br />

creating 109, 111<br />

user code<br />

associating with a button 183<br />

User Login Page template 278<br />

UserProfile interface 292, 299<br />

userroot 40, 71<br />

V<br />

Variable window 341<br />

variables 107<br />

and multiple processes 99<br />

Application object 98<br />

global (HAHTtalk Basic projects) 64<br />

locking 99<br />

VBScript 237, 238, 249<br />

VisiBroker for Java 310<br />

GateKeeper 329<br />

installing 329<br />

interoperability with other ORBs 328<br />

SmartAgent 329<br />

W<br />

Watch window 343<br />

watched variables<br />

adding 343<br />

removing 344<br />

WebApp object<br />

methods 350<br />

pseudo methods 352<br />

whoAmI (Session class) 114<br />

whoCalledMe (Session class) 114<br />

writeBinary (Response class) 129<br />

Z<br />

ZIP files 28<br />

Index<br />

399


Index<br />

400

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!