Java Servlet (Part 2) - Thread-Safe Servlet, Sending Error Messages, Request Dispatching - Building Web Applications

nutmegactSoftware and s/w Development

Nov 10, 2012 (4 years and 9 months ago)

232 views

CSC 2720

Building Web Applications

Java Servlet (Part 2)

Thread
-
Safe Servlet

Sending Error Messages

Request Dispatching

Thread
-
Safe Servlet

Multi
-
threaded Servlets


Regardless of the number of requests to the same servlet,
a server container creates
only one instance of the servlet
.



To handle multiple requests to the same servlet, a server
container creates multiple
threads

in which each thread
invokes the
service()

method of the servlet to handle the
request.



Each servlet receives a distinct copy of the “
request
” and
the “
response
” objects.



Instance variables of a servlet are shared.


import java.io.*;

import javax.servlet.*;


public class SomeServlet extends GenericServlet {

int
instanceVar
;

// shared by all instances of this servlet



public void service(ServletRequest
request
,


ServletResponse
response
)


throws ServletException, IOException

{ … }

}

SomeServlet Object


int
instanceVar
;


service(…) { … }

Thread 1

ServletRequest
request
;

ServletResponse
response
;

run() {




}

Thread 2

ServletRequest
request
;

ServletResponse
response
;

run() {




}

Servlet Container

import java.io.*;

import javax.servlet.*;


public class UnsafeCounterServlet extends GenericServlet {


public void service(HttpServletRequest request,


HttpServletResponse response)


throws ServletException, IOException

{


// 1. Read the counter from a file


// 2. Increment counter


// 3. Write the counter to a file

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14


Multi
-
threaded servlets become unsafe when they need to
share resources such as instance variables, files, and
database.



Demo: A servlet that increments a value stored in a file

Thread
-
Unsafe Servlet Demo

UnsafeCounterServlet (Thread 1)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}


1.
Server receives two requests to UnsafeCounterServlet


2.
Server creates two threads to handle the requests. Each
thread takes turn to run.


Assuming the value stored in the file is 0.

UnsafeCounterServlet (Thread 2)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}

Thread
-
Unsafe Servlet Demo

UnsafeCounterServlet (Thread 1)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}


1.
Thread 1 runs first and manages to finish the first two steps.

UnsafeCounterServlet (Thread 2)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}

Thread
-
Unsafe Servlet Demo

UnsafeCounterServlet (Thread 1)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}


1.
Thread 2 is scheduled to run next and also manages to
finish the first two steps.


2.
Both threads assign 0 to “counter”.

UnsafeCounterServlet (Thread 2)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}

Thread
-
Unsafe Servlet Demo

UnsafeCounterServlet (Thread 1)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}


1.
Both threads eventually complete their tasks.


2.
Because both threads read the value 0 from the same file,
the final value written to the file is 1 instead of 2.


3.
Create problems when your web application relies on
counting “hits” to generate revenue.

UnsafeCounterServlet (Thread 2)


doGet() {

// 1. Read counter

// 2. Increment counter

// 3. Write counter

}

import java.io.*;

import javax.servlet.*;


public class SafeCounterServlet extends GenericServlet

implements SingleThreadModel

