Previous Contents Index DocHome Next |
iPlanet Application Server Programmer's Guide (Java) |
Chapter 13 Taking Advantage of iAS Features
This chapter describes how to implement iAS features in your application.iAS provides many additional features to augment your servlets for use in a iAS environment. These features are not a part of the official servlet specification, though some, like the servlet security paradigm described in Chapter 12 "Writing Secure Applications" are based on emerging Sun standards and will conform to those standards in the future.
This chapter contains the following sections:
Accessing the Servlet Engine
Accessing the Servlet Engine
The servlet engine controls all servlet functions, including instantiation, destruction, service methods, request and response object management, and input and output. The servlet engine in iAS is a special class called an AppLogic. AppLogics are iAS components that interact with the core server. In previous releases of iAS, AppLogics were a part of the application model, though for current and future releases they are solely available to access iAS internal features.Each servlet is scoped in an AppLogic. You can access the AppLogic instance controlling your servlet using the method getAppLogic() in the iAS feature interface HttpServletRequest2. When you do this, you also gain access to server context. These activities are necessary to take advantage of other iAS features, as described in the other sections in this chapter.
Accessing the Servlet's AppLogic
To access the controlling AppLogic, cast the request object as an HttpServletRequest2. This interface provides access to the AppLogic via the method getAppLogic(), which returns a handle to the superclass.The following example servlet header shows how to access the AppLogic instance:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.kivasoft.applogic.*;
import com.kivasoft.types.*;
import com.netscape.server.servlet.extension.*;
public class AppLogicTest extends HttpServlet {
public void service(HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException
{
HttpServletRequest2 req2 = (HttpServletRequest2)req;
AppLogic al = req2.getAppLogic();
//al is now a handle to the superclass
...
Accessing the Server Context
Some iAS features, such as Application Events (see Using Application Events), require an IContext object. IContext defines a view of the server context. For more information about IContext, see the entry for the IContext interface in the iAS Foundation Class Reference.To obtain an IContext from a servlet, the standard servlet context can be cast to IServerContext, and from there, a com.kivasoft.IContext instance can be obtained, as in the following example:
ServletContext ctx = getServletContext();
com.netscape.server.IServerContext sc;
sc = (com.netscape.server.IServerContext) ctx;
com.kivasoft.IContext kivaContext = sc.getContext();Alternatively, you can access the underlying AppLogic instance from a servlet, as described in Accessing the Servlet's AppLogic, and obtain the context from the AppLogic's context member variable, as in the following example:
HttpServletRequest2 req2 = (HttpServletRequest2)req;
AppLogic al = req2.getAppLogic();
com.kivasoft.IContext kivaContext = al.context;From an EJB, the standard javax.ejb.SessionContext or javax.ejb.EntityContext can be cast to IServerContext, and from there, a com.kivasoft.IContext instance can be obtained, as in the following example:
javax.ejb.SessionContext m_ctx;
....
com.netscape.server.IServerContext sc;
sc = (com.netscape.server.IServerContext) m_ctx; /
com.kivasoft.IContext kivaContext;
kivaContext = sc.getContext();
Caching Servlet Results
iAS has the ability to cache the results of a servlet in order to make subsequent calls to the same servlet faster. iAS caches the results of a request (i.e. a servlet's execution) for a specific amount of time, so that if another call for that data happens, iAS can just return the cached data rather than having to perform the operation again. For example, if your servlet returns a stock quote that you only want to update every 5 minutes, you could set the cache to expire after 300 seconds.Whether to cache results, and how to cache them, depends on the type of data involved. It makes no sense to cache the results of a quiz submission, for example, because the input to the servlet is different each time. However, you could cache a high-level report showing demographic data taken from quiz results and updated once an hour.
You can define how an iAS servlet handles memory caching by editing specific fields in the servlet's configuration file. In this way, you can create programmatically standard servlets that still take advantage of this valuable iAS feature. For more information on servlet configuration files, see Chapter 10 "Packaging for Deployment ".
Set the following variables in the ServletData section of the servlet's configuration file:
You use the CacheCriteria field to set criteria used to determine whether the results of a servlet should be cached. The CacheCriteria field contains a test for one or more fields in the request. This allows you to conditionally cache results based on the value or presence of one or more form fields. If the tests succeed, the servlet results are cached.
Use the follow syntax for the CacheCriteria field:
Using Application Events
In an iAS environment, you can create and use named events. The term event is widely used to refer to user actions, such as mouse clicks, that trigger code. However, the events described in this section are not caused by users. Rather, an event is a named action that you register with the iAS. The event occurs either when a timer expires or when the event is activated from application code at run time.Events are stored persistently in the iAS, and are removed only when your application explicitly deletes them. Typical uses for events include periodic backups, reconciling accounts at the end of the business day, or sending alert messages. For example, you can set up an event that sends an email to alert your company's buyer when inventory levels drop below a certain level.
Each event has a name, a timer (optional), and one or more actions to take when the event is triggered. Application events have the following characteristics:
Each event can cause the execution of one or more actions, which can include sending email or calling another application component.
You can set up events to occur at specific times or at intervals, such as every hour or once a week. You can also trigger an event by calling the event by name from code. When an event's timer goes off or it is called from code, the associated action occurs.Actions can be synchronous or asynchronous with the calling environment.
Multiple actions can be configured to execute concurrently with one another, or serially, one after the other.
Multiple actions are executed in a specific order (the order in which they are registered).
Request data can be passed to an application event in an IValList object.
The Application Events API
iAS uses two interfaces to support events:
The IAppEventMgr interface manages application events. This interface defines methods for creating, registering, triggering, enabling, disabling, enumerating, and deleting events.
These two interfaces are described in the following sections.The IAppEventObj interface represents the defined events an application supports. This interface defines methods not only for getting or setting attributes of an event, but also for adding, deleting, or enumerating actions of the event.
The IAppEventMgr Interface
You can perform any of the following administrative tasks with an event by using the associated methods in the IAppEventMgr interface:
The IAppEventObj Interface
The event's behavior is determined by its attributes, which define how and when an event executes, and its actions, which define what the event does when it is triggered. To set and examine attributes and actions, use the methods in the IAppEventObj interface:
Table 13-4 IAppEventObj Methods
Creating a New Application Event
Follow these steps to create a new application event and register it with iAS. For more information about the interfaces and methods described in each step, see the entries for IAppEventMgr and IAppEventObj in the iAS Foundation Class Reference.Note A com.kivasoft.IContext object is required to create an event. For more information, see Accessing the Server Context.
You first need the context parameter, an IContext object which provides access to iAS services. Obtain the context parameter from the server context IServerContext, as in the following example:
ServletContext ctx = getServletContext();
com.netscape.server.IServerContext sc;
sc = (com.netscape.server.IServerContext) ctx;
com.kivasoft.IContext ic = sc.getContext();Next, use the GetAppEventMgr() method in the GXContext class to create an IAppEventMgr object:
IAppEventMgr mgr = com.kivasoft.dlm.GXContext.GetAppEventMgr(ic);
After creating the IAppEventMgr object, you can create an application eventan instance of IAppEventObjby calling createEvent() on the IAppEventMgr object, as in the following example:
IAppEventObj evtObj = mgr.createEvent("myEvent");
You now have an empty event in the system. Create an IValList object to hold the event's attributes, and then set the attributes to the requirements you have for this event. Finally, assign the attributes to your event. For example, this event executes at 5:00 AM every morning:
IValList atts = GX.CreateValList();
atts.setValString(GXConstants.GX_AE2_RE_KEY_TIME, "5:0:0 */*/*");
evtObj.setAttributes(atts);You can assign actions to the event in order to cause it to do something when it is triggered. This procedure is similar to creating event attributes; first create an IValList object to contain the actions, then assign them to the event. For example, this event runs a servlet called myServlet:
IValList action = GX.CreateValList();
action.setValString(GXConstants.GX_AE2_RE_KEY_SERVLET, "myServlet");
evtObj.addAction(action);You must then register the event, or make iAS aware of it, by calling registerEvent(). Further, you must also instruct iAS to enable the event for access by calling enableEvent(). The following example shows the registration and enabling of an event:
if (mgr.registerEvent("myEvent", evtObj) != GXE.SUCCESS)
return streamResult("Cannot register RepGenEvent<br>");Once the event is registered and enabled, you can trigger it by hand if you want. To trigger the event, use the IAppEventMgr method triggerEvent(), as in the following example:
Sending and Receiving Email from iAS
iAS supports email transactions through the IMailbox interface. For more information, see the entry for the IMailbox interface in the iAS Foundation Class Reference.In order for email applications to work, you must have access to an SMTP server if you want to send email and a POP server if you want to receive email.
Security in Email
Security is often a concern when sending or receiving email. If the application generates and sends email using user input to set the address or content, then there is a risk of propagating inappropriate messages or mailing to incorrect recipients. Be sure to validate all user input before incorporating it in email.
Accessing the Controlling AppLogic
Using the IMailbox interface from a servlet requires access to the AppLogic instance that controls the servlet's functions. For more information, see Accessing the Servlet Engine.For example, before you can use the IMailbox interface, create a handle to the AppLogic instance that controls your servlet:
HttpServletRequest2 req2 = (HttpServletRequest2)req;
AppLogic al = req2.getAppLogic();The examples in this section assume that the above code exists in your servlet.
Receiving Email
To receive email, your application must have access to a POP server.Before retrieving messages, you can use retrieveCount() to see how many messages are waiting in the specified inbox on the mail server. By checking first, you can avoid attempting to retrieve messages if the mailbox is empty. You can also use this technique when you need to know how many messages are waiting in order to construct a loop that iterates through them one by one.
To retrieve messages, call retrieve(). Depending on the parameters you pass to this method, you can customize the retrieval process in the following ways:
Retrieve all messages
Only those messages received before the last call to open() are retrieved. You can not open a mailbox session, leave it open, and continuously receive email messages. Instead, you must open a new session each time you want to retrieve new email.After retrieving messages, you can return the mailbox to its original state by calling retrieveReset(). This method undeletes and unmarks any messages that were affected by the previous retrieve() call.
To receive email
Create an instance of IMailbox by calling createMailbox() from the servlet's controlling AppLogic instance (Accessing the Controlling AppLogic). In this call, you specify valid user information and the name of the POP server you want to access. For example:
You can have only one mail server session open at a time. For example, suppose you open a session with the OPEN_RECV flag, then want to send email. You must first close the existing session, then open another one with the OPEN_SEND flag.mb = al.createMailbox("mail.myOrg.com","myUserName",
Open a session on your POP server by calling open() with the OPEN_RECV flag. For example:
result = mb.open(GX_MBOX_OPEN_FLAG.OPEN_RECV);
To find out whether you have messages, call retrieveCount(). For example:
int mbCount = mb.retrieveCount();
To retrieve messages, instantiate an IValList object to contain the email messages, then call retrieve(). For example, the following code retrieves the latest unread messages and does not delete them from the mailbox:
IValList messages = GX.CreateValList();
messages = mb.retrieve(true, false);To undo changes, call retrieveReset(). For example:
Example
The following code retrieves email in a servlet:// Create mailbox object to connect to a POP mail server
IMailbox recvMB;
public void recvMail()
{
// Only check messages received after the last open
boolean Latest = true;
// Remove retrieved messages from the mail server
boolean Delete = true;
// Create an IMailbox instance
HttpServletRequest2 req2 = (HttpServletRequest2)req;
AppLogic al = req2.getAppLogic();
IMailbox recvMB;
recvMB = al.createMailbox(recvhost, user, pswd, useraddr);
if (recvMB != null)
{
if (recvMB.open(GX_MBOX_OPEN_FLAG.OPEN_RECV))
{
// Count the number of new messages
int numMsgs = recvMB.retrieveCount();
if(numMsgs > 0)
{
IValList mesgList;
// Retrieve the new messages
mesgList = recvMB.retrieve(Latest,Delete);
// Use IValList methods to iterate through
// the returned IValList. The keys in the
// IValList are the message numbers. The
// values are the email messages as strings
}
recvMB.close();
}
}
}
Sending Email
To send email, your application must have access to an SMTP server. Construct the email address and message separately, then use the send() method to send the email out through the server.You can send email to a single recipient or to a group of recipients. To send email to a group, use one of the following techniques:
Pass the email addresses to send() as an array.
You can populate an address array dynamically using the results of a query, in which each row returned by the query is one email address. Use a loop to iterate through the rows in the query's result set and assign the data to successive elements of the array.
To send email
Create an instance of IMailbox by calling createMailbox() from the servlet's controlling AppLogic instance (Accessing the Controlling AppLogic). In this call, you specify valid user information and the name of the POP server you want to access. For example:
You can have only one mail server session open at a time. For example, suppose you open a session with the OPEN_SEND flag, then want to retrieve your email. You must first close the existing session, then open another one with the OPEN_RECV flag.IMailbox mb;
mb = al.createMailbox("mail.myOrg.com",
"myUserName",
"pass7878",
"sid@blm.org");Open a session on your SMTP server by calling open() with the OPEN_SEND flag. For example:
int result = mb.open(GX_MBOX_OPEN_FLAG.OPEN_SEND);
To send the message, call send(). Pass a single email address or an array of addresses to this method, along with the text of the message. For example:
java.lang.String[] ppTo = {"sal@dat.com","sid@blm.com",null};
int mbSend = mb.send(ppTo,"Testing email");
Example
The following code sends email in a servlet:// Define the string parameters that will be passed
// to IMailbox methods
String sendhost = "smtp.kivasoft.com";
String recvhost = "pop.kivasoft.com";
String user = "eugene";
String pswd = "eugenesSecretPassword";
String useraddr = "eugene@kivasoft.com";
String sendTo[] = {"friend@otherhost.net", null};
String mesg = "Hi Friend, How are you?";
public void sendMail()
{
// Create an IMailbox instance
HttpServletRequest2 req2 = (HttpServletRequest2)req;
AppLogic al = req2.getAppLogic();
IMailbox sendMB;
sendMB = al.createMailbox(sendhost, user, pswd, useraddr);
if (sendMB != null) // sendMB successfully created
{
// Open a session with the mail server
if (sendMB.open(GX_MBOX_OPEN_FLAG.OPEN_SEND))
{
// Send a mail message
sendMB.send(sendTo,mesg);
// Close the mailbox session
sendMB.close();
}
}
}
iAS Application Builder Features
iAS includes APIs that were designed for use by the code generated from iAS Application Builder (iAB) wizards. These APIs are available to servlet programmers, although we recommend that you use iAB to create servlets that use these features.The features presented here include:
Validating Form Field Data
Validating Form Field Data
You can set a servlet to automatically check form fields for certain types of values. Additionally, you can create a named error handler to control application flow if the validation fails.In short, you specify the rules for validation in a servlet's configuration file, and then call the HttpServletRequest2 method validate() to test the fields against the validation rules. If validation fails, you can let iAS generate an error page automatically, or you can provide an error handler method in your servlet to produce an error message.
Validation Methods
iAS provides a method called validate() that validates all the form fields configured in the servlet's configuration file. This method is defined in the iAS feature interface HttpServletRequest2. To use this interface, cast the standard request object to it, as in the following example:public void service (HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException
{
HttpServletRequest2 req2 = (HttpServletRequest2) req;There are two method signatures for validate(), as shown here:
public boolean validate(HttpServletResponse response)
throws IOException;public boolean validate(HttpServletResponse response,
HttpServlet servlet,
String errHandlerName)
throws ServletException, IOException;In the first form, if a validation error occurs, the system automatically generates an error response page. In the second form, you pass a servlet and method name in the servlet and errHandlerName parameters, respectively, that correspond to a named error handler that you write. (See Error Handlers)
validate() returns true if the input matches the validation rule, or false otherwise.
Validation Rules
Input data are validated based on the rules configured for each form field in the servlet's configuration file, in the Parameters section. This section resides in the ServletData section. The Parameters section enables you to specify the following information for each form field:
You can also specify a flag inputRequired (set to y or n) for each parameter. This flag indicates whether the specified value must exist in the input stream. If the variable is not present, validation fails.
For more information about the Parameters section in servlet configuration files, see "Web Application XML DTD" in Chapter 10 "Packaging for Deployment".
The following types of data can be checked:
Data consists only of 10 digits and optionally the characters (, ), and -.
Data consists only of numbers and the characters (, ), +, and -.
Error Handlers
You can create methods in your servlet to handle specific validation failures. These methods are called error handlers, and generally follow this method signature:public void myErrorHandler(HttpServletRequest req,
HttpServletResponse res);Use this method to generate an error page if the validate() method returns false, indicating a validation error. (For information on the validate() method, see Validation Methods).
You can examine the type of error using an error vector of type Vector, using the following methods in the HttpServletRequest2 interface:
The following table shows the error code and message associated with each validation rule:
Example Validation Rules
The following example shows the Parameters section from a servlet configuration file. This section describes a form consisting of several parameters, including a name, social security number, an address, an email address, and a US phone number:"Parameters" NTV {
"name" NTV {
"inputRequired" Str "y",
},
"zip" NTV {
"inputRequired" Str "y",
"inputRule" Str "VALIDATE_US_ZIPCODE ",
},
"ssn" NTV {
"inputRequired" Str "y",
"inputRule" Str "VALIDATE_SSN",
},
"email" NTV {
"inputRequired" Str "n",
"inputRule" Str "VALIDATE_EMAIL",
},
"phone" NTV {
"inputRequired" Str "y",
"inputRule" Str "VALIDATE_US_PHONE",
}
}In this example, the user does not need to supply an email address but must supply a name, zip code, a social security number, and a US phone number in the form. The zip code, social security number, phone number, and email (if it is present) are checked for valid data.
Note that this validation does not fail if the email value is missing, only if it is present and does not match the VALIDATE_EMAIL rule.
Creating Named Form Action Handlers
You can create methods that handle particular buttons on a form. This enables you to build in a level of modularity to your servlet to handle requests cleanly.Form handlers are used in code generated by Netscape Application Builder (NAB). Usage consists of two methods in the HttpServletRequest2 interface, coupled with entries in the servlet's configuration file.
Use the following methods in service() (generic servlets) or doGet() or doPost() (HTTP servlets) to handle requested actions. These methods reside in the HttpServletRequest2 interface. Note that you must also configure form action handlers in the FormActionHandlers section of the servlet's configuration file.
Example Validation and Form Action Handler
This example shows a servlet and its configuration file. The servlet performs some validation on the incoming request and then passes it to a form action handler called submitHandler().
Servlet Configuration File
NTV-ASCII {
"DispatchServlet" NTV {
"ServletRegistryInfo" NTV {
"type" Str "j",
"enable" Str "y",
"encrypt" Str "n",
"lb" Str "y",
"descr" Str "Testing action dispatch",
"group" StrArr ["Actions"],
"guid" Str
"{6952A1AC-FED2-1687-9BB6-080020A1689 6}",
},
"ServletRunnerInfo" NTV {
"ServletClassPath" Str
"com.netscape.server.servlet.test.TestDispatchServl et",
},
"ServletData" NTV {
"FormActionHandlers" NTV {
"submitAction" Str "submitHandler",
},
},
},
}import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* An HTTP Servlet that responds to the GET and HEAD methods of the
* HTTP protocol. It returns a form to the user that gathers data.
* The form POSTs to another servlet.
*/
public class TestDispatchServlet extends HttpServlet {
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// Get the user's session and shopping cart
out.println("<html>"
+ "<head><title> TestDispatch </title></head>"
+ "<body bgcolor=\"#ffffff\">\n"
+ "<br>");
out.println("<form action=\""
+ response.encodeUrl("/servlet/DispatchServlet")
+ "\" method=\"post\">"
+ "<strong>Please Update your account information"
+ "</strong><br><br><br>"
+ "<table>"
+ "<tr>"
+ "<td><strong>Your Name:</strong></td>"
+ "<td><input type=\"text\" name=\"personname\""
+ "\" size=\"19\"></td>"
+ "</tr>"
+ "<tr>"
+ "<td><strong>Account ID:</strong></td>"
+ "<td><input type=\"text\" name=\"accountID\""
+ "\" size=\"19\"></td>"
+ "</tr>"
+ "<tr>"
+ "<td><strong>Your Password:</strong></td>"
+ "<td><input type=\"password\" name=\"password1\""
+ "\" size=\"19\"></td>"
+ "</tr>"
+ "<tr>"
+ "<td><strong>Match Password:</strong></td>"
+ "<td><input type=\"password\" name=\"password2\""
+ "\" size=\"19\"></td>"
+ "</tr>"
+ "<tr>"
+ "<td></td>"
+ "<td><input type=\"submit\" name=\"submitAction\""
+ "value=\"Submit Information\"></td>"
+ "</tr>"
+ "</table>"
+ "</form>"
+ "</td></tr></table></body>"
+ "</html>");
out.close();
}
public void doPost (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
HttpServletRequest2 newReq = (HttpServletRequest2) request;
if( newReq.validate(response)) {
newReq.dispatchAction(response,this);
}
}
public int submitHandler ( HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String p1 = request.getParameter("password1");
String p2 = request.getParameter("password2");
if( p1 == null ||
p2 == null ||
! p1.equals(p2) )
{
out.println("<html>"
+ "<head><title> TestDispatch </title></head>"
+ "<body bgcolor=\"#ffffff\">\n"
+ "<br><br>Your password does not match! "
+ "Please try again"
+ "</body>"
+ "</html>");
out.close();
return HttpServletRequest2.ERROR_USER;
}
out.println("<html>"
+ "<head><title> TestDispatch </title></head>"
+ "<body bgcolor=\"#ffffff\">\n"
+ "<br><br>Your Account information: <br><br>"
+ "<br>Your name: "
+ request.getParameter("personname")
+ "<br>Account ID: "
+ request.getParameter( "accountID")
+ "<br><br>Updated successfully in the database"
+ "</body>"
+ "</html>");
out.close();
return HttpServletRequest2.NO_ERROR;
}
}
Previous Contents Index DocHome Next
Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.
Last Updated June 25, 2000