When can a parameter value be null?

I’ve noticed that request.getParameter() always return a string for the parameter that corresponds to a text field in my form, even when the field is empty. To find out if the field is empty, I need to use code like this:

if (request.getParameter("foo").length() == 0) {
  ...
}

But in your book, you have examples where you test if the parameter value is null instead.

When is the value null and when is it an empty string?

Answer:
Most (all?) browers send empty form text fields to the server as an HTTP request parameter with an empty value. Hence, the value for a text field will rarely be null. Typically it’s an empty string. But it never hurts to test for both null and empty string to be on the safe side:

String foo = request.getParameter("foo");
if (foo == null || foo.trim().length() == 0) {
  ...
}

For checkboxes, radio buttons and select lists, on the other hand, the browser only sends a parameter if the item is selected. For these types of form elements, you must always be prepared to handle a null value.

How to pass request parameters to frame pages?

I have a servlet (or JSP) that sets a request attribute and then forwards to a JSP page. This JSP page contains a frame set, where each frame contains another JSP page. When I try to access the request attribute (as a request scope bean) in the JSP pages that represent the frames, it is not available anymore.

I know I could use session scope beans instead, but since the attribute values are only needed while setting up the frame pages, I want to avoid that. How can it be done?

Answer:
The reason you can’t use request attributes to transfer info to the JSPs loaded in separate frames is that request attributes are only available while you process the same request; the frame JSPs are retrieved with separate requests from the one that invokes the servlet.Here the servlet sets the attribute and forwards to the first JSP page. This means this JSP page processes the same request as the servlet, and can access the attribute. But this JSP page just sends back a response that contains the frame set. The browser then makes new requests for the JSP pages that represent each frame. A new request means that the original request attribute is lost.What you can do is let the first JSP generate the frame set so that each frame src attribute include a request parameter with a value created from the request attribute. The parameter is then sent by the browser with the request for each frame JSP page:

<frameset rows="65%,35%">
  <frame src="a.jsp?foo= name="a">
  <frame src="b.jsp?foo= name="b">
  <noframes>
    <body>
      Viewing this page requires a browser capable of displaying frames.
    </body>
  </noframes>
</frameset>

Note that this only works for request attributes of type String (or attributes that can be converted to a meaningful String).

The frame JSP pages can access the parameter value using a scriptlet, useBean/setProperty or a custom action:

<% String foo = request.getParameter("foo"); %>

<jsp:useBean id="pars" class="com.mycomp.MyBean" />
<jsp:setProperty name="pars" property="*" />

<mylib:doSomething param="foo" />

That is, in the same way as a JSP page gets access to any parameter value.

Can I communicate between JavaScript code and JSP?

I need to use JavaScript code to perform some user interaction based on data that is stored in a database. How can I get this data to the JavaScript code using JSP? And how can I communicate back from JavaScript code to JSP.
Answer:
The book contains a brief example of how you can generate JavaScript code from a JSP page. It does not show how to pass variables between the two environments, but it does describe in some detail the main concepts you need to understand: that JSP code executes on the server and JavaScript code executes in the browser.Given that, the only way to pass variable values from JSP code to JavaScript code is to generate JavaScript variable assignments dynamically in the JSP page, e.g.

<script language="JavaScript">
  // JavaScript code
  var choices = new Array();
  <%
    // Java code in a JSP scriptlet that assigns the
    // JavaScript array elements to values of a Java
    // array created earlier in the JSP page.
    for (int i = 0; i < aJavaArray.length; i++) {
  %>
      choices[<%= i %>] = "<%= aJavaArray[i] %>";
  <% } %>
  // More JavaScript code
  ...
</script>

In the other direction, the only way is to use JavaScript to set HTTP parameter values that get sent with a request for a JSP page, e.g. setting the value of a hidden field.

How can I run the examples from the first edition with another database than MS Access?

The first edition of the book describes how to use an MS Access database for all examples. How can I use another database?
Answer:
You can use any database you like, as long as there’s a JDBC driver for it. Just put the JDBC driver classes in the WEB-INF/lib or WEB-INF/classes directory and change the JDBC URL in the example JSP pages to point to your database. Mike Braden has been kind enough to contribute instructions¬†for how to run the examples with Oracle.

Lucy Newman has done the same for PostgreSQL, and Masako Onishi has contributed inststructions for InstantDB.

The second edition of the book uses the JSP Standard Tag Library (JSTL) actions for all database access. The data source used by the JSTL actions is configured in the web.xmlfile for the application, to make it easier to switch between databases.

I have also included a script with all SQL statements needed to create the example tables, located in WEB-INF/examples.sql. You can use this script to create the tables in a MySQL database, and it should work fine for most other database engines as well.

Why is there both a PBController and a PBDispatcher in the sample code?

I have downloaded the example code. In the directory src/com/ora/jsp/servlets, there are a PBControllerServlet class and a PBDispatcherServlet class.

I want to implement your Action Object design and get confused as to what files I need to look at. Where do I find what files belong to what example?

Answer:
Sorry about the confusion.

The PBControllerServlet class corresponds to examples 14-1 through 14-3. It contains the logic for all actions as private methods.