{


public void service(HttpServletRequest request,


HttpServletResponse response)


throws ServletException, IOException

{


// 1. Read the counter from a file


// 2. Increment counter


// 3. Write the counter to a file

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15


One possible solution: Single
-
threaded servlet


Have the servlet implements the interface
SingleThreadModel


No need to add additional methods.


Servlets are scheduled to run sequentially on the first come first
served basis.


What's the drawback? Should all servlets that share resources be
made into single
-
threaded servlets?

import java.io.*;

import javax.servlet.*;


public class SafeCounterServlet extends GenericServlet {

int lock;


public void service(HttpServletRequest request,


HttpServletResponse response)


throws ServletException, IOException

{


synchronized (lock) {





// 1. Read the counter from a file


}


// 2. Increment counter


synchronized (lock) {



// 3. Write the counter to a file


}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19


Another possible solution:


Use the language feature to write thread safe code


In this example, only one of the read/write operations can be
performed by any thread at any given time.

Sending an Error Code

Sending an Error Code


The
HttpServletResponse

object in
doGet()

or
doPost()

contains methods to send pre
-
defined error
code and error message.


void sendError(int sc);


void sendError(int sc, String errorMsg);


sc
is a HTTP status code defined as constant in

HttpServletResponse


errorMsg
is a customized error message.



e.g.:

response.sendError(HttpServletResponse.SC_FORBIDDEN,



"Login Failed");


SC_FORBIDDEN
corresponds to HTTP status code 403


response.sendError(response.SC_NOT_FOUND);


SC_NOT_FOUND
corresponds to HTTP status code 404



See

HttpServletResponse

for a complete list of status code constants

sendError() Demo


You can configure the web server to use customized pages
to convey error messages.

protected void processRequest(


// Method generated by NetBeans

HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.sendError(response.SC_NOT_FOUND,


"Generated by SendErrorDemoServlet");

}

Categories of Status Code


100
-
199


Indicate the client should respond with some other actions.


200
-
299


Indicate the request was successful.


300
-
399


Usually include a location header


400
-
499


Indicate an error by the client.


500
-
599


Indicate an error by the server.



See list of
HTTP status codes

at Wikipedia.

Request Dispatching


Forward and Include

Request Dispatching


To
include
static or dynamic file content



To
pass the processing of an HTTP request

from your
servlet to another servlet



RequestDispatcher

object


public void
include
(ServletRequest request,
ServletResponse response)


public void
forward
(ServletRequest request,


ServletResponse response)


Both methods may throw

ServletException
and

IOException

Obtaining
RequestDispatcher

object #1


A
RequestDispatcher

object acts as a wrapper for a
resource corresponds to a specified path.



Call
getRequestDispatcher()

of
ServletContext
object



Path name is relative to the root of the servlet's context and
must start with '/' as prefix



e.g.

String path = "/AnotherServlet";

RequestDispatcher rd =
getServletContext().getRequestDispatcher(path);

Obtaining
RequestDispatcher

object #2


Call
getRequestDispatcher()

of
ServletRequest
object


String path = "AnotherServlet";

// Suppose AnotherServlet is located in the same

// directory as the current servlet

RequestDispatcher rd =
request.getRequestDispatcher(path);



With this method, the path name is relative to the location of
the current servlet.


Don’t use '
/
' as prefix because it indicates the path name
that follows is relative to the root of the ServletContext.

Obtaining
RequestDispatcher

object #3


Call
getNamedDispatcher()

of

ServletContext
object


String servletName = "AnotherServlet";

// Suppose AnotherServlet is located in the same

// directory of the current servlet

RequestDispatcher rd =
getServletContext.getNamedDispatcher(servletName);



servletName

is a name assigned to the servlet or JSP
page and is defined in
web.xml
.


If the included resource is a Java Servlet, the included servlet
can only write
to the
PrintWriter

object of the response object
, and
cannot modify the
header info of the response object
.



One can include as many resources as one need.

protected void processRequest(


// Method generated by NetBeans

HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

PrintWriter out = response.getWriter();


// Can use "out" to write something here


RequestDispatcher rd =


getServletContext().getRequestDispatcher("index.jsp");

rd.
include
(request, response);


// Con use "out" to write something here

}

Including Other Resources


If you have written something to the PrintWriter object prior to
calling "
rd.forward()
", you may call "
response.reset()
"
to clear the output.


protected void processRequest(


// Method generated by NetBeans

HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {


// Cannot flush output here


RequestDispatcher rd =


getServletContext().getRequestDispatcher("index.jsp");

rd.
forward
(request, response);


// Cannot write to the PrintWriter object

// or modify the response's header info

}

Forwarding Processing Control

sendRedirect()


The method
sendRedirect()

of
HttpServletResponse

object can also be used to
redirect the client to a different resource.



String path = "AnotherServlet";

// Suppose AnotherServlet is located in the same

// directory of the current servlet

response.sendRedirect(path);



path
can also be a string representing an absolute URL.


sendRedirect()

"asks" the client to request a different
resource whereas
forward()

passes another resource to
the client.

Summary


Reference:


"Java for the Web with Servlets, JSP, and EJB" by Budi
Kurniawan