Previous Contents Index DocHome Next |
iPlanet Application Server Programmer's Guide (Java) |
Chapter 13 Taking Advantage of the iPlanet Application Server Features
This chapter describes how to implement the iPlanet Application Server features in your application. The iPlanet Application Server provides many additional features to augment your servlets for use in an iPlanet Application Server 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 Microsystem standards and conforms to these future standards.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 the iPlanet Application Server is a special class called an AppLogic. AppLogics are iPlanet Application Server components that interact with the core server. In previous iPlanet Application Server releases, AppLogics were part of the application model, though for current and future releases they are solely available to access the iPlanet Application Server internal features.Each servlet is scoped in an AppLogic. You can access an AppLogic instance controlling a servlet using the getAppLogic() method in the iPlanet Application Server feature interface HttpServletRequest2. When you do this, you also gain access to the server context. These activities are necessary to take advantage of other iPlanet Application Server features, as described in the following sections.
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 getAppLogic() method, which returns a handle to the superclass.The following example servlet header shows how to access an 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 iPlanet Application Server features, such as Application Events (see Using Application Events), require an IContext object. IContext defines a server context view. For more information, see the IContext interface section in the 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 shown 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 shown 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 shown 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
The iPlanet Application Server has the ability to cache a servlet's results in order to make subsequent calls to the same servlet faster. The iPlanet Application Server caches the request results (for example, a servlet's execution) for a specific amount of time. In this way, if another data call occurs the iPlanet Application Server can return the cached data instead of performing the operation again. For example, if your servlet returns a stock quote that updates every 5 minutes, you set the cache to expire after 300 seconds.Whether to cache results and how to cache them, depends on the data type involved. For example, it makes no sense to cache the results of a quiz submission 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 iPlanet Application Server 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 iPlanet Application Server feature. For more information on servlet configuration files, see Chapter 10 "Deployment Packaging."
Table 13-1 shows the ServletData section settings in a servlet configuration file.
The CacheCriteria field sets criteria to determine if serlet results are cached. This field tests one or more fields in the request. This allows conditionally cache results based on value or presence of one or more fields. If the tests succeed, the servlet results are cached.
Table 13-2 shows the CacheCriteria field syntax.
Using Application Events
In an iPlanet Application Server environment, you create and use named events. The term, event, widely used to refer to a user action, for example, a mouse click triggers an event. However, the events described in this section are not caused by users. Rather, an event is a named action you register with the iPlanet Application Server. The event occurs either, when a timer expires or when an event is activated from an application at runtime.Events are stored persistently in the iPlanet Application Server and are removed only when your application explicitly deletes them. Typical event usage include periodic backups, end of the business day account reconciling, or sending alert messages. For example, you can set an event to send 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 causes execution of one or more actions, which can include sending email or calling another application component.
You can set events to occur at specific times or intervals, for example, every hour or once a week. You can also trigger an event by calling the event name from an application. When an event's timer goes off or by calling it, the action occurs.Actions are 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 is passed to an application event in an IValList object.
The Application Events API
The iPlanet Application Server 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 for getting or setting event attributes, as well as, adding, deleting, or enumerating event actions.
The IAppEventMgr Interface
Table 13-3 shows the administrative tasks you can perform with an event by using the associated methods, in the IAppEventMgr interface.
Table 13-3    IAppEventMgr Methods
Method
Description
Removes a registered event from the iPlanet Application Server.
The IAppEventObj Interface
The event's behavior is determined by its attributes, which defines how and when an event executes, and its actions, which defines what the event does when triggered. Table 13-4 shows the methods to set and examine attributes and actions, in the IAppEventObj interface.
Table 13-4    IAppEventObj Methods
Method
Description
Creating a New Application Event
Use the steps below to create a new application event and register it with the iPlanet Application Server. For more information about the interfaces and methods described in each step, see IAppEventMgr and IAppEventObj in the Foundation Class Reference.
Note A com.kivasoft.IContext object is required to create an event. For more information, see Accessing the Server Context.
Obtain a context parameter from the server context IServerContext, as shown 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 GetAppEventMgr() method in the GXContext class to create an IAppEventMgr object, as shown in the following example:
- An IContext object provides access to the iPlanet Application Server services.
IAppEventMgr mgr =
com.kivasoft.dlm.GXContext.GetAppEventMgr(ic);After creating the IAppEventMgr object, create an application eventan instance of IAppEventObjby calling createEvent() on the IAppEventMgr object, as shown in the following example:
IAppEventObj evtObj = mgr.createEvent("myEvent");
An empty system event was created. Next, create an IValList object to hold the event attributes, and set the attribute requirements for this event. Finally, assign the attributes to the 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);Assign event actions to do something when the event 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 register the event or make the iPlanet Application Server aware of it, by calling registerEvent(). Further, you must instruct the iPlanet Application Server to enable event access by calling enableEvent(). The following example shows the registration and enabling of the 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. To trigger the event, use the IAppEventMgr method triggerEvent(), as in the following example:
Sending and Receiving Email
The iPlanet Application Server supports email transactions through the IMailbox interface. For more information, see the IMailbox interface in the Foundation Class Reference.In order for email applications to work, you must have access to an SMTP server send email and a POP server to receive email.
Security in Email
Security is often a concern when sending or receiving email. If the application generates and sends email with the address or content from user input, 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
To use the IMailbox interface from a servlet requires access to the AppLogic instance that controls the servlet's functions. 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();For more information, see Accessing the Servlet Engine.
The following examples assume the example above 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 mail server inbox. By checking, you avoid attempting to retrieve messages from an empty mailbox. Further, use this technique to obtain how many messages are waiting in order to construct a loop to iterats through the list 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.
Create an instance of IMailbox by calling createMailbox() from the servlet's controlling AppLogic instance (for more information, see Accessing the Controlling AppLogic). In this call, specify the valid user information and the POP server name. For example:
Only one mail server session can be 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.IMailbox mb;
mb = al.createMailbox("mail.myOrg.com","myUserName",
"pass7878","sid@blm.org");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 if 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 sample 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:
- Only the messages received before the open() call are retrieved.
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 a query results, 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 array elements.
Create an instance of IMailbox by calling createMailbox() from the servlet's controlling AppLogic instance (for more information, see Accessing the Controlling AppLogic). In this call, specify the valid user information and the POP server name. For example:
Only one mail server session can be 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 message text. 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();
}
}
}
iPlanet Application Server Application Builder Features
The iPlanet Application Server includes APIs designed for code generated from the iPlanet Application Builder wizards. These APIs are available to servlet programmers and we recommend that you use the iPlanet Application Builder to create servlets that use these features.The features presented here include:
Validating Form Field Data
Validating Form Field Data
This method sets a servlet to automatically check form fields for certain value types. Additionally, create a named error handler to control application flow if the validation fails.In short, specify the validation rules in a servlet's configuration file and then call the HttpServletRequest2 method validate() to test the fields against the validation rules. If validation fails, the iPlanet Application Server generates an error page automatically, or you can provide an error handler method in the servlet to produce an error message.
Validation Methods
The iPlanet Application Server provides a method called validate() that validates all form fields configured in the servlet's configuration file. This method is defined in the iPlanet Application Server 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, pass a servlet and method name in the servlet and errHandlerName parameters, respectively, that correspond to a named error handler that you write.
validate() returns true if the input matches the validation rule or false otherwise. For more information, see Error Handlers.
Validation Rules
The input data is 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 is used to specify the information for each form field, as shown in Table 13-5.
You can also specify a flag inputRequired (set to y or n) for each parameter. This flag indicates if 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.
Table 13-6 shows the data types that can be checked:
Error Handlers
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);This method generates an error page if the validate() method returns false, indicating a validation error. Examine error types with an error vector of type Vector. For more information on the validate() method, see Validation Methods.
Table 13-7 shows in the HttpServletRequest2 interface methods.
Table 13-8 shows the error code and message associated with each validation rule:
Table 13-8    Validation Rules
Validation Rule
Error Code
Error Message
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 USA 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 USA 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
Create methods to handle buttons on a form. This enables a build in modularity level to your servlet to handle requests. Form handlers are used in code generated by the iPlanet Application Builder. Usage consists of two methods in the HttpServletRequest2 interface, coupled with entries in the servlet's configuration file.Table 13-9 shows the methods used in service() (generic servlets), doGet(), or doPost() (HTTP servlets) to handle requested actions. These methods reside in the HttpServletRequest2 interface. Note that form action handlers must also be configured 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().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-080020A16896}",
},
"ServletRunnerInfo" NTV {
"ServletClassPath" Str
"com.netscape.server.servlet.test.TestDispatchServlet",
},
"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)
hrows 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 January 25, 2001