|
|
 |  |
|
|
Each web application is part of the web server. It has a unique name or
path that identifies it within the server.
Each web application has a corresponding url. The url begins with the part
needed to identify the server, followed by the webapp path:
http://server/webapp-name. Each server has one
web-app that is the default, it is the one that is used when no webapp-name is
provided.
Web applications are "deployed" within a web server, such as Resin. The
simplest way to "deploy" a new web application is to the create a subdirectory
in $RESIN_HOME/webapps/webapp-name. The special
webapp name ROOT is used for the default web application. (There
are other deployment options, but for the
purposes of this discussion the one described here is used).
A web application has "web components", such as Servlets, Filters, JSP's,
supporting Java source files, and supporting java libraries.
You can make your own web application in a local install of Resin. Make a
directory $RESIN_HOME/webapps/test. Use the url
http://localhost:8080/test to access the web application.
To start with, you can make a file named
$RESIN_HOME/test/index.jsp.
Hello, world!
index.jsp is a JSP file, and is also the name of the default page
to show for a directory. So you can use the url
http://localhost:8080/test/index.jsp in your browser, or since
index.jsp is the default page to show, you can use
http://localhost:8080/test.
For example, www.hogwarts.com has two web
applications, the default web application, and a web-application
named "intranet".
Server: www.hogwarts.com
Server URL: http://www.hogwarts.com
webapp: default webapp
webapp URL: http://www.hogwarts.com/
filesystem directory: $RESIN_HOME/webapps/ROOT
default jsp page: $RESIN_HOME/webapps/ROOT/index.jsp
webapp: intranet
webapp URL: http://www.hogwarts.com/intranet
filesystem directory: $RESIN_HOME/webapps/intranet
default jsp page: $RESIN_HOME/webapps/intranet/index.jsp
From the Servlet Specification 2.2:
A servlet is a web component, managed by a container, that generates
dynamic content. Servlets are small, platform independent Java classes
compiled to an architecture neutral bytecode that can be loaded
dynamically into and run by a web server. Servlets interact with web
clients via a request response paradigm implemented by the servlet
container. This request-response model is based on the behavior of the
Hypertext Transfer Protocol (HTTP).
A Servlet is a Java class that has a method that gets called with
information about a client request and is expected to produce some
kind of result to be sent back to the client. It is just like any
other class in Java, it happens to inherit from , so Resin can call certain
methods on it when a request is made.
A Servlet class is made available by placing the .java source file
in the approriate sub-directory and file of WEB-INF/classes:
package example;
import java.io.*;
import javax.servlet.http.*;
import javax.servlet.*;
/**
* Hello world servlet. Most servlets will extend
* javax.servlet.http.HttpServlet as this one does.
*/
public class HelloServlet extends HttpServlet {
/**
* Initialize the servlet. Servlets should override this method
* if they need any initialization like opening pooled
* database connections.
*/
public void init() throws ServletException
{
}
/**
* Implements the HTTP GET method. The GET method is the standard
* browser method.
*
* @param request the request object, containing data from the browser
* @param repsonse the response object to send data to the browser
*/
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Returns a writer to write to the client
PrintWriter out = response.getWriter();
// Write a string to the browser.
out.println("Hello, world!");
out.close();
}
}
Entries in ithe WEB-INF/web.xml file tell Resin the URL that
should invoke the Servlet:
<web-app xmlns="http://caucho.com/ns/resin">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<url-pattern>/hello</url-pattern>
<servlet-name>hello</servlet-name>
</servlet-mapping>
</web-app>
In a web-app named "foo" on a server named "localhost" listening on port
"80", the servlet is now invoked with the URL
http://localhost:8080/foo/hello.
More information on the usage of Servlets is available in the Servlet section of the Resin documenation.
Java Server Pages are text files that contain text to be output (usually
HTML or somesuch) and special directives, actions, scripting elements, and
expressionsthat are used to generate results dynamically.
From the JSP 2.0 specification:
JavaServer Pages technology supports scripting elements as well as actions.
Actions encapsulate useful functionality in a convenient form that can be
manipulated by tools. Expressions are used to access data. Scripts can be used
to glue together this functionality in a per-page manner.
With JSP the developer specifies the content mostly as the kind of thing they
want to send back to the client or browser, for example HTML. Optionally
interspersed with the HTML are special xml tags (directives and actions), EL
expressions, or specially marked scripting code (Java code). The special xml
tags, EL expressions and Java code are used to generate dynamic ouput.
It is helpful to understand what it is that Resin does with a
JSP page. Basically, it takes the JSP page and turns it into the Java
code for a Servlet, a process of translation.
From the JSP specification:
JSP pages are textual components. They go through two
phases: a translation phase, and a request phase. Translation is done
once per page. The request phase is done once per request.
The translation phase occurs when Resin takes a look at the
JSP page, reads it in, and creates a Servlet. This only needs to be
done once. Now when a request from a client comes in, Resin
will call the appropriate method in the Servlet that it created from the.
During translation, Resin takes all of the code that has been specially
marked in the JSP as java code and inserts it directly into the code for a
Servlet. It takes all of the template text and makes the equivalent of print
statements to generate that ouput.
Because JSP files are translated into Servlets, JSP is an extension to Java
Servlets. Everything that applies to Java Servlets also applies to JSP. Much
information that is relevent to JSP programming is found in documentation about
Java Servlets. So you want to have the Servlet Specification around as a handy
reference, as well as the JSP Specification. Any reference to the capabilities
and resources available to a Servlet are also available to a JSP page.
This process is invisible to the JSP developer, all the developer
needs to do is make the JSP page and Resin will look at it and
turn it into a Servlet.
JSP has it's own section in the Resin documentation,
the following is an introductory guide.
Unless specially marked, the text in the JSP file will be sent exactly
as it is in the text file as part of the response. This is called
template data in the JSP specification.
JSP EL is the JSP Expression Language. It is used to evaluate
expressions that do not have side-effects (side-effects are changes to
Objects). The use of EL is recognizable by it's syntax:
${ expr }.
JSTL is the JavaServer Pages Standard Tag Libray, a set of tags that are
used to create dynamic output from JSP. These tags look like regular XML tags,
and are interpreted by Resin at translation time to generate java code that
performs the desired action.
EL and JSTL are used throughout this discussion, the Resin JSP documentation, the JSP
Specification, and the JSTL Specification provide
more information.
<%@page session="false" contentType="text/html" %>
<%@taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<head>
<title>A simple thing</title>
</head>
<body>
<!-- this comment gets all the way to the browser -->
<%-- this comment gets discarded when the JSP is translated into a Servlet --%>
<%
// some java code that makes the variable `x' available to EL
pageContext.setAttribute("x",new Integer(5));
%>
The value of x is ${ x }
The value of x + 2 is ${ x + 2 }
Is x
less than 6?
<c:if test="${ x < 6 }">
<%@include file="y.jsp" %>
</c:if>
</body>
Yes, it is true that x is less than 6,
with a value of ${ x }
<head>
<title>A simple thing</title>
</head>
<body>
<!-- this comment gets all the way to the browser -->
The value of x is 5.
The value of x + 2 is 7.
Is x
less than 6?
Yes, it is true that x is less than 6,
with a value of 5.
</body>
Prior to the introduction of JSTL and EL, JSP pages used the direct insertion
of Java code to accomplish the same thing. The use of JSTL and EL is much
cleaner and more maintable.
Often it is desirable to include the contents of another file into a
JSP file. For example, sometimes there is code that you find yourself
using over and over again. The mechanism for this is the
include directive:
<%@ include file="relativeURLspec"%>
Using the include directive it is exactly the same as if the included
text was in the original file. The text is included at translation
time - when the JSP is turned into a servlet.
A JSP page can use the contentType attribute of the
page directive to indicate the content type of the response it
is sending. For example, text/html and
text/wml are valid content types.
Since this value is part of a directive, a given page will always
provide the same content type. It is also possible to dynamically
indicate the content type using the response object, which is
discussed later.
A JSP comment is of the form:
<%-- anything but a closing --%> ... --%>
The body of the JSP content is ignored completely. JSP Comments are discarded
at translation time, they do not become part of the Servlet that is used to
generate the response. Comments are useful for documentation but also to
comment out some portions of a JSP page. JSP comments do not nest.
In order to generate comments that appear in the response to the requesting
client, the HTML and XML comment syntax is used, as follows:
<!-- comments ... -->
Java code in the JSP is marked by the special characters <%
and %>. To insert the value of a variable or an expression in
the output it is marked with ><%= expr &>.
Be careful not to depend on the ability of JSP to include Java code too much.
JSP is best used to present a view of data that has already been
prepared in Servlets or other code, as discussed in Architecture.
Now that JSTL and JSP EL exist, they are preferred over the insertion of Java
code directly.
<%@page session="false" contentType="text/html" import="java.util.*, example.*%>
<head>
<title>A simple thing</title>
</head>
<body>
<!-- this comment gets all the way to the browser -->
<%-- this comment gets discarded when the JSP is translated into a Servlet --%>
<% int x = 5; // java-style comments valid here %>
The value of x is <%= x %>.
The value of x + 2 is <%= x + 2 %>.
Is x
less than 6?
<% if (x < 6) { %>
<%@include file="y.jsp" %>
<% } %>
</body>
Yes, it is true that x is less than 6,
with a value of <%= x %>.
<head>
<title>A simple thing</title>
</head>
<body>
<!-- this comment gets all the way to the browser -->
The value of x is 5.
The value of x + 2 is 7.
Is x
less than 6?
Yes, it is true that x is less than 6,
with a value of 5.
</body>
Usually when making a JSP the developer draws on classes from various
packages. Unless these packages are imported, the use of such a class
must include the fully qualified class name:
<%
java.util.Date d = new java.util.Date();
%>
Packages can be imported with the import attribute of the
page directive. Multiple packages are seperated with a comma:
<%@ page import="java.util.*, example.*" %>
<%
Date d = new Date();
%>
Custom tag libraries are a mechanism that allows developers to make
functionality available to a JSP author through the use of XML tags.
As an example, a mail tag can be implemented and then used in the JSP
in the following manner:
<mail:mailMessage
from="registration@hogwarts.com"
to="<%= userEmail %>"
subject="Hogwarts Registration">
Thank-you for registering with the Hogwarts news service. We will be sending
you an email with twice-weekly with updates and the latest news from Hogwarts.
</mail:mailMessage>
Tag libraries can be very useful, however they are somewhat
complicated to implement. They are probably best left to developers of
libraries -- the taglibs can provide some simple access to the
functionality of the library.
More information on implementing custom tag libraries is in the JSP section of the Resin documentation.
From the Servlet Specification 2.4:
A filter is a reusable piece of code that can transform the content of HTTP
requests, responses, and header information. Filters do not generally create a
response or respond to a request as servlets do, rather they modify or adapt
the requests for a resource, and modify or adapt responses from a resource.
A Filter is a Java class that is used to intercept the request and the
response ("request" and
"response" are discussed later). A filter can
intercept the request before it get's to other web components, such as a JSP or
Servlet, and change what the request looks like. A filter can intercept the
response that is generated by web components, such as a JSP or Servlet, and
change (transform) the reponse before it is sent to the client.
More information on the usage of Filters is available in the Servlets and Filters section of the Resin documenation.
A developer can, and usually does, use the general facilities of Java to
create custom Java classes that are used by the Servlets, JSP, Filters, and
other components of the web applications. Java source files are placed in the
WEB-INF/classes/ directory (for example,
WEB-INF/classes/com/hogwarts/Util.java, and are automatically
compiled by Resin.
A web application can take advantage of java code libraries. These
libraries are usually packaged in a .jar file, and placed in the
WEB-INF/lib directory (for example,
WEB-INF/lib/batik.jar). The libraries in the jar file are then
available to the Servlet, JSP, Filter, and other components of the web
application.
Jar libraries usually contain code that is not specific to the web
application, for example a library that provides a database driver, or a
library that is used to generate images.
The componets of a web application are placed in appropriate files and
configured using the WEB-INF/web.xml file.
| File | Description
|
| /index.jsp | A jsp file that is usually the default file that is accesed
|
| /WEB-INF/web.xml | The file that configures the Web Application
|
| /WEB-INF/classes | A directory containing classes specific to this
application
|
| /WEB-INF/classes/com/hogwarts/foo/Util.java |
|
| /WEB-INF/classes/com/hogwarts/foo/Util.class |
|
| /WEB-INF/lib | A directory containing jar files
|
| /WEB-INF/lib/mysql-connector-java-3.0.9-stable-bin.jar | An example usage of the lib directory, the MySQL driver
|
For the most part, the directory structure of a web application
reflects the structure that the end-user will see from their browser.
In addition, a special directory named
WEB-INF is recognized by Resin.
This directory contains a WEB-INF/classes sub-directory which is
where you put any Java classes that are specifically for
your application.
There is also a WEB-INF/lib directory which can contain .jar files
for libraries that are needed by the application. These .jar files are usually
third-party libraries or libraries that are reused amongst many different web
applications.
Finally, the file WEB-INF/web.xml is used to
configure your web application.
A Web Application is configured with a deployment descriptor that
collects information about the JSP pages, Servlets, security zones,
and other resources used in the Web Application.
A full description of it can be found in the JSP specification.
In the web.xml file (and in Java programming in general), always use
"/" as the path seperator. Do not use the MS-DOS/Windows "\"
path seperator.
A convenience that is provided by Resin is the automatic
compilation of Java files that are changed.
You can take advantage of this by placing your java source files in
the WEB-INF/classes/... directory of your web application.
For example, if you have a file Util.java, in package
com.hogwarts.foo, place the file in
WEB-INF/classes/com/hogwarts/foo/Util.java. Now any
changes to Util.java will result in the automatic recompilation of
the java file into a class file.
ServletContexts, Sessions, Requests, and Responses have corresponding
java objects that Resin creates. Each of these objects has a
unique scope: they are created at a certain time and destroyed at a
certain time.
The JavaServer Pages specification inherits from the Servlet
specification the concepts of ServletContexts, Sessions,
Requests and Responses.
These objects are created by Resin, they are always available
to a Servlet, Filter, or JSP page.
A ServletContext provides a view of the application that the Servlet, Filter,
or JSP is running in. The ServletContext models the Web Application. A
ServletContext is an object that is common to all
Servlets in an application.
A ServletContext is represented by a
object.
Resin creates a ServletContext as soon as the Web Application
is started, and it remains until the Web Application is closed. There
is one ServletContext made for each web application, and any usage of
the ServletContext will always use the same one.
Every time a user follows a URL that points to a Servlet or JSP within
the Web Application, Resin creates a Request object to
represent the current request. Resin also creates a Response object
which the developer can use to set certain things that apply to the
response to the users browser.
A request is represented by a
object.
A response is represented by a
object.
A new Request and Response are created each time the user follows a
link into the Web Application. These objects last until the response
is sent back to the client.
A Session is established for each user of the web application. The
first time a user accesses anything within the web application,
Resin recognizes this unknown user and creates a new Session to
represent them. This Session object will remain the same for that user
for the duration of their use of the web application.
A session is represented by a
object.
The Session is created the first time a user access a component in the
web application that requests the session. Resin sees the incoming request
from a user and checks to see if it has a Session for that user. If it does
not, it creates one. This session object will remain the same for that
user.
The end of the session object is a bit complicated. Since
Resin cannot tell the difference between when the user has stopped
using the application and when the user is just taking a long time to
do something, Resin must guess. Resin uses a time-out
value to determine when it should assume that the user has gone
away, it defaults to 30 minutes. What this means is that if a user has
not accessed any resource in the Web application for 30 minutes the
Resin will destroy the session object for that user.
A developer can also explicitly destroy the Session object, and that
is discussed later.
Resin establishes a session by giving the user's browser a
unique id that is returned back to Resin with each new
request. This is accomplished in one of two ways: using cookies or URL
rewriting.
Resin attempts to track the session of a user by sending the
user's browser a cookie. This cookie contains a long string that
Resin creates that becomes the id of the session.
Sometimes Resin cannot establish a cookie, either because the
user has disabled cookies in their browser or because the browser does
not support them (as is the case with some HDML and WML browsers). If the
cookie cannot be established then something called URL rewriting is
used.
with URL rewriting, Resin rewrites every URL that it submits to the user so
that it contains a portion ';jsessionid=id;'. Then for each incoming
request the first thing it does is look for this parameter, and if it is
available it knows a session has been established and it removes the jsessionid
and uses it to find the users session object.
URL rewriting requires some assistance from the developer, which is
discussed later.
The Servlet implementation class usually obtains the ServletContext in the
init() method. The request and response object are passed in the
doXXXX() method. The request object is used to obtain the
Session.
When translation of a JSP to a Servlet occurs, there are some variables that
are automatically defined. These variables can be used within any Java code
that is inserted in the page.
| Variable | Class | Description
|
| response | |
Assists in sending a response to the client. Includes the ability to
set the HTTP response headers.
|
| request | |
Provides client request information including parameter name and
values from forms and the HTTP headers that the client sends.
|
| session | |
Provides a way to identify a user across more than one request
and allows the developer to store information about that user (but see below).
|
| application | |
Every Web Application gets a ServletContext when it is started. It
contains information and attributes that apply to the whole
application.
|
| config | |
The ServletConfig for this JSP page
|
| pageContext | |
A variable specific to JSP (not available to servlets). It contains a
number of convenience functions for use in a JSP page.
|
| out | |
An Object that is used to write into the output stream
|
With JSP, the page directive is used to indicate that the JSP needs
the session object. When the page is executed, and has indicated that the
session is needed, a session will be created for the user if it has not already
and the session variable will be made available.
<%@page session="true">
The default for session is true, which is
convenient for pages that need the session, but creates an undue burden on the
server if the page does not need the session. Therefore it is best to mark all
JSP pages with session="false" unless they really do need the
session.
<%@page session="false">
Each of the objects application, session, and
request can have attributes. These attributes consist
of a name and a value.
Using attributes the developer can store a value for later retrieval.
The name is a String that uniquely identifies the attribute, and the
value is a Java object.
The following methods are available for the application,
session, and request objects.
| Method | Description
|
| getAttribute(String name) |
Return the Object that is associated with the passed
name. Usually you will need to cast the Object to whatever
class you know it to be. If there is no attribute with the given name,
null is returned.
|
| setAttribute(String name, Object value) |
Associates the given name with the value. If an
attribute name already exists, it is replaced.
|
| removeAttribute(String name) |
Removes the attribute with the given name if it exists.
|
As a developer you have a choice of which object to store attributes
in. The object that you choose should be appropriate to the scope
within which you will need to get that value out again.
Whenever possible put the attribute in the request object. If that
cannot work, put it in the session object. And very rarely, put values
in the application object.
The reason for this order is simple, all of the attributes in a
session cannot be garbage collected until they are explicitly removed
or the session expires. All of the objects in the application stay
until they are explicitly removed or the web application is stopped or
restarted.
Probably the most important and most frequent usage of the response
object is to rewrite the URL. Recall from earlier that in order to
maintain the identity of a Session with the user Resin may
have to add a special parameter to every URL. The developer must
co-operate with this, using the response.encodeURL method.
Because of this, it is a good idea to form a String for every URL you
will use in a page and store it in a variable:
<%
String boatUrl = response.encodeURL("water/boat.jsp");
String goatUrl = response.encodeURL("animals/goat.jsp");
%>
<%-- the presentation --%>
Hello, would you like some green eggs and ham?
Would you, could you, on a
<a href='<%= boatUrl %>'>boat</a>?
Would you, could you, with a
<a href='<%= goatUrl %>'>goat</a>?
This has the added benefit of placing all of your URL's in
one place, allowing you to change them more easily.
Sometimes it is desirable to send a redirect to the client. This is a
response to the client that tells it to go to some other URL. This is
often used by developers so that the URL in the browser makes sense to
the user. It is however, a slow procedure because it requires a
response to go all the way back to the browser, and then the browser
will make a new request.
The redirect is accomplished by using the response.sendRedirect()
method. Again, the URL must be encoded, and a special kind of encoding
is needed for a redirect:
<%
String redirectUrl =
response.encodeRedirectURL("elsewhere.jsp");
response.sendRedirect(redirectUrl);
%>
Redirects often do not work with wireless devices like cell phones and WML
clients, and the emulators of these devices. As well, the latency of a wireless
connection compounds the speed problem of using redirects. Redirects should
probably be avoided with wireless devices.
As mentioned eariler, the <%@ page contentType="..." %>
directive can be used to tell the browser the type of content that it is
getting.
The page directive method does not allow you to do this
dynamically. You can instead use: response.setContentType("...")
to set the content type.
Often it is necessary to inform the browser that a page should not be
cached - the browser should ask for a new copy of the page every
time. The best way to do this is by setting appropriate HTTP headers
in the response to the browser.
Unfortunately, all the browsers work differently. The following seems
to be a consensus on the headers to set:
<%
/** stop browser from caching */
response.setHeader("Cache-Control","no-cache,post-check=0,pre-check=0,no-cache");
response.setHeader("Pragma","no-cache");
response.setHeader("Expires","Thu,01Dec199416:00:00GMT");
%>
A little known fact is that it is necessary to inform the browser with
certain pages that they are private pages, meaning they should never
be seen by anyone except the current user.
This applies to any pages that the user has needed a password to get to.
<%
/**
* Add an HTTP header to the response that
* indicates to the browser and any
* intervening cache's that this is a private
* page, and should never be seen
* by a different user.
*/
response.addHeader("Cache-Control","private");
%>
The main use of the request object is to get the values that a user
has supplied in a form submit. For example, with this HTML on
page a.jsp:
<%
String bUrl = response.encodeUrl("b.jsp");
%>
<%-- presentation --%>
<form method="post" action="<%= bUrl %>">
What is your favourite kind of eggs?
<input type="text" name="favegss" size="25">
<br>
<input type="submit" value="Submit">
<input type="reset" value="Reset">
</form>
The value that was supplied in ``eggs'' can be retrieved with:
<%
String aUrl = response.encodeUrl("a.jsp");
%>
<%
String faveggs = request.getParameter("eggs");
if ((faveggs != null) && (faveggs.trim().length() == 0))
faveggs = null;
%>
<%-- presentation --%>
<% if (faveggs == null) { %>
No eggs supplied!
<a href="<%= aUrl %>">Try again</a>
<% } else if (faveggs.equals("green")) { %>
Of course we have <%= faveggs %> eggs!
It's one of our favourites too.
<% } else { %>
We do not have <%= faveggs %> eggs.
<% } %>
The Session object is used primarily to store two types of
information. The first is information about the user, and the second
is data that is built up and used over multiple pages. A classic
example of information you would store in a session is user profile
information, or a shopping cart that is filled up over many pages.
It is important to try to limit the amount of information that is
stored in the session object.
The session object will go away if the user is inactive for a certain
time (usually 1/2 hour). You can also explicitly destroy the session,
which you may want to do for example if the user chooses to logout.
This is accomplished with: session.invalidate();
It is possible to add a hook so that something can be done when
Resin decides that a Session has expired, or the Session is
explicitly destroyed.
To accomplish this, you write a class that implements the
interface.
Then you register this class with the session simply by putting it as one of
the attributes. The Session will notify all of it's attributes that implement
.
<%@page import="example.SessionListener" %>
<%
// example.SessionListener implements HttpSessionBindingListener
SessionListener d = new SessionListener();
session.setAttribute("sessiongoesbyebye", d);
%>
It is important to realize that the user can have multiple
windows open that use the same session. If the user uses the "Open in
new Window" functionality of a browser, they will have two windows
open and the Web Application will see them both as belonging to the
same session. This has some ramifications on how the Session can be
used for shopping-cart like applications.
For example, let's assume that an application uses the Session
attribute "cart" to store shopping cart information about different
types of juice a user has chosen to purchase.
The user may start one juice buying transaction and get to the
confirmation page, having 3 grape and 2 apple in their
cart. Now, what happens if at this point they use another browser
window to initiate another purchase? If the Web Application is using
the Session to store shopping cart information then the second window
may destroy the contents of the shopping cart, so that if the user
finishes the first window they end up buying nothing!
A possible solution for this is to keep a version counter in your
cart. Every time the cart is changed, the version counter is updated.
Then, when your application shows the "confirm purchase" page (the next action
will cause the purchase to occur), it sends the version counter to the "confirm
purchase page". The "confirm purchase" page submits that version counter as a
parameter. The application can check the submitted version counter, and the
current version counter in the shopping cart - if they are different then the
cart has been modified in some other way, and a message is returned that the
purchase did not occur because the cart had been modified elsewhere.
Some errors may occur at JSP translation time. This could be, for
example, from an error in the syntax of some Java code in your JSP.
You will usually see this error in your browser the first time you try
to access the page. Resin can also put the error in log files.
From the JSP specification:
The translation of a JSP page source into a corresponding JSP page
implementation class using the Java technology by a JSP container can
occur at any time between initial deployment of the JSP page into the
runtime environment of a JSP container, and the receipt and processing
of a client request for the target JSP page. If translation occurs
prior to the JSP container receiving a client request for the target
(untranslated) JSP page then error processing and notification is
implementation dependent. Fatal translation failures shall result in
subsequent client requests for the translation target to also be
failed with the appropriate error; for HTTP protocols, error status
code 500 (Server Error).
Some errors may occur at the time a Servlet or other source file is being
compiled by Resin. This could be, for example, from an error in the syntax of
the Java code.
You will usually see this error in your browser the first time you try
to access the page. Resin might also put the error in log files.
Java handles runtime errors with exceptions. If an exception is not
caught in your JSP or Servlet, Resin will use a special error page
to send results back to the browser. Resin uses a default error
page unless you explicitly provide an error page yourself.
From the JSP specification:
During the processing of client requests, arbitrary runtime errors can
occur in either the body of the JSP page implementation class or in
some other code (Java or other implementation programming language)
called from the body of the JSP page implementation class. Such errors
are realized in the page implementation using the Java programming
language exception mechanism to signal their occurrence to caller(s)
of the offending behavior 1 . These exceptions may be caught and
handled (as appropriate) in the body of the JSP page implementation
class.
However, any uncaught exceptions thrown from the body of the JSP page
implementation class result in the forwarding of the client request
and uncaught exception to the errorPage URL specified by the offending
JSP page (or the implementation default behavior, if none is
specified).
The offending java.lang.Throwable describing the error that occurred
is stored in the javax.ServletRequest instance for the client request
using the putAttribute() method, using the name
javax.servlet.jsp.jspException. Names starting with the prefixes java
and javax are reserved by the different specifications of the Java
platform; the javax.servlet prefix is used by the Servlet and JSP
specifications. If the errorPage attribute of a page directive names
a URL that refers to another JSP, and that JSP indicates that it is an
error page (by setting the page directive's isErrorPage attribute to
true) then the exception implicit scripting language variable of that
page is initialized to the offending Throwable reference.
There are many ways to use the capabilities that are offered by
JSP -- different models apply to different applications.
The simplest model is to use JSP as an add-on to existing web
pages. At the top of each page is the Java code that is necessary for
the display of the page, and at the bottom is the markup that is to be
output, with appropriate insertion of any dynamically generated
variables.
Note the seperation of the different logical parts. It is a very good
idea to keep the presentation section as Java-less as possible. Setup
all of the values in the logic part, and then use only simple
<%= var %> and if statements in the
presentation part.
<%-- urls --%>
<%
// store your target urls in String variables
%>
<%-- incoming parameters --%>
<%
// store form values from the request object in variables
%>
<%-- logic --%>
<%
// we all make decisions with logic, right?
%>
<%-- presentation --%>
<markup>
<forthebrowser>
</forthebrowser>
</markup>
This seems like a sensible approach. However, imagine that later it is
decided that a different set of HTML is needed for the output if there
is no news available. As well, support of WML output is required. Now
we need to put the display code for 4 different types of output into
one page. Maybe we need to go to different places as well, for
example an administrator might get a different display page, or we
need to check the users profile to see what is apporiate to display.
This is too much complication to put all in one place.
This type of implementation, because of it's limitiations and it's
inability to change without exponentially increasing the complexity,
should be avoided.
To address some of the disadvantages of the Simple JSP method, it is
possible to seperate the `logic' and the `presentation' into two
different JSP files.
In this model, instead of a link pointing directly to the page that
does the display, it points to a page that handles the incoming
request. This 'logic' page contains the Java code that is responsible
for preparing the values that will be used for displaying. It stores
these prepared values as attributes of the request object,
and then forwards to the appropriate display page. The display
page then pulls the information it needs out of the request object and
displays it.
<%
/** -- incoming parameters -- */
String strJuiceType = request.getParameter("juiceType");
String strQuantity = request.getParameter("juiceQuantity");
/** -- logic -- */
Double cost;
String strCost;
here we might do a check to make sure mandatory fields
have values.
Here we might do a database lookup to determine the price, and
set the cost value to the price * quanitity
Now we might format the cost double into
a two-decimal number and store it in strCost
/** -- set outgoing parameters
-- forward to display page -- */
/** note that here we put juiceType in as a request
attribute, even though the display page could get
it from the request parameters. This helps us keep
the interface between the logic and the presentation
cleaner */
request.setAttribute("cost", strCost);
request.setAttribute("juiceType", strJuiceType);
request.setAttribute("quantity", strQuantity);
if (isWML)
pageContext.forward("SeperateJspPresentationWML.jsp");
else
pageContext.forward("SeperateJspPresentationHTML.jsp");
%>
<%-- urls --%>
<%-- prepared objects --%>
<%
String cost = (String) request.getAttribute("cost");
String juiceType = (String) request.getAttribute("juiceType");
String quantity = (String) request.getAttribute("quantity");
%>
<%-- presentation --%>
Hey, if you want <%= quantity %> bottles of
<%= juiceType => juice, it is going to cost
you $<%= cost %>
Here we have introduced a new thing: pageContext.forward.
The pageContext.forward(String url) forwards the processing to a
different JSP page. That is, it passes control over to another
page. This page is then executed, inheriting the current request and
response objects. It is important that this is the last thing
that a JSP page does.
Even the seperation of all logic into a different JSP can get a bit muddled.
You can seperate the `logic' into two types of logic, business logic
and presentation logic.
Presentation logic is logic that is part of the presentation.
Examples are form validation and formatting of numbers into strings.
Business logic is programming that involves your data. If you can
separate something in your mind from the presentation, it doesn't
depend on the presentation in any way, that's business logic.
Examples are database lookups and shopping cart manipulation.
Your application will be cleaner and easier to manage if you put your
business logic in Java classes (beans) which hide the
complexities. You then use these classes in the logic.jsp.
The final approach discussed here is called the `Model 2' approach. This
approach requires a level of sophistication that is usually not
warranted unless you use a library that supports it, however it is the
cleanest way to implement an application.
In this approach there is a special Servlet called a controller
servlet. The controller maps an incoming request to a Java class that
takes care of all of the 'business logic'. This Java class returns a result
that indicates to the controller where it should go next. The controller then
dispatches to the appropriate place.
The flow of a request moves through these `business logic' pieces, finally
ending up at a `view'. The logic pieces are responsible for examing the
submitted information (such as parameters from forms), managing logical flow,
and preparing objects for the view. The objects for the view are stored
as attributes of the request (or sometimes, the session).
The view is responsible for preparing a response for the user using the
prepared objects now available as request or session objects. This is where
JSP is often used, it works very well as the view component of a Model 2
architecture.
The developer tells the controller what the flow for each request is
by specifying it an external (usually XML) file.
This approach is by far the cleanest approach to using Servlets and JSP. Most
applications of any significant complexity use a Model 2 architecture.
JSP inherits the Servlet security mechanism. Using the two fundamental
concepts of Principals and Roles, JSP provides
declarative and programmatic security.
In addition, there is builtin support for various HTTP methods of
login that establish a Principal and it's Roles based on a user login
and password.
A Principal is established in association with a Session. There is a
one to one correspondence between the two. Usually the Principal is a
user, a real live honest to goodness person sitting at a computer
somewhere and accessing the Web Application.
The Application may require that the User go through a login process,
a successful login will establish a Principal, which will have a
certain set of Roles.
Servlet 2.2 Specification states:
A role is an abstract logical grouping of users that is defined by the
Application Developer or Assembler. When the application is deployed,
these roles are mapped by a Deployer to security identities, such as
principals or groups, in the runtime environment.
Roles are similar to groups in Unix security. As an example, you
might have a "member" role for users who have a membership, and an
"admin" role for administrators.
Principals can have more than one role -- a user might be both a
"member" and an "admin".
Servlet 2.2 Specification states:
Declarative security refers to the means of expressing an
application's security structure, including roles, access control, and
authentication requirements in a form external to the application. The
deployment descriptor is the primary vehicle for declarative security
in web applications.
Basically what this means in real terms is that you can specify
certain paths in web.xml that require certain roles. For example, you
can say that to access any page in the "/accountsetup/" subdirectory,
the user must have a role of "admin".
Servlet 2.2 Specification states:
Programmatic security is used by security aware applications when
declarative security alone is not sufficient to express the security
model of the application.
Programmatic security lets you decide in some Java code what to do,
based on the role that a user has. For example, you might make a
certain button appear in the button bar only for an "admin" user.
| Method | Description
|
| request.getRemoteUser()
return the name of an authenticated user.
|
| request.isUserInRole(String role)
| return true if the current user is in a given security role.
|
| request.getUserPrincipal()
| return the associated with the
current user.
|
The resources in an Application are by default open to the public, and
do not require a login. As soon as the User attempts to access a
resource that has been declared to require a role in the web.xml,
Resin will insert in the process a login of some kind before
continuing on to the resource that was originally requested.
For example, if the "/members/*" area has been declared to require a
"member" role, as soon as the user tries to access anything in
"/members/" Resin will check to see if the user has logged in
yet. If the user has logged in, then the roles for the user are
checked to see if "member" is a role that user can take. If the user
has not logged in, Resin inserts a login procedure and then
checks the roles.
The Servlet Specification details numerous methods for getting user
identification and password information from the user.
The example below shows usage of "Form Based Authentication", which
allows you to specify a login page to be sent to the user when needed,
and an error page that will be displayed if the user login fails.
The login page should submit a form to the url
j_security_check with the parameters
j_username and
j_password set to appropriate values.
Resin recognizes the special url j_security_check and
authenticates the username and password.
The Servlet authentication associates a principal with a session. The principal will only last as long as the
Session; as soon as the Session is gone then the user will no longer be logged
in.
As a result, invalidation of the Session will also cause a logout:
session.invalidate();
You can also cause a logout without invalidating the whole Session. Other
objects in the session will remain available but the principal will be
null:
session.logout();
Once the user information is collected, the password must be verified
and the roles determined. Unfortunately, the Servlet specification
does not indicate a standard way for this to occur.
What that means is that every Container is likely to do this
differently, and you will have to refer to Container specific
documentation and examples.
Copyright (c) 1998-2009 Caucho Technology, Inc. All rights reserved. caucho® ,
resin® and
quercus®
are registered trademarks of Caucho Technology, Inc.
|
Copyright (c) 1998-2009 Caucho Technology, Inc. All rights reserved. caucho® ,
resin® and
quercus®
are registered trademarks of Caucho Technology, Inc.
|