The PBDispatcherServlet class, the Action interface, all XXXAction classes and the ActionUtils class correspond to the example described in “A More Modular Design Using Action Objects”.

How can I use Tomcat behind IIS?

How can I configure Tomcat 3.2 with my IIS server so I don’t have to use http://localhost:8080?
Answer:The documents under Tomcat’s doc directory describe how you can configure Tomcat the way you want, but here’s a brief answer.If all you want is to avoid specifying the port number, you can just tell Tomcat to use port 80 instead of port 8080. You can change this in the conf/server.xml file:

<!-- Normal HTTP -->
<Connector className="org.apache.tomcat.service.PoolTcpConnector">
<Parameter name="handler"
  value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
<Parameter name="port"
  value="80"/>
</Connector>

After you make this change and restart Tomcat, you can use a URL like http://localhost/ instead. Note that if you try this on a Unix/Linux system, you must start Tomcat as “root”, which may be a security risk. On Windows, however, you can use port 80 from any login account.

The only reason for running Tomcat behind IIS that I can think of is if you need to serve both JSP pages and dynamic content based on other non-Java technologies (ASP, CGI, etc). You can read more about how to use Tomcat with IIS in doc/tomcat-iis-howto.html.

How can I use a different JSP directory than webapps for Tomcat?

How can I put JSP files in a directory other than /webapps/ when I use the Tomcat 3.2 container?
Answer:
The documents under Tomcat’s doc directory describe how you can configure Tomcat the way you want, but here’s a brief answer.Edit the conf/server.xml file and add an element like this for top level directory you want to store the JSP files in:

<Context path="/myapp"
  docBase="C:/websites/myapp"
  crossContext="false"
  debug="0"
  reloadable="true" >
</Context>

Note, however, that the directory you specify as docBase must contain the complete web application directory structure, i.e. the WEB-INF directories as well as the JSP pages (see Chapter 2, 4 and Appendix D in the book for more info).

You need to restart Tomcat for this change to take effect.

How can I access a session scope bean in a servlet?

I create a java bean in the session scope using <jsp:useBean> in a JSP page. I then need to access the information held by the bean in a servlet. How can I get hold of the bean in the servlet?
Answer:
The JSP session scope corresponds to the javax.servlet.http.HttpSession class in the Servlet API. The session scope objects are saved as attributes for the current instance of this class, so you can get them with code like this in a servlet:

HttpSession session = request.getSession();
String foo = (String) session.getAttribute("foo");

For more information about how to share objects between JSP pages and servlets, see Chapter 14 in the book.

When do I need to call clearBody()?

In another JSP book, they make the point of clearing the body content after using it, so the same instance can be reused for another tag handler.In JavaServer Pages (O’Reilly), you do not say anything about calling the clearBody() method. When do I really have to call this method?
Answer:
Typically, you do not need to call the clearBody() method, and it has nothing to do with the container’s ability to reuse the BodyContent instance.According to the JSP 1.1 spec, the container is supposed to get an instance of the BodyContent class for each BodyTag by calling PageContext.pushBody(). The spec says that this method must return a “new” instance, but the language will likely be relaxed in JSP 1.2 to allow a container to use pooled instances instead. Anyway, the BodyContent instance it returns must be empty, so there’s no need to clear it for reuse reasons. This is also clarified in the description of setBodyContent() in the JSP 1.2 Proposed Final Draft.

A scenario when you do need to call clearBody() is in an iterating tag handler class, if you push the processed body content to the parent’s “out” in doAfterBody(), i.e. for each pass through the body. In the iteration example in my book (Chapter 16), it’s not needed since I let the evaluation of the body for each pass accumulate and process all of it after the last pass in the doEndTag() method.

Why do I get “socket write error” messages from Tomcat?

Right after installing the ‘ora’ example application for Tomcat, I surfed to http://localhost:8080/ora no problem, then clicked on Chapter 5, Current Date/Time example. Long delay, then finally the date and time are displayed. But in my Tomcat startup console window, I see:

2000-12-29 10:18:37 - Ctx(  ): IOException in: R(  + 
  /tomcat-power.gif + null) socket write error (code=10053)
2000-12-29 10:18:37 - Ctx(  ): IOException in: R(  + 
  /index.html + null) socket write error (code=10053)

Do I have an install problem?

Answer:
First, the delay you see the first time you access a JSP page is the time it takes to convert the JSP page into a servlet class file. It only happens the first time, and when you change the JSP page.The error message means that Tomcat could not send the complete response to the browser, because the browser has already closed its connection.As far as I know, this only happen with Internet Explorer (IE). IE seems to close the connection before it has received the complete response when it asks for a resource it already has in its cache. So the first time you load the Tomcat index page, everything is fine. But from then on, both the index.html and the image file are in IE’s cache, and you see this message. It doesn’t cause any problems though, so you can just ignore it.

Rumor has it that this problem can be fixed with the latest patches for IE, at least on some Windows platforms. You can also reduce the log level for the Tomcat server so it doesn’t print these error messages. See the Tomcat configuration documents for details.

If you use Netscape instead, you’ll notice that it behaves according to the HTTP spec, so you don’t get this message.