Here is a listing of most of the functions of BonForumEngine: n Provides multiple, simultaneous contexts for Web application n Allows multiple simultaneous user threads to be serviced n
Trang 1birds with one stone: It would solve the refresh problem and give us material for ourchapter about applets, Chapter 9, “Java Applet Plugged In: bonForumRobot.”
Because we also wanted to avoid using scripting languages on the client side, wedecided not to pursue the experimentation with HTML pragma, buffering pages, and
so on Instead, the robot applet idea was born and provided an alternative, Java-relatedsolution to the problems inherent in frequent refreshes of a page For all the gorydetails of how it works, read Chapter 9
We pointed out that the robot applet on the _robot JSP we are discussing gets itsparameter values from session attribute values that are set on the top page in the group
of pages handling the “host executes chat” phase of the Web application cutes_chat.jsp
host_exe-If we look there again, we will see by the value used to set the documentsessionattribute that this particular applet instance will continually try to display the filenamed host_executes_chat_frame.jsp
This means that it is going to refresh the display of the chat messages that the hostsees.That is something that we would like to do as frequently as possible, allowing forthe bandwidth and physical manifestation of such a repeatedly fired Web page.When aguest in the chat adds a message, we want it to show up in the display of all the users
as soon as possible
How does the user break out of the frameset that is representing the “host executeschat”Web application phase? We saw before, in host_executes_chat_controls.jsp, thatthe host can do one of three things: send a message to the chat guests, exit from thischat, or enter command mode Again, this choice is presented in the code as follows:
<table border=”0” cellspacing=”0” cellpadding=”0” rows=”4” cols=”1” width=”100%”
➥bgcolor=”#00FFFF”>
<tr>
<label for=”bonCommand”>send this message</label><input type=”radio”
name=”bonCommand” value=”host_executes_chat_controls” CHECKED></input>
<input type=”hidden” name=”actorReturning” value=”yes”></input>
<input type=”submit” value=”Do it!” name=”submit”></input>
</tr>
</table>
One of these Web app destinations, the “host executes command” state, will be cussed only briefly here If you have followed the discussion so far, you will possess theinformation needed to understand the following seven interrelated JSP pages that are
Trang 2dis-together involved in offering the chat host some commands to execute.You will havenoticed that we have not provided many commands yet, but we have set up the frame-work and the manner in which more host (and other actor) commands will be addedlater.
host_executes_command.jsp host_executes_command_frame.jsphost_executes_command_controls.jsphost_executes_command_ready.jsphost_executes_command_robot.jsphost_increases_rating.jsp
host_decreases_rating.jspThe three commands now available for the host to execute do the following:
n Increase the status of a guest
n Decrease the status of a guest
n Change the number of messages displayed to the host
A host can select one guest in the chat from a list of guests displayed by the _frameJSP host_executes_command_frame.jsp
That list is being produced by an XSLT transformation of the information tained in the hashtable-based database of the BonForumEngineclass For a relevant dis-cussion, see Section 10.13, “Displaying the Guests in a Chat,” in Chapter 10
con-The overall idea is that the Web application will automatically remove from a chatany guest whose rating has decreased to 0 Furthermore, the Web application willautomatically change the role of an actor from that of chat guest to that of chat host assoon as the rating of that guest reaches some set value, such as 10 points
The design envisions these multihosted chats, as well as multichat forums and tiforum chat networks However, the code for these was not considered as high of apriority as those more fleshed-out portions of the Web application
mul-When you are trying out this part of the Web application (you are doing that, aren’tyou?), you should definitely try increasing and decreasing a guest’s rating, changing thenumber of chat messages being displayed, and exercising the navigator buttons in con-junction with smaller lists (You may even discover that showing the first page of sev-eral is still a bit rough, although it works.) This simple exercise in user feedback in JSPshould make you aware of the possibilities of control mechanisms that can be designedwith similar techniques
Notice that there is again a robot applet on a JSP:
host_executes_command_robot.jsp In a manner similar to the one discussed for thehost executes chat bonForum state, this JSP works in conjunction with its top-levelJSP, host_executes_command.jsp.Together, they refresh the list of chat guests on theHTML produced by the JSP host_executes_command_frame.jsp
Trang 3At this point in this chapter, you should know enough about the bonForum Webapplication to be able to decipher the functioning of the rest of the JSP files in thefolder TOMCAT_HOME\webapps\bonForum\jsp\forum Some of these files arebetter discussed in other contexts, such as the use of Java servlets in Java-and-XML–based software, so they will be visited in later chapters.
We next briefly discuss visitor_joins_chat_frame.jsp, which is of considerable interest
in the context of XML and XSLT.We concentrate on presenting things from the JSPpoint of view
We first make sure that we can use our tag library from this page by referring tothe taglib URL:
<%@ taglib uri=”http://www.bonForum.org/taglib/bonForum-taglib” prefix=”bon” %>
The Tomcat Server will know how to resolve this reference and will be capable ofusing the tld file to find the tag classes when it translates the JSP file into a Javaservlet source file Look at one of these sometime for a JSP with a custom tag on it, tobetter understand how tags merge your tag class code into the code produced by aJSP
The JSP now being discussed simply lists all the available chats to the bonForumvisitor, allowing that user to select and submit a chat to join.To actually join it, theuser must then click a button on the controls frame
Too Many Clicks?
As an aside, this has been criticized as a stupid design—why so many clicks just to join a chat? Our answer is that we are not trying to design the simplest and best user interface now, but instead we’re trying to design a prototype that will enable us to explore and solve problems For example, we are inter- ested in the problems encountered when several cooperating JSP reside in frames We are essentially in the business here of creating problems! That does get criticized for being an academic exercise rather than a serious, practical example of a Web application We would rather call it R&D than academic, but
we also recognize that the way we research software technologies is not everyone’s cup of tea As to whether it is practical, that depends on whether you can learn anything practical from it (we certainly have!) As to whether it is serious, that depends on whether you are having fun yet (seriously!)
We first developed the code to display available chat topics with XSLT by writing JSPscriptlets directly on the JSP document After we had the code working (at least, forone or two users), we moved it all into a custom tag class.The code ended up finally
in the TransformTagclass, defined by the file TransformTag.java (See Figure 7.5.)Prototyping the XSLT custom tag to produce a chat list display is discussed in section10.10, “XSLT and the bonTransformCommand,” in Chapter 10
Trang 4What we designed is a way to call the Apache Xalan XSLT processor to apply anXSL style sheet to the chat room data that the Web application contains at runtime.
The outcome of such a process will be an XML document, which (in this case) isused to display to the user the list of chats that can be joined in bonForum Here ishow the TransformTagis used to generate that list:
<bon:transform type=”bonTransform” inDoc=”bonForumXML”
that is created by the BonForumTagExtraInfoclass.This gives us the possibility ofreusing the results elsewhere, if we change the setting of the extra tag information sothat it is visible outside the custom tag body
Figure 7.5 HTML displayed by visitor_joins_chat.jsp and related JSP documents.
In the following code scriptlet, you can see how this JSP page gets the value of thecurrently chosen chatItemto display to the user.When the user clicks the Submit but-ton to choose the selected chat, the form is sent by an HTTP POST method to the
BonForumEngineservlet.The request makes a round-trip because of the value of the
bonCommandrequest parameter.That refreshes the HTML produced by the JSP and
Trang 5updates the selected chatItem—the chat that was just chosen from the selection list.
<%
String chatItem = (String)session.getAttribute(“chatItem”);
String chatItemMessage = “chat: <none>”;
if(chatItem != null && chatItem.trim().length() > 0) { chatItemMessage = “chat: “ + chatItem;
}
%>
Finally, the current chat is displayed to the user using the following JSP expression:
<%=chatItemMessage%>
By now, you should have the information required to understand all the other JSPpages in the Web application.They are just variations on the themes we have been dis-cussing here You can read functional descriptions of all the JSP pages in Section6.1.5, “The States of the Forum,” in Chapter 6 Figure 7.6 shows the HTML dsplayed
by guest_executes_chat.jsp Some of the JSP pages not discussed are quite simple.Theyonly forward the request to the next page using the following JSP trick:
<jsp:forward page=”visitor_executes_choice.jsp”/>
Figure 7.6 HTML displayed by guest_executes_chat.jsp and related JSP documents.
It might seem that these pages are not needed, but remember that this version ofbonForum is really just a framework for building a complete Web chat application
Trang 6ality later, if we have the entire design represented in the JSP pages.
For example, later we will change things so that, when a host leaves the bonForum,most of the data that was added for that host will be deleted.We can do this very con-veniently from our host_exits_forum.jsp page
Quite a bit more complex is the processing that is done by the JSP servlet piled from the JSP page bonForum.jsp.There we use the bon:Transformtag commandagain, this time to use XSLT to get a list of available bonForum locations.The stylesheet produces these in the form of a list of Web hyperlinks.We will discuss that morefully in Chapter 10 because the XSLT transform is handled by the code of the
com-TransformTagclass
bonForum
Before we leave this chapter, we want to further discuss two interrelated topics:
n Using session attributes to pass data between JSPs
n Reducing versus increasing the number of JSP files
We are aware that we may be improperly using session objects when we use them topass values for our applet parameters from one JSP to another.The criteria is whetherthese applet parameter values qualify as information about a specific user of the appli-cation and, thus, session information.They probably are better treated as thread-spe-cific information instead, and we should develop a way to use beans to pass theinformation in a thread-safe manner between these JSPs
Furthermore, why do we need to pass the applet parameter values into the _robotpage at all? Why not just put the values directly into the applet parameters right onthe _robot page? Using the same target parameter as we did in the last section as anexample, that would mean doing this:
<jsp:param name=”target” value=”display”/>
The various other applet parameters would then also be hard-wired Of course, thatwould work as well.The applet doesn’t care where it gets its strings If we did it thisway, we would have no need to use the session attributes to pass values from the JSPthat creates the frameset to the JSP with the embedded robot applet
In fact, we could just put the jsp:pluginelement in the _controls JSP and noteven have a third frame.We would then get rid of all the _robot JSP files except foractor_leaves_frameset_robot.jsp
It all comes down to a balancing act On one hand, especially in a chat application,performance is important, and “simpler” usually means “better performance.”Thatwould argue in favor of reducing the number of frames, objects, and files—no need forall the robot session attributes, nor all the _robot JSP files
On the other hand, a key purpose of JSP is to create dynamic Web pages that areeasily expandable and customizable.We see the design of bonForum as being a lot likeone of those new and empty land subdivisions that will later become an entire suburb
Trang 7application pages could certainly use more and better content.
You will also no doubt have noticed, for example, that there is very little differenceamong many of the JSP files in the bonForum project If that is so, why not justreplace every group of similar JSP files with just one? We could take care of any differ-ences that exist some other way For example, we could replace this lot of files:guest_executes_chat_robot.jsp
guest_executes_command_robot.jsphost_executes_chat_robot.jsphost_executes_command_robot.jspvisitor_joins_chat_robot.jspvisitor_starts_chat_robot.jspThese six JSPs could all be replaced by one file, which we could callactor_refreshes_frame_robot.jsp
The only other changes needed would be to the top-level JSP files in eachbonForum state that uses a refresh robot, which are these files:
guest_executes_chat.jspguest_executes_command.jsphost_executes_chat.jsphost_executes_command.jspvisitor_joins_chat.jspvisitor_starts_chat.jsp
We would replace the entire robot frame element in all these files.Those are now allsimilar to this:
<frame src=”/bonForum/jsp/forum/host_executes_chat_robot.jsp” name=”robot”/>
They would now all contain the same robot frame element, which would be like this:
<frame src=”/bonForum/jsp/forum/actor_refreshes_frame_robot.jsp” name=”robot”/>
On the face of it, replacing six files with one seems like a no-brainer However, if youlook at each one of those replaceable _robot JSP files as defining a customizable piece
of Web real estate that is related to a particular state of a Web application (for example,the user is joining, starting, chatting, commanding, hosting, and being a guest), thenyou can argue that having all those files is a better framework to build upon than hav-ing just the one file It is a bit like biodiversity being favorable for evolution
Trang 8Java Servlet and Java Bean:
This chapter is divided into two parts:The first covers the BonForumEngineservlet, andthe second covers the BonForumStorebean.The servlet will be discussed in more detailbecause the problems that it solves are more universally encountered by developers ofWeb applications After a brief introduction to the purposes of the servlet and its con-text in the Web application, we proceed to a discussion of its two major methods, the
service()method and the processRequest()method.Whenever possible, code that isnot dependent on the nature of the application (chatting) has been placed in the
service()method, while code that is more related to the specific needs of the Webapplication (chatting) has been put in the processRequest()method
Trang 98.1.1 Purpose of the BonForumEngine Class
The main purpose of theBonForumEngineclass is to connect and coordinate all theJSP documents in the Web application By extending the HttpServletabstract class, itcan receive the many simultaneous HTTP requests being generated by the browseruser interface discussed in Chapter 7, “JavaServer Pages:The Browseable UserInterface.”BonForumEngineforwards each request it receives to a “destination” JSP.Thisservlet is the engine that moves every instance of bonForum from one state to thenext
Before forwarding each request, it can also process it, which it does in relation tothe bonForum Web application.That “chat” processing relies heavily on the methods
of the BonForumStoreclass, which is the subject of the second part of this chapter (seeSection 8.2, “The BonForumStoreClass”) Here is a listing of most of the functions of
BonForumEngine:
n Provides multiple, simultaneous contexts for Web application
n Allows multiple simultaneous user threads to be serviced
n Prevents entry to an application except from login page
n Enforces unique nicknames within application instance
n Acts as a switchyard for different HTTP request categories
n Manages the Web application sessionobjects
n Processes HTTP request objects as a Web (chat) application
n Processes and forwards applet-generated JSP requests
n Processes information from all JSPs in the Web application
n Initializes the XML data wrapper, a BonForumStoreinstance
n Sets up an application scope reference to BonForumStore
n Makes user input available to chat processes, by session
n Processes chat messages from JSP users to other JSP users
n Manages XML data items for multiple simultaneous users
n Forwards users from JSP to JSP with programmatic control
n Provides extension and customization mechanism for Web app
n Provides some examples of user input verificationThe best way to understand any distributed application is perhaps from the point ofview of the host (or hosts) that connect the clients.These connections create contractsthat define the allowable transactions: between the clients, between the clients anddatabases, and so on Just trying out the bonForum chat software as a chat host or as achat guest will not reveal the mechanics of this Web application.The following discus-sion of the BonForumEngineand BonForumStoreclasses will hopefully make clear some
of the Ozian wizardry behind the curtain
Trang 108.1.2 Web Application Context for this Servlet
Although Tomcat is a complete HTTP server, its specialty is handling Java servlets andJavaServer Pages (JSP).The Tomcat configuration file web.xml determines whatTomcat does with the various requests that it gets, whether directly from a browser orfrom another server such as Apache.The following document type links the web.xmlconfiguration file to a definition of what a Web application should look like:
<!DOCTYPE web-app PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN”
Web Application Deployment Descriptor for bonForum
The web.xml Web application deployment descriptor for bonForum can be found inthe following file:
Trang 11Servlet Initialization Parameters
To illustrate how you can pass initialization parameters to a servlet, we have included apurely illustrative parameter name,bonfoo47, and valuebonbar47.To access this para-meter from within the BonForumEngineservlet, you could use something like either ofthese two equivalent statements (the second is a convenient shortcut for the first):
String bonFoo47 = getServletConfig.getInitParameter(“bonfoo47”);
String bonFoo47 = getInitParameter(“bonfoo47”);
Context Initialization Parameters
You can also define initialization parameters for the entire Web application context.These are shared by all the servlets in the Web app Here is one example from our Webapplication.The parameter named Logginghas a value of all, which turns on the log-ging output both to logfiles (one for each major object) and to the console (the stan-dard error output, actually) Here is how we make that Web app global informationavailable:
Trang 12BonForumEngine.That servlet name could be a different one, but it must be the oneused in the servlet tag.
The second servlet-mapping element in the web.xml file tells Tomcat that a URLpattern that matches /BonForumEngineshould also cause Tomcat to forward the request
to the servlet known as BonForumEnginebecause of the servlet tag seen earlier
First and foremost, the BonForumEngineis a descendant of HTTPServlet.The directbenefit that you get from that includes many things that were already taken care of foryou as a developer:You simply do not have to solve some hard problems in the area ofcommunication across the world.The best place to start examining the doings of this
HTTPServletis right at its heart: the service()method
Servicing HttpServletRequest Objects
As you know already (or could guess by looking at its arguments’ types), the service()
method in an HTTPServletaccepts an HttpServletRequestobject and an
HttpServletResponseobject.The servlet and the JavaServer Pages API documentationsays the following about the service method:
There’s almost no reason to override the service()method.service()handlesstandard HTTP requests by dispatching them to the handler methods for eachHTTP request type (the doxxxmethods …)
These doXXXmethods are doGet(),doPost(),doPut(), and doDelete().The standardapproach, when only postand getactions are to be handled (and handled in the sameway), is to override doPost()instead of service(), and then to override doGet()tosimply invoke doPost().The bonForum Web app uses only the postaction If wewere to override doPost()instead of service()and then later decided to use the get
action also, we would have to add “and also in doGet()” everywhere in the bookwhere we had written “in doPost().” We decided that was reason enough to override
service()!
Trang 13What service( ) Does in BonForumEngine
So what is in the service()method of BonForumEngine? Table 8.1 gives a brief list ofits tasks
Table 8.1 Tasks of the service( ) Method in BonForumEngine
front door: forum_login.jsp.
servlet in deployment descriptor BonForumEngine —some are processed
before forwarding, and others not.
request-based Web application (a chat, in this case).
or an error JSP, based on processing, form data, or servlet-mapped URL decoding.
Hopefully, you will now be able to make faster sense out of the source code with thisinformation
Pseudocode Listing for the service( ) Method
The following listing in pseudocode shows the logic of the service method in the
BonForumEngineclass.This listing can serve as a reference while you read the followingsections, which discuss its concepts, terms, and details
set serviceStatus to CheckForServicing
get requestUri
get boncommand request parameter
if requestUri is for BonForumEngine set bonForumCommand to bonCommand
if bonCommand request parameter full
if boncommand includes “forum entry”
set serviceStatus to CheckInAtEntrance
if boncommand includes “UserMustLogin”
Trang 14set serviceStatus to UserMustLogin else if boncommand includes “system_executes_command”
set serviceStatus to SystemCommands else
set serviceStatus to ProcessRequest endif
else set serviceStatus to ProcessRequest endif
else set serviceStatus to DecodeServletMappedURI endif
if requestUri includes “forum_login”
set serviceStatus to ForwardToLoginPage endif
else if requestUri includes “forum_error”
set serviceStatus to ForwardToErrorPage endif
else if requestUri includes “UserMustLogin”
set serviceStatus to UserMustLogin endif
if serviceStatus is CheckInAtEntrance create session
get sessionId // Get a servlet context attribute, or // if not, then an init param named, // “SessionMaxInactiveMinutes”
// (default is forever)
// Use it to set chat inactivity limit:
set maxInactiveInterval for session set serviceStatus to ProcessRequest else if serviceStatus is not ForwardToLoginPage nor ForwardToErrorPage // It is ProcessRequest,
// DecodeServletMappedURI, // or SystemCommands!
check for existing session
if no session set serviceStatus to UserMustLogin else
get sessionId check requested sessionId
if requested sessionId is not valid set serviceStatus to UserMustLogin endif
if request is from forum_entry (nickname input page) get input nickname from request parameter else
get existing nickname from session attribute endif
Trang 15if nickname gotten
if nickname in registry
if nickname is for another session
if at forum_entry // nickname is taken!
set serviceStatus to ForwardWithoutServicing
➥ set bonForumCommand to forum_entry save nickname in actorNicknameNotAvailable
➥ session attribute else
// existing nickname not ok, // session expired?
set serviceStatus to UserMustLogin endif
// else re-entered nickname is ok endif
else // nickname not in registry
if at forum_entry // nickname unique and available put nickname in registry put nickname in session attribute else
// existing nickname not ok!
set serviceStatus to UserMustLogin endif
endif else // nickname missing in request or session!
if at forum_entry set serviceStatus to ForwardWithoutServicing set bonForumCommand to forum_entry
else set serviceStatus to UserMustLogin endif
endif endif endif
if serviceStatus is DecodeServletMappedURI set serviceStatus to ForwardWithoutServicing
if requestUri contains embedded bonForum JSP name set bonForumCommand to embedded JSP name
if request needs processing (guest_executes_chat, host_executes_chat)
➥ set serviceStatus to ProcessRequest endif
endif endif
if serviceStatus is ProcessRequest, or serviceStatus is SystemCommands try
save serviceStatus in a request attribute
Trang 16invoke processRequest with request, response, session, bonForumCommand
➥ set serviceStatus from the request attribute catch exception
printStackTrace endtry
endif
if serviceStatus is not ForwardWithoutServicing, nor ForwardAfterRequestProcessed
➥ // service was not successful!
if serviceStatus is ForwardToLoginPage set bonForumCommand to forum_login endif
else if serviceStatus is ForwardToErrorPage set bonForumCommand to forum_error endif
else if serviceStatus is SystemCommands set bonForumCommand to system_executes_command endif
else //serviceStatus is UserMustLogin, or unknown
if session exists try
invalidate session catch IllegalStateException printStackTrace endtry
endif create new session get new sessionId set bonForumCommand to forum_login_robot set robot applet parameters in session attributes // document is set to “forum_login.jsp”
// target is set to “_top” frame // applet will restart the webapp!
endif endif
create JSP filename from bonForumCommand
Forward request and response to JSP using RequestDispatcher
Some Notes for the service( ) Method
We list here a series of items that can help you understand the functioning of the
service()method Rather than try to understand these items now, it is best to keepthem as a reference to use while reading the sections that follow, which cover the
Trang 172 You can think of bonForumCommandas the ticket out of the service()method—and, thus, out of the servlet.The value of bonForumCommanddetermines whereeach request gets forwarded because it generates the destination’s JSP filename.The bonForumCommandvariable is local to the service()method.
3 JSP-generated HTML forms in the browser interface are always posted to the
BonForumEngineservlet, so their related requestURIvalues are always
BonForumEngineas well
4 A request with a URI of BonForumEngineand a valid bonCommandvalue matically gets a BonForumEnginewith the same value as the bonCommand.That ishow a JSP form can select the next JSP in the Web application
auto-5 Other requests transiting the service()method have arrived only because of aservlet mapping for URIs that end in tfe (as discussed in the previous section,
“Servlet-Mapping elements”) For example, the BonForumRobotapplet includesthe “true” request destination (the value of its documentparameter) as part of amangled URI that ends in tfe.These servlet-mapped requests are given a
BonForumCommandthat is obtained from the embedded JSP filename value
6 To ensure that all requests pass through the service()method of
BonForumEngine, we also added a tfe suffix to the JSP filename values of all src
attributes of HTML frame elements (for example, the frames onhost_executes_chat.jsp) and the JSP filename values of all pageattributes of thejsp:forward elements (for example, the frames on host_exits_command.jsp)
7 The only application state in which a bonCommandof forum_entryis posted as arequest parameter is the forum_login state (created by forum_login.jsp)
Therefore, if a request has a bonCommandvalue of forum_entry, it is correctlyentering bonForum
8 Unless a request is correctly entering bonForum, it must already have a session.Otherwise, the request gets forwarded to the forum login state, for re-enteringbonForum
9 Unless a request is correctly entering bonForum, it must already be associatedwith a nickname If the request originated in the nickname input page(forum_entry.jsp), the nickname will be in a request parameter Other nonenter-ing requests should have a nickname stored in an attribute of a session thatbelongs to the request Nonentering requests without nicknames are forwarded
back so that a user can re-enter a nickname These “bad nickname” requests are
forwarded back to the nickname input page, if they originated on one
Otherwise, they are forwarded back to the forum_login state
10 For normal request forwarding, either to the expected destination or back to thepage that originated the request, the engine can just set BonForumCommandto the
Trang 18JSP filename (without path or extension) and set ServiceStatusto
ForwardWithoutServicingor ProcessRequests
11 To handle abnormal request forwarding, the engine needs to use BonForumRobot
to forward the request to the forum login page Otherwise, problems can pen (For example, if a request without a session is not correctly entering, thenthe usual situation is that its session has expired due to browser inactivity If such
hap-a request originhap-ates within hap-an HTML frhap-ame, hap-and if the engine used the forwhap-ard-ing method described in item 9, the login page would end up being displayedinside the frame!) The applet came in handy here, even though its real jobs arerefreshing JSP-generated HTML frames and switching application framesets, asexplained in Chapter 7 and Chapter 9,“Java Applet Plugged In: BonForumRobot.”
forward-After this look at the overall tasks and design of the service()method, and the details
of a few key characteristics, we now describe the way BonForumEngineclassifiesrequests associated with the various threads “traversing” its code
One of the most important tasks of the service()method is to classify and route eacharriving request so that the processing executed by its thread is correct for the func-tion of the request within the logical context of the application.That is the topic ofthis section
Because each thread executing code within a service()method has its own copies
of all the method variables, we can use the variables freely in the code, without ing that one thread can affect the value of the variables for a different thread Much ofthe beauty of Java lies in its built-in multithreaded processing capability (Later, in sec-tion 8.1.20, “The processRequest()Method: Handling ‘Host Executes Chat’”we willdiscuss the decidedly different situation that we face when two or more threads aresharing the same resource—for example, our database.)
worry-The ServiceStatus Variable
BonForumEngineuses theserviceStatusvariable to classify and route all incomingrequests to the service()method.The value of this variable sorts the requests intovarious handling categories It is used to route each request through the various pro-cessing choices in the method.Table 8.2 lists all possible values of serviceStatus, eachwith a description of its implied request category
Trang 19Table 8.2 Request Types Handled in the service( ) Method
Value of serviceStatus Situation of Request
CheckForServicing Request has just entered service().
CheckInAtEntrance Request is for entering the Web app and needs a
session.
SystemCommands Request is for access to Web app administration pages.
ProcessRequest Request needs processing—invoke processRequest()
for it.
DecodeServletMappedURI Request is mapped to this servlet and needs its URL
decoded.
ForwardToLoginPage Request is servlet-mapped by robot applet to force
relogin, so only forward it.
ForwardToErrorPage Request is for error page, so only forward it.
UserMustLogin Request has failed session or nickname verification, so
get the BonForumRobot applet on the forum_login_robot JSP page to request the forum_login page.
ForwardWithoutServicing Request needs to be only sent on its way (or else back
where it came from), using the bonForumCommand to get the name of the JSP destination.
InProcessRequestMethod Request is in processRequest() method now.
ForwardAfterRequestProcessed Request is completely processed—send it on its way.
All requests entering the service()method are classified in the CheckForServicing
String requestUri = request.getRequestURI();
The URIs that are associated with requests coming to this service()method are oftwo types, as follows:
1 URI for the BonForumEngine
2 URI servlet-mapped to the BonForumEngine
The first type of request URI is always due to the following HTML code that is erated by the typical bonForum JSP:
gen-<form method=”POST” action=”/bonForum/servlet/BonForumEngine”>
Trang 20The getRequestURI()method for any request posted by this form will, of course,return the following:
/bonForum/servlet/BonForumEngine
The second type of request URI is generated in three very different situations, eachone producing a URI that ends in tfe One situation includes all requests used by thebrowser to fill frames in framesets using JSPs and is exemplified by the followingHTML code taken from guest_executes_chat.jsp:
uncachedDocument = document + millis + “.tfe”;
As discussed in the next chapter, the applet does this to produce requests with URIs,
as in the following example:
/bonForum/jsp/forum/guest_executes_chat.jsp986480673940.tfe
In fact, there are four different subtypes of these “robot” request URIs.The one justshown is used to change application states, from “visitor joins chat” to “guest executeschat.” A second subtype, shown next, is used to refresh the frame that displays chatmessages to a guest:
Trang 21The bonCommandrequest parameter is sent to the servlet when a user submits anHTML form created by a compiled JSP page.
Here are some example boncommandvalues:
forum_entryvisitor_executes_choicevisitor_starts_chatvisitor_starts_chat_framevisitor_starts_chat_readyhost_executes_chat_controlsvisitor_joins_chat
visitor_joins_chat_framevisitor_joins_chat_readyguest_executes_chat_controlssystem_executes_commandsystem_dumps_xmlbonForum
As you know, these represent both the states of the Web app and the JSP files that ituses to create its user interface.The service()method checks that the request URIfor a bonCommandis for the BonForumEngineand then uses the bonCommandvalue to setthe all-important variable bonForumEngine, which determines the next JSP page to beexecuted for the user of the current thread Here is the code that sets that variable:
if((requestUri.indexOf(“BonForumEngine”) > -1)) { if(bonCommand.length() > 0) {
bonForumCommand = bonCommand;
Notice that bonCommandhere has an empty value whenever the request is servletmapped to the BonForumEngine(see the previous section “Request URI”) In thatcase, information that is equivalent to that of bonCommandcan instead be found embed-ded in the URI itself.)
CheckInAtEntrance
Requests that have bonCommandvalues end up classified in the ProcessRequestservicestatus, unless they fall in either of two special categories.The first belong to the
CheckInAtEntranceservice status By design, only the first page of the Web app creates
a boncommandparameter with a value of forum_entry.The service()method uses thatinformation to produce this category of incoming requests generated by users cominginto the application through its proper entrance:
// Check if request came from // the first page (forum_login.jsp).
if(bonCommand.indexOf(“forum_entry”) > -1) { serviceStatus = “CheckInAtEntrance”;
Trang 22The second special category of requests belong to the SystemCommandsservice status
These request resources that only the bonForum server administration and developerscan use.This area of the Web app has a “doorway” of its own, which is created by theJSP system_executes_command.To be immediately useful, these requests need to begiven a session and a nickname After that is done, the requests are classified into a sep-arate status and request handling of their own, as follows:
else if(bonCommand.indexOf( “system_executes_command” ) > -1) { // here later add password security on system.
// for now, no security at all // Get the session, creating it if none session = request.getSession();
session.setAttribute(“actorNickname”, “system”);
serviceStatus = “SystemCommands”;
}
ProcessRequest and DecodeServletMappedURI
The final act of request classification at this early stage of the service()method is tothrow the rest of the requests with a BonForumEngineURI into the ProcessRequest
service status, and put all the servlet-mapped requests into the
DecodeServletMappedURIservice status
HttpSession session = null;
String sessionId = “”;
String serviceStatus = “CheckForServicing”;
String bonForumCommand = “”;
String requestUri = request.getRequestURI();
String bonCommand = normalize( (String)request.getParameter( “bonCommand”
➥)).trim();
if((requestUri.indexOf(“BonForumEngine”) > -1)) { if(bonCommand.length() > 0) {
bonForumCommand = bonCommand;
if(bonCommand.indexOf(“forum_entry”) > -1) { serviceStatus = “CheckInAtEntrance”;
} else if(bonCommand.indexOf( “system_executes_command” ) > -1) {
Trang 23session = request.getSession();
session.setAttribute( “actorNickname”, “system”);
serviceStatus = “SystemCommands”;
} else { serviceStatus = “ProcessRequest”;
} } } else { serviceStatus = “DecodeServletMappedURI”;
} [the rest of the method is here .]
}
Request Control and Security
Notice that it is part of the design that each request involved in the Web applicationshould traverse the service()method of the BonForumEngineand thus be subject tocontrol by whatever Java code there can accomplish In effect, the servlet providessecurity within an application context Just before this book went to print, there werestill some requests that were not subject to this control.These (discussed previously inthe section “Request URI”) included all “frame-filling” requests made by browsersand all requests by jsp:forwardtags.The fix for all these “out-of-control” requeststurned out to be extremely simple:We only added a tfe suffix to all the requested JSPfilenames
That left one other source of requests that were not being routed through the
service()method of BonForumEngine: the error page JSP requests Each JSP (exceptforum_error.jsp) has in it a page directive like this:
<%@ page errorPage=”forum_error.jsp” %>
It would be a simple matter to also add tfe to this JSP filename, which would routethe request through the service()method.We are still debating whether it is better togain control (and access) to all these error page requests in BonForumEngineor whetherall JSP errors should be handled only by Tomcat
After that fix, all the requests are sent to the service()method because of theservlet mapping.Without any additional changes to the code, we are ready to establishtotal control of all requests in the Web application In the “if-else-if-else-if-else” con-struct that handles all servlet-mapped requests in the service()method, we can easilyadd new code that responds to these “frame-filling” and direct “JSP-to-JSP” transi-tions (In a future release, we will use three different suffixes, not just tfe, to provide aneasy way to sort these three types of servlet-mapped requests.)
Trang 248.1.5 The service( ) Method: Requests for Engine Control
Some requests are used not to implement the Web application, but rather to controlthe engine that implements the Web application As of now, the only examples in
BonForumEnginecontrol the error page display and reboot the application.They aredescribed fully later in this chapter, in Section 8.1.12, “The service()Method:
Handling Abnormal Outcomes.”
These control requests need no further processing and, indeed, should not beprocessed.These are detected early in the service()method and are given a
serviceStatusvalue that will route them past all the code to the request-forwardingmechanism at the end of the method.That is all done by checking the incomingrequest URIs, as follows:
if(requestUri.indexOf(“forum_login”) > -1) { serviceStatus = “ForwardToLoginPage”;
} else if(requestUri.indexOf(“forum_error”) > -1) { serviceStatus = “ForwardToErrorPage”;
} else if(requestUri.indexOf(“UserMustLogin”) > -1) { serviceStatus = “UserMustLogin”;
}
In Section 8.1.2, “Web Application Context for this Servlet,” we discuss what becomes
of requests that are given these Web app control serviceStatusvalues
The service()method code first looks for the max inactive interval (in minutes), a
ServletContextattribute string called sessionMaxInactiveMinutes Failing that, itlooks in an initialization parameter of the same name.The default, if neither is found,
is –1, meaning that sessions persist until Tomcat shuts down
Trang 25Here is the code that handles new requests coming it at the entrance to the Webapplication:
if(serviceStatus.equals(“CheckInAtEntrance”)) { session = request.getSession();
sessionId = session.getId();
String sessMax = normalize((String)getServletContext().getAttribute(
➥“sessionMaxInactiveMinutes”));
if(sessMax.trim().length() < 1) { sessMax = getServletContext().getInitParameter(
“sessionMaxInactiveMinutes”);
if(sessMax == null) { sessMax = “-1”;
} } int minutes = -1;
try { minutes = Integer.parseInt(sessMax);
} catch (NumberFormatException nFE) { minutes = -1;
} session.setMaxInactiveInterval(minutes);
serviceStatus = “ProcessRequest”;
}
the Web Application
In Section 8.1.5, “The service()Method: Requests for Engine Control,” we saw thatsome requests are to be routed around most of the code in the service method Exceptfor those login and error requests and the special Web app entrance requests that wejust discussed in Section 8.1.6, “The service()Method: Requests to Enter the WebApplication,” all requests must be checked for two requirements:
n They must have a valid session object
n They must have a valid actor nickname
These checks are applied to all requests with the following serviceStatusvalues: