What, exactly, is an attribute?

We saw how the ServletContext listener created a Dog object (after getting the context init parameter) and was able to stick (set) the Dog into the ServletContext as an attribute, so that other parts of the app could get it. Earlier, with the beer tutorial, we saw how the servlet was able to stick the results of the call to the model into the Request (usually HttpServletRequest) object as an attribute (so that the JSP/view could get the value).

An attribute is an object set (referred to as bound) into one of three other servlet API objects—ServletContext, HttpServletRequest (or ServletRequest), or HttpSession. You can think of it as simply a name/value pair (where the name is a String and the value is an Object) in a map instance variable. In reality, we don’t know or care how it’s actually implemented—all we really care about is the scope in which the attribute exists. In other words, who can see it and how long does it live.

image with no caption

Who can see this bulletin board? Who can get and set the attributes?

An attribute is like an object pinned to a bulletin board. Somebody stuck it on the board so that others can get it.

The big questions are: who has access to the bulletin board, and how long does it live? In other words, what is the scope of the attribute?

Attributes are not parameters!

If you’re new to servlets, you might need to spend some time reinforcing the difference between attributes and parameters. Rest assured that when we created the exam we spent just that little bit of extra time trying to make sure we made attribute and parameter questions as confusing as possible.[5]

 

Attributes

Parameters

Types

Application/context

Request

Session

Note

There is no servlet-specific attribute (just use an instance variable).

Application/context init parameters

Request parameters

Servlet init parameters

Note

No such thing as session parameters!

Method to set

setAttribute(String name, Object value)

You CANNOT set Application and Servlet init parameters—they’re set in the DD, remember? (With Request parameters, you can adjust the query String, but that’s different.)

Return type

Object

String

Note

Big difference!

Method to get

ServletContext.getAttribute(String name)

HttpSession.getAttribute(String name)

ServletRequest.getAttribute(String name)

Note

Don’t forget that attributes must be cast, since the return type is Object.

ServletContext.getInitParameter(String name)

ServletConfig.getInitParameter(String name)

ServletRequest.getParameter(String name)

The Three Scopes: Context, Request, and Session

image with no caption

Everyone in the application has access

image with no caption

Accessible to only those with access to a specific HttpSession

image with no caption

Accessible to only those with access to a specific ServletRequest

Attribute API

The three attribute scopes—context, request, and session—are handled by the ServletContext, ServletRequest, and HttpSession interfaces. The API methods for attributes are exactly the same in every interface.

Object getAttribute(String name)

void setAttribute(String name, Object value)

void removeAttribute(String name)

Enumeration getAttributeNames()

image with no caption

The dark side of attributes...

Kim decides to test out attributes. He sets an attribute and then immediately gets the value of the attribute and displays it in the response. His doGet() looks like this:

public void doGet(HttpServletRequest request, HttpServletResponse response)
                                         throws IOException, ServletException {

   response.setContentType("text/html");
   PrintWriter out = response.getWriter();

   out.println("test context attributes<br>");

   getServletContext().setAttribute("foo", "22");
   getServletContext().setAttribute("bar", "42");

   out.println(getServletContext().getAttribute("foo"));
   out.println(getServletContext().getAttribute("bar"));
}

Here’s what he sees the first time he runs it.

It’s exactly what he expected.

image with no caption

But then something goes horribly wrong...

The second time he runs it, he’s shocked to see:

image with no caption

Flex Your Mind

Look closely at the code, and think about what’s happening. Do you see anything that could explain the problem?

You might not have enough info to solve the mystery, so here’s another clue: Kim put this code in a test servlet that’s part of a larger test web app. In other words, the servlet that holds this doGet() method was deployed as part of a larger app.

Now can you figure it out?

Can you think of how he might fix it?

image with no caption

Context scope isn’t thread-safe!

That’s the problem.

Remember, everyone in the app has access to context attributes, and that means multiple servlets. And multiple servlets means you might have multiple threads, since requests are concurrently handled, each in a separate thread. This happens regardless of whether the requests are coming in for the same or different servlets.

image with no caption

The problem in slow motion...

