HAHTsite IDE Programming Guide - Product Documentation
HAHTsite IDE Programming Guide - Product Documentation
HAHTsite IDE Programming Guide - Product Documentation
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(" \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