Here’s what happened to Kim’s test servlet.

  1. Servlet A sets the context attribute “foo” with a value of “22”.

    image with no caption
  2. Servlet A sets the context attribute “bar” with a value of “42”.

    image with no caption
  3. Thread B becomes the running thread (thread A goes back to Runnable-but-not-Running), and sets the context attribute “bar” with a value of “16”. (The 42 is now gone.)

    image with no caption
  4. Thread A becomes the running thread again, and gets the value of “bar” and prints it to the response.

    image with no caption
    image with no caption

How do we make context attributes thread-safe?

Let’s hear what some of the other developers have to say...

image with no caption

Synchronizing the service method is a spectacularly BAD idea

OK, so we know that synchronizing the service method will kill our concurrency, but it does give you the thread protection, right? Take a look at this legal code, and decide whether it would prevent the problem Kim had with the context attribute being changed by another servlet...

public synchronized void doGet(HttpServletRequest request, HttpServletResponse response)
                                          throws IOException, ServletException {

    response.setContentType("text/html");
    PrintWriter out = response.getWriter();

    out.println("test context attributes<br>");

    getServletContext().setAttribute("foo", "22");
    getServletContext().setAttribute("bar", "42");

    out.println(getServletContext().getAttribute("foo"));
    out.println(getServletContext().getAttribute("bar"));
}
image with no caption

What do you think? Will it fix the problem Kim had? Look back at the code and the diagrams if you’re not sure.

Synchronizing the service method won’t protect a context attribute!

Synchronizing the service method means that only one thread in a servlet can be running at a time... but it doesn’t stop other servlets or JSPs from accessing the attribute!

Synchronizing the service method would stop other threads from the same servlet from accessing the context attributes, but it won’t do anything to stop a completely different servlet.

image with no caption

You don’t need a lock on the servlet... you need the lock on the context!

The typical way to protect the context attribute is to synchronize ON the context object itself. If everyone accessing the context has to first get the lock on the context object, then you’re guaranteed that only one thread at a time can be getting or setting the context attribute. But... there’s still an if there. It only works if all of the other code that manipulates the same context attributes ALSO synchronizes on the ServletContext. If code doesn’t ask for the lock, then that code is still free to hit the context attributes. But if you’re designing the web app, then you can decide to make everyone ask for the lock before accessing the attributes.

image with no caption
image with no caption

For context attributes, it won’t do any good to synchronize on the Servlet, because other parts of the app will still be able to access the context!

image with no caption

Note

Expect to see lots of code about thread-safety

On the exam, you’ll see plenty of code showing different strategies for making attributes thread-safe. You’ll have to decide if the code works, given a particular goal. Just because the code is legal (compiles and runs), doesn’t mean it’ll solve the problem.

Note

Since we have the context lock, we’re assuming that once we get inside the synchronized block, the context attributes are safe from other threads until we exit the block... sort of. Safe means “safe from any other code that ALSO synchronizes on the ServletContext.”

But this is the best you’ve got for making the context attributes as thread-safe as you can.

Are Session attributes thread-safe?

Think about it.

We haven’t talked about HTTP sessions in detail yet (we will in the Sessions chapter), but you already know that a session is an object used to maintain conversational state with a client. The session persists across multiple requests from the same client. But it’s still just one client we’re talking about.

And if it’s one client, and a single client can be in only one request at a time, doesn’t that automatically mean that sessions are thread-safe? In other words, even if multiple servlets are involved, at any given moment there’s only one request from that particular client... so there’s only one thread operating on that session at a time. Right?

image with no caption

Even though both servlets can access the Session attributes in separate threads, each thread is a separate request. So it looks safe.

Unless...

Can you think of a scenario in which there could be more than one request at the same time, from the same client?

What do you think? Are session attributes guaranteed thread-safe?

What’s REALLY true about attributes and thread-safety?

Listen in as our two black-belts discuss the issues around protecting the state of attributes from multithreading problems.

image with no caption

We know that context attributes are inherently NOT safe, because all pieces of the app can access context attributes, from any request (which means any thread).

 
 

Yes master. And I know that synchronizing the service method is not a solution, because although it will stop that servlet from servicing more than one request at a time, it will NOT stop other servlets and JSPs in the same web app from accessing the context.

Very good. Now what about Session attributes. Are they safe?

 
 

Yes master. They are for only one client, and the laws of physics prevent a client from making more than one request at a time.

You have much to learn, grasshopper. You do not know the truth about session attributes. Meditate on this before speaking again.

 
 

But master, I have meditated and still I do not know how one client could have more than one request...

You must think outside the Container. Color outside the lines. Run with scissors.

 
 

Very wise advice, master! I have it! The client could open a new browser window! So the Container can still use the same session for a client, even though it’s coming from a different instance of the browser?

Yes! The Container can see the request from the second window as coming from the same session.

 
 

So Session attributes are not thread-safe, and they, too, must be protected. I will meditate on this...

And how would you protect these session attributes from the havoc of multiple threads?

 
 

Ah... I must synchronize the part of my code that accesses the session attributes. Just the way we did for the context attributes.

That is good, yes, but synchronize on what?

 
 

I must synchronize on the HttpSession!

Protect session attributes by synchronizing on the HttpSession

Look at the technique we used to protect the context attributes. What did we do?

You can do the same thing with session attributes, by synchronizing on the HttpSession object!

image with no caption

SingleThreadModel is designed to protect instance variables

Here’s what the servlet specification says about the SingleThreadModel (or STM) interface:

image with no caption

Ensures that servlets handle only one request at a time.

This interface has no methods. If a servlet implements this interface, you are guaranteed that no two threads will execute concurrently in the servlet’s service method. The servlet container can make this guarantee by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet.

Note

Here’s the key part...

But how does the web container guarantee a servlet gets only one request at a time?

The web container vendor has a choice. The container can maintain a single servlet, but queue every request and process one request completely before allowing the next request to proceed. Or the container can create a pool of servlet instances and process each request concurrently, one per servlet instance.

Which STM strategy do you think is better?

image with no caption
image with no caption

Which is the better STM implementation?

Once again we must consult our black belts. These guys must know the score on the best STM implementation. Let’s see them battle it out...

image with no caption

Queue all requests

Send requests through a pool

Queuing the requests to a single servlet makes the most sense. It clearly implements what the spec writers intended.

 
 

But master, won’t performance be impacted? Surely, queuing each request prevents multiple users from access to the same servlet?

Yes, but that is the only way to protect the instance variables of the servlet.

 
 

But master, the container may also create a pool of servlet instances. Then the container can process one request with one servlet instance and another request with a second instance. Each request is handled in parallel.

Ahh, you see deeply into the fortune cookie, my student, but you do not see just how deadly that fortune might be...

 
 

You speak in riddles, master. What could possibly go wrong with the pooling strategy?

The servlet spec defines that a single servlet declaration in the deployment descriptor becomes a single object instance at runtime, but now using the STM interface, this definition is no longer valid. Can you imagine a scenario in which having multiple servlet instances fails?

 
 

Hmm, what if one of the instance variables is meant to record how many requests have been processed. The counter variable would have several different counts, and none of them would be right... only the summation of them is correct.

YES! You have penetrated the depth of the ruse that is servlet pooling. The semantics of the “single servlet instance” definition is lost. The servlet has lost touch with reality.

 

Relax

You do not need to know about these container STM strategies for the exam.

You just need to know that STM attempts to protect instance variables of the servlet.

Only Request attributes and local variables are thread-safe!

That’s it. (We include method parameters when we say “local variables”). Everything else is subject to manipulation by multiple threads, unless you do something to stop it.

Request attributes and Request dispatching

Request attributes make sense when you want some other component of the app to take over all or part of the request. Our typical, simple example is an MVC app that starts with a servlet controller, but ends with a JSP view. The controller communicates with the model, and gets back data that the view needs in order to build the response. There’s no reason to put the data in a context or session attribute, since it applies only to this request, so we put it in the request scope.

So how do we make another part of the component take over the request? With a RequestDispatcher.

image with no caption
  1. The Beer servlet calls the getBrands() method on the model that returns some data that the view needs.

    image with no caption
  2. The servlet sets a Request attribute named “styles”. (First it puts “Moose Drool” into an ArrayList.)

    image with no caption
  3. The servlet asks the HttpRequest for a RequestDispatcher, passing in a relative path to the view JSP.

    image with no caption
  4. The servlet calls forward() on the Request-Dispatcher, to tell the JSP to take over the request. (Not shown: the JSP gets the forwarded request, and gets the “styles” attribute from the Request scope.)

    image with no caption

RequestDispatcher revealed

RequestDispatchers have only two methods—forward() and include(). Both take the request and response objects (which the component you’re forwarding to will need to finish the job). Of the two methods, forward() is by far the most popular. It’s very unlikely you’ll use the include method from a controller servlet; however, behind the scenes the include method is being used by JSPs in the <jsp:include> standard action (which we’ll review in Chapter 8). You can get a RequestDispatcher in two ways: from the request or from the context. Regardless of where you get it, you have to tell it the web component to which you’re forwarding the request. In other words, the servlet or JSP that’ll take over.

<<interface>>

RequestDispatcher

forward(ServletRequest, ServletResponse)

include(ServletRequest, ServletResponse)

javax.servlet.RequestDispatcher

Getting a RequestDispatcher from a ServletRequest

image with no caption

The getRequestDispatcher() method in ServletRequest takes a String path for the resource to which you’re forwarding the request. If the path starts with a forward slash (“/”), the Container sees that as “starting from the root of this web app”. If the path does NOT start with a forward slash, it’s considered relative to the original request. But you can’t try to trick the Container into looking outside the current web app. In other words, just because you have lots of “../../../” doesn’t mean it’ll work if it takes you past the root of your current web app!

Getting a RequestDispatcher from a Servlet Context

image with no caption

Like the equivalent method in ServletRequest, this getRequestDispatcher() method takes a String path for the resource to which you’re forwarding the request, EXCEPT you cannot specify a path relative to the current resource (the one that received this request). That means you must start the path with a forward slash!

Calling forward() on a RequestDispatcher

view.forward(request, response);

Simple. The RequestDispatcher you got from your context or request knows the resource you’re forwarding to—the resource (servlet, JSP) you passed as the argument to getRequestDispatcher(). So you’re saying, “Hey, RequestDispatcher, please forward this request to the thing I told you about earlier (in this case, a JSP), when I first got you. And here’s the request and response, because that new thing is going to need them in order to finish handling the request.”

What’s wrong with this code?

What do you think? Does this RequestDispatcher code look like it will work the way you’d expect?

image with no caption

You’ll get a big, fat IllegalStateException!

Note

You can’t forward the request if you’ve already committed a response!

And by “committed a response” we mean, “sent the response to the client”. Look at the code again. The big problem is:

os.flush();

That’s the line that causes the response to be sent to the client, and at that point, this response is DONE. FINISHED. OVER. You can’t possibly forward the request at this point, because the request is history! You’ve already responded, and you get only one shot at this.

So, don’t be fooled if you see questions on the exam that forward a request AFTER a response is sent. The Container will throw an IllegalStateException.

Q:

Q: How come you didn’t talk about the RequestDispatcher include() method?

A:

A: It’s not on the exam, for one thing. For another, we already mentioned that it’s not used much in the real world. But to satisfy your curiosity, the include() method sends the request to something else (typically another servlet) to do some work and then comes back to the sender! In other words, include() means asking for help in handling the request, but it’s not a complete hand-off. It’s a temporary, rather than permanent transfer of control. With forward(), you’re saying, “That’s it, I’m not doing anything else to process this request and response.” But with include(), you’re saying, “I want someone else to do some things with the request and/or response, but when they’re done, I want to finish handling the request and response myself (although I might decide to do another include or forward after that...”).



[5] It’s true. If we’d made the exam simple and straightforward and easy, you wouldn’t feel that sense of pride and accomplishment from passing the exam. Making the exam difficult enough to ensure that you’d need to buy a study guide in order to pass it was never, EVER, a part of our thinking. No, seriously. We were just thinking of you.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset