|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The scope of each object can vary significantly. For example, the session object has a scope which exceeds that of a page, as it many span several client requests and pages. The application object can provide services to a group of JSP pages that together represent a Web application. JSP directivesDirectives are messages to the JSP container and are denoted by the “@”: <%@ directive {attr="value"}* %>
Directives do not send anything to the out stream, but they are important in setting up your JSP page’s attributes and dependencies with the JSP container. For example, the line: <%@ page language="java" %>
says that the scripting language being used within the JSP page is Java. In fact, the JSP specification only describes the semantics of scripts for the language attribute equal to “Java.” The intent of this directive is to build flexibility into the JSP technology. In the future, if you were to choose another language, say Python (a good scripting choice), then that language would have to support the Java Run-time Environment by exposing the Java technology object model to the scripting environment, especially the implicit variables defined above, JavaBeans properties, and public methods. The most important directive is the page directive. It defines a number of page dependent attributes and communicates these attributes to the JSP container. These attributes include: language, extends, import, session, buffer, autoFlush, isThreadSafe, info and errorPage. For example: <%@ page session=”true” import=”java.util.*” %>
This line first indicates that the page requires participation in an HTTP session. Since we have not set the language directive the JSP container defaults to using Java and the implicit script language variable named session is of type javax.servlet.http.HttpSession. If the directive had been false then the implicit variable session would be unavailable. If the session variable is not specified, then it defaults to “true.” The import attribute describes the types that are available to the scripting environment. This attribute is used just as it would be in the Java programming language, i.e., a comma-separated list of ordinary import expressions. This list is imported by the translated JSP page implementation and is available to the scripting environment. Again, this is currently only defined when the value of the language directive is “java.” JSP scripting elementsOnce the directives have been used to set up the scripting environment you can utilize the scripting language elements. JSP 1.1 has three scripting language elements—declarations, scriptlets, and expressions. A declaration will declare elements, a scriptlet is a statement fragment, and an expression is a complete language expression. In JSP each scripting element begins with a “<%”. The syntax for each is: <%! declaration %> <% scriptlet %> <%= expression %>
White space is optional after “<%!”, “<%”, “<%=”, and before “%>.” All these tags are based upon XML; you could even say that a JSP page can be mapped to a XML document. The XML equivalent syntax for the scripting elements above would be: <jsp:declaration> declaration </jsp:declaration> <jsp:scriptlet> scriptlet </jsp:scriptlet> <jsp:expression> expression </jsp:expression>
In addition, there are two types of comments: <%-- jsp comment --%> <!-- html comment -->
The first form allows you to add comments to JSP source pages that will not appear in any form in the HTML that is sent to the client. Of course, the second form of comment is not specific to JSPs—it’s just an ordinary HTML comment. What’s interesting is that you can insert JSP code inside an HTML comment and the comment will be produced in the resulting page, including the result from the JSP code. Declarations are used to declare variables and methods in the scripting language (currently Java only) used in a JSP page. The declaration must be a complete Java statement and cannot produce any output in the out stream. In the Hello.jsp example below, the declarations for the variables loadTime, loadDate and hitCount are all complete Java statements that declare and initialize new variables. //:! c15:jsp:Hello.jsp <%-- This JSP comment will not appear in the generated html --%> <%-- This is a JSP directive: --%> <%@ page import="java.util.*" %> <%-- These are declarations: --%> <%! long loadTime= System.currentTimeMillis(); Date loadDate = new Date(); int hitCount = 0; %> <html><body> <%-- The next several lines are the result of a JSP expression inserted in the generated html; the '=' indicates a JSP expression --%> <H1>This page was loaded at <%= loadDate %> </H1> <H1>Hello, world! It's <%= new Date() %></H1> <H2>Here's an object: <%= new Object() %></H2> <H2>This page has been up <%= (System.currentTimeMillis()-loadTime)/1000 %> seconds</H2> <H3>Page has been accessed <%= ++hitCount %> times since <%= loadDate %></H3> <%-- A "scriptlet" that writes to the server console and to the client page. Note that the ';' is required: --%> <% System.out.println("Goodbye"); out.println("Cheerio"); %> </body></html> ///:~
When you run this program you’ll see that the variables loadTime, loadDate and hitCount hold their values between hits to the page, so they are clearly fields and not local variables. At the end of the example is a scriptlet that writes “Goodbye” to the Web server console and “Cheerio” to the implicit JspWriter object out. Scriptlets can contain any code fragments that are valid Java statements. Scriptlets are executed at request-processing time. When all the scriptlet fragments in a given JSP are combined in the order they appear in the JSP page, they should yield a valid statement as defined by the Java programming language. Whether or not they produce any output into the out stream depends upon the code in the scriptlet. You should be aware that scriptlets can produce side effects by modifying the objects that are visible to them. JSP expressions can found intermingled with the HTML in the middle section of Hello.jsp. Expressions must be complete Java statements, which are evaluated, coerced to a String, and sent to out. If the result of the expression cannot be coerced to a String then a ClassCastException is thrown. Extracting fields and valuesThe following example is similar to one shown earlier in the servlet section. The first time you hit the page it detects that you have no fields and returns a page containing a form, using the same code as in the servlet example, but in JSP format. When you submit the form with the filled-in fields to the same JSP URL, it detects the fields and displays them. This is a nice technique because it allows you to have both the page containing the form for the user to fill out and the response code for that page in a single file, thus making it easier to create and maintain. //:! c15:jsp:DisplayFormData.jsp <%-- Fetching the data from an HTML form. --%> <%-- This JSP also generates the form. --%> <%@ page import="java.util.*" %> <html><body> <H1>DisplayFormData</H1><H3> <% Enumeration flds = request.getParameterNames(); if(!flds.hasMoreElements()) { // No fields %> <form method="POST" action="DisplayFormData.jsp"> <% for(int i = 0; i < 10; i++) { %> Field<%=i%>: <input type="text" size="20" name="Field<%=i%>" value="Value<%=i%>"><br> <% } %> <INPUT TYPE=submit name=submit value="Submit"></form> <%} else { while(flds.hasMoreElements()) { String field = (String)flds.nextElement(); String value = request.getParameter(field); %> <li><%= field %> = <%= value %></li> <% } } %> </H3></body></html> ///:~
The most interesting feature of this example is that it demonstrates how scriptlet code can be intermixed with HTML code, even to the point of generating HTML within a Java for loop. This is especially convenient for building any kind of form where repetitive HTML code would otherwise be required. JSP page attributes and scopeBy poking around in the HTML documentation for servlets and JSPs, you will find features that report information about the servlet or JSP that is currently running. The following example displays a few of these pieces of data. //:! c15:jsp:PageContext.jsp <%--Viewing the attributes in the pageContext--%> <%-- Note that you can include any amount of code inside the scriptlet tags --%> <%@ page import="java.util.*" %> <html><body> Servlet Name: <%= config.getServletName() %><br> Servlet container supports servlet version: <% out.print(application.getMajorVersion() + "." + application.getMinorVersion()); %><br> <% session.setAttribute("My dog", "Ralph"); for(int scope = 1; scope <= 4; scope++) { %> <H3>Scope: <%= scope %> </H3> <% Enumeration e = pageContext.getAttributeNamesInScope(scope); while(e.hasMoreElements()) { out.println("\t<li>" + e.nextElement() + "</li>"); } } %> </body></html> ///:~
This example also shows the use of both embedded HTML and writing to out in order to output to the resulting HTML page. The first piece of information produced is the name of the servlet, which will probably just be “JSP” but it depends on your implementation. You can also discover the current version of the servlet container by using the application object. Finally, after setting a session attribute, the “attribute names” in a particular scope are displayed. You don’t use the scopes very much in most JSP programming; they were just shown here to add interest to the example. There are four attribute scopes, as follows: The page scope (scope 1), the request scope (scope 2), the session scope (scope 3—here, the only element available in session scope is “My dog,” added right before the for loop), and the application scope (scope 4), based upon the ServletContext object. There is one ServletContext per “Web application” per Java Virtual Machine. (A “Web application” is a collection of servlets and content installed under a specific subset of the server’s URL namespace such as /catalog. This is generally set up using a configuration file.) At the application scope you will see objects that represent paths for the working directory and temporary directory. Manipulating sessions in JSPSessions were introduced in the prior section on servlets, and are also available within JSPs. The following example exercises the session object and allows you to manipulate the amount of time before the session becomes invalid. //:! c15:jsp:SessionObject.jsp <%--Getting and setting session object values--%> <html><body> <H1>Session id: <%= session.getId() %></H1> <H3><li>This session was created at <%= session.getCreationTime() %></li></H1> <H3><li>Old MaxInactiveInterval = <%= session.getMaxInactiveInterval() %></li> <% session.setMaxInactiveInterval(5); %> <li>New MaxInactiveInterval= <%= session.getMaxInactiveInterval() %></li> </H3> <H2>If the session object "My dog" is still around, this value will be non-null:<H2> <H3><li>Session value for "My dog" = <%= session.getAttribute("My dog") %></li></H3> <%-- Now add the session object "My dog" --%> <% session.setAttribute("My dog", new String("Ralph")); %> <H1>My dog's name is <%= session.getAttribute("My dog") %></H1> <%-- See if "My dog" wanders to another form --%> <FORM TYPE=POST ACTION=SessionObject2.jsp> <INPUT TYPE=submit name=submit Value="Invalidate"></FORM> <FORM TYPE=POST ACTION=SessionObject3.jsp> <INPUT TYPE=submit name=submit Value="Keep Around"></FORM> </body></html> ///:~
The session object is provided by default so it is available without any extra coding. The calls to getID( ), getCreationTime( ) and getMaxInactiveInterval( ) are used to display information about this session object. When you first bring up this session you will see a MaxInactiveInterval of, for example, 1800 seconds (30 minutes). This will depend on the way your JSP/servlet container is configured. The MaxInactiveInterval is shortened to 5 seconds to make things interesting. If you refresh the page before the 5 second interval expires, then you’ll see: Session value for "My dog" = Ralph
But if you wait longer than that, “Ralph” will become null. To see how the session information can be carried through to other pages, and also to see the effect of invalidating a session object versus just letting it expire, two other JSPs are created. The first one (reached by pressing the “invalidate” button in SessionObject.jsp) reads the session information and then explicitly invalidates that session: //:! c15:jsp:SessionObject2.jsp <%--The session object carries through--%> <html><body> <H1>Session id: <%= session.getId() %></H1> <H1>Session value for "My dog" <%= session.getValue("My dog") %></H1> <% session.invalidate(); %> </body></html> ///:~
To experiment with this, refresh SessionObject.jsp, then immediately click the “invalidate” button to bring you to SessionObject2.jsp. At this point you will still see “Ralph,” and right away (before the 5-second interval has expired), refresh SessionObject2.jsp to see that the session has been forcefully invalidated and “Ralph” has disappeared. If you go back to SessionObject.jsp, refresh the page so you have a new 5-second interval, then press the “Keep Around” button, it will take you to the following page, SessionObject3.jsp, which does NOT invalidate the session: //:! c15:jsp:SessionObject3.jsp <%--The session object carries through--%> <html><body> <H1>Session id: <%= session.getId() %></H1> <H1>Session value for "My dog" <%= session.getValue("My dog") %></H1> <FORM TYPE=POST ACTION=SessionObject.jsp> <INPUT TYPE=submit name=submit Value="Return"> </FORM> </body></html> ///:~
Because this page doesn’t invalidate the session, “Ralph” will hang around as long as you keep refreshing the page before the 5 second time interval expires. This is not unlike a “Tomagotchi” pet—as long as you play with “Ralph” he will stick around, otherwise he expires. Creating and modifying cookiesCookies were introduced in the prior section on servlets. Once again, the brevity of JSPs makes playing with cookies much simpler here than when using servlets. The following example shows this by fetching the cookies that come with the request, reading and modifying their maximum ages (expiration dates) and attaching a new cookie to the outgoing response: //:! c15:jsp:Cookies.jsp <%--This program has different behaviors under different browsers! --%> <html><body> <H1>Session id: <%= session.getId() %></H1> <% Cookie[] cookies = request.getCookies(); for(int i = 0; i < cookies.length; i++) { %> Cookie name: <%= cookies[i].getName() %> <br> value: <%= cookies[i].getValue() %><br> Old max age in seconds: <%= cookies[i].getMaxAge() %><br> <% cookies[i].setMaxAge(5); %> New max age in seconds: <%= cookies[i].getMaxAge() %><br> <% } %> <%! int count = 0; int dcount = 0; %> <% response.addCookie(new Cookie( "Bob" + count++, "Dog" + dcount++)); %> </body></html> ///:~
Since each browser stores cookies in its own way, you may see different behaviors with different browsers (not reassuring, but it might be some kind of bug that could be fixed by the time you read this). Also, you may experience different results if you shut down the browser and restart it, rather than just visiting a different page and then returning to Cookies.jsp. Note that using session objects seems to be more robust than directly using cookies. After displaying the session identifier, each cookie in the array of cookies that comes in with the request object is displayed, along with its maximum age. The maximum age is changed and displayed again to verify the new value, then a new cookie is added to the response. However, your browser may seem to ignore the maximum age; it’s worth playing with this program and modifying the maximum age value to see the behavior under different browsers. JSP summaryThis section has only been a brief coverage of JSPs, and yet even with what was covered here (along with the Java you’ve learned in the rest of the book, and your own knowledge of HTML) you can begin to write sophisticated web pages via JSPs. The JSP syntax isn’t meant to be particularly deep or complicated, so if you understand what was presented in this section you’re ready to be productive with JSPs. You can find further information in most current books on servlets, or at java.sun.com. It’s especially nice to have JSPs available, even if your goal is only to produce servlets. You’ll discover that if you have a question about the behavior of a servlet feature, it’s much easier and faster to write a JSP test program to answer that question than it is to write a servlet. Part of the benefit comes from having to write less code and being able to mix the display HTML in with the Java code, but the leverage becomes especially obvious when you see that the JSP Container handles all the recompilation and reloading of the JSP for you whenever the source is changed. As terrific as JSPs are, however, it’s worth keeping in mind that JSP creation requires a higher level of skill than just programming in Java or just creating Web pages. In addition, debugging a broken JSP page is not as easy as debugging a Java program, as (currently) the error messages are more obscure. This should change as development systems improve, but we may also see other technologies built on top of Java and the Web that are better adapted to the skills of the web site designer. Exercises12.Create a JSP page that prints a line of text using the <H1> tag. Set the color of this text randomly, using Java code embedded in the JSP page. If you do not have an existing JSP container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run JSPs. 13.Modify the maximum age value in Cookies.jsp and observe the behavior under two different browsers. Also note the difference between just re-visiting the page, and shutting down and restarting the browser. If you do not have an existing JSP container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run JSPs. 14.Create a JSP with a field that
allows the user to enter the session expiration time and and a second field
that holds data that is stored in the session. The submit button refreshes the
page and fetches the current expiration time and session data and puts them in
as default values of the aforementioned fields. If you do not have an existing
JSP container, you will need to download, install, and run Tomcat from
jakarta.apache.org in order to run JSPs. Custom Tags provide you with the full power of the Java language with almost seamless integration into your presentation layer[6]. A custom tag is a homemade JSP tag. In order to fully understand the implications of this, you first need to be clear about what a tag is. The chances are that you will have made good use of tags long before reading this chapter. Very few developers these days work in environments which are completely divorced from the Internet, and that means you have probably had at least some basic HTML or XML exposure. In a mark-up language, like HTML, or XML, the structure is embedded within the data. This allows the parser, e.g. a browser, to interpret instructions for displaying or storing the information. The main mechanism for this is the tag. At its most simple, a tag, like for instance, <b> just tells the reader (in this case, a web browser) to apply some formatting to the data. With this particular tag, it would be to display the data (which is plain text) in bold format. Every tag should have a start and end point i.e. in this case </b> which allows the parser of the mark-up language to identify a portion of content, by determining which of the data lies between the start and end tags. This allows some structure or format to be applied to that data. In this case any text between the start and end tags would be displayed in bold font. The other important mechanism for applying this structure to the data, is the attribute, making the tag slightly more complicated, like the “table” tag in HTML, for example. A table tag can have a border attribute e.g. <table border=”3”>, this attribute value, border, applies to the data which appears after the <table> tag and before the </table> tag. This data found in between the two tags is referred to as the body of the tag. All data in the body of this tag would be displayed in a table, and the border around each element in the table would be of width “3”. In the case of the table tag in HTML, it gets more complicated still, because the body of the tag can contain other tags as well as data, allowing nesting. Thus you can define a table row within a table, and table data (or columns) within a row. This allows for very good structuring of the data. e.g. <table border=”3”> <tr> <td>black</td> <td>white</td> </tr> </table>
This defines a table, with a border of size three, one row and two columns, containing data black and white. The words black and white are the data items which make up the body of the <td> or table data tag. The <tr> or table row tag with its embedded <td> tags and data make up the body of the table tag. You can clearly see that the relationship between these tags is important. The table row tag, <tr>, doesn’t have much meaning outside of a table tag, and similarly, the table data tag, <td>, has no meaning outside of the table row tag. We refer to the table tag as being the parent of the table row tag, and the table row tag as being a parent of the table data tag. XML introduces the notion of namespaces which allow you a little more flexibility again when naming tags. (see the XML chapter “” for more detail). If you want to create your own HTML-type mark up language, you could define a namespace called mytags and define your tag within it, thus having a tag <mytag:table> and </mytag:table>. Put simply, this would mean that there would be no confusion between the original HTML table tag and your own, newly defined one. Your table tag is in its own namespace. This means that you can use consistent naming conventions, e.g. call a “table” a “table”, rather than “myspecialtable”, without having to worry about it clashing with the HTML standard definition. Custom tags have all of the above properties. They have bodies that can either contain data, or might be empty and they have properties that can be applied to the body of the tag. They also use namespaces to allow consistent naming conventions. You will use some or all of these features, depending on what is appropriate for your application. What do custom tags give us?Power: As with JavaBeans, the real programming problems like querying databases or making complex calculations etc. can all be done in Java code with the full power of the Java libraries behind you. JSP custom tags also allow you to make objects available to a web page author via fragments of Java code, or “scriptlets”, so with careful design, you can make a lot of functionality available via a simple and neat interface. Consistency: Unlike JavaBeans, the presentation code is neatly separated from the business logic code, the need for scriptlets is reduced and more development is done using HTML type tags. It is therefore easier for a web page author to understand, and much easier to read and debug. Encapsulation: The business logic, is now defined in Java classes that can solve complex programming problems like network communication or database querying. This code can be unit tested in isolation, and finally presented as simple tags, ideal for a web author to use when getting on with building the web application. Reuse: Tags are stored in libraries which are perfect entities for re-use in web development. Tag libraries typically contain a collection of tags of similar or connected functionality. The library can easily be included by a web page author needing that functionality. A tag is even easier to use than your average Java method! At this point, if you remember the earlier discussions about using Java beans from JSP in the JSP chapter, you might be asking yourself why this is necessary. Javabeans in JSP also help us to separate the presentation layer from the business logic. Beans can be stored in libraries too, they are reusable, have a consistent interface and can even communicate with scriptlets, so why do we need tags? The answer is quite subtle. Beans are indispensable to the application developer and are very helpful if used in the right way. In fact, as we shall see, beans and custom tags complement each other very nicely. The difference, though, is that beans are components, and custom tags are essentially actions, or handlers. This needs to be understood well and carefully considered in your design if it is not to lead to the incorrect use of beans. Beans, like any other components, have properties, methods and internal state. What makes using beans with JSP so easy is that the interface between JSP pages and Java beans is designed specifically for getting and setting the bean properties. As long as you have named your bean methods according to the Javabeans convention, you can access these properties very simply via JSP. Let’s revisit Javabeans. Consider a person bean that has two properties, name and age. In order to access these via JSP tags, you would need to use the <jsp:usebean …> action, and the <jsp:getProperty name=”beanName” property=”requiredProperty”> action for each of these two values. Should you want to put these in the row of an HTML table, you would have to specify .. <table> <tr> <td><jsp:getProperty name=”personbean” property=”name”></td> <td><jsp:getProperty name=”personbean” property=”age”></td> </tr> </table> ..
This is good-looking, consistent HTML type code. It is very manageable at the moment, but will get more ugly and “bloated” as you use beans with more properties. You might have five beans, with five properties each, and instantly you would have twenty five lines to type. In a real application you are very unlikely to have as few as two properties, as we do in the example above. What is needed here is clearly some programming so we don’t have to do so much typing and create so much source code. One of the great strengths of using JavaBeans with JSP is also a limitiation. Because of the JSP getProperty and setProperty tags, it is very easy to get and set the bean properties. Remember, these are short cuts for using the set and get methods. But, if you are trying to call other methods on the bean, you have to do it directly and you are confined to using scriptlet code or expression code, using the <% %> tags. This starts to make the code look a little ugly and inconsistent. Consider the fragment. <ol> <% while (list.hasNextElement()) { list.nextElement(); %> <li><jsp:getProperty name=”list” property=”currentElement”></li> <% } %> </ol>
In the example above, notice that to iterate through a simple loop, and display items from a list (using an imagined list bean which iterates through its data) the first two lines of the Java scriptlet code have to be put in scriptlet brackets. The jsp:getProperty tag which allows the use of HTML type brackets gives consistent looking presentation code, but then the close brace of the while loop has to use the scriptlet brackets, <%}%> again. Two tags are now enclosing a single close bracket and as you can see, it is not very nice to look at. If you were trying to debug it, it might be very difficult to work out where one loop ends and the next starts. JSP debuggin tools are improving but still leave a lot to be desired. Add to this the fact that it is almost impossible to arrive at a consistent convention for indenting your brackets and you can see it is potentially messy. Some scriptlet code is inevitable, but too much is undesirable. As the complexity of the code increases, so the combination of HTML tags, JSP directives, actions and scriptlet code, each with its own bracket notation, further increases the complexity of the code, making it difficult to read and maintain. How can this be prevented? It is very tempting to write a bean that returns values that are already in tags. This would at first glance appear to remove a great deal of the HTML code and keep the documents shorter and simpler. Implemented like this, a bean could just return a string value from the get method that already has formatting tags in it and our data would display itself nicely on the screen. As attractive as this sounds, it turns out to be a very bad idea as you will see. Consider a bean which has a String method which returns a table row of data including the tags. It might look something like this.. public class PersonDataBean { private int age; private String name;
String getCurrentRow() { return “<tr><td>” + name + “</td><td>”+ age + “</td></tr>”; } }
The getCurrentRow() method now returns a string which displays a table row, and the HTML which displayed the person in a table, two examples above, becomes simply: .. <table> jsp:getProperty name=”personbean” property=”currentRow”> </table> ..
This might makes for shorter HTML coding but it is a poor design approach for a number of reasons. For one thing, it creates a very tight cohesion between the data and its presentation. That tends to cloud one’s ability to think of the bean as an object, and clutter one’s design. From a programming perspective, it is even worse. A programmer using this bean would get the results back in a table whether or not it was appropriate. The layout and the field order wouldn’t be changeable programmatically and although a stylesheet could be used, to change the style of the output, it would not be possible to do anything more specific, (like make one column appear in bold text, for example). This means that the web page author using the bean is now limited to presenting data in a format defined by the bean developer. The bean developer might be an excellent database developer, but might not be the person responsible for presenting the final layout. In fact, it is very likely that the layout requirements are not even known at the time of the bean’s development. The bean should have been written with reuse in mind, and no one designing a web page would appreciate having to work with a pre-determined layout. So, although this appears to solve the problem of increased code complexity, it in fact detracts enormously from the code’s re-usability. You will always come across these layout issues with dynamic web content. When developing web pages, you constantly need layouts or presentations that are dependent on certain program conditions (like variable length tables, different colors for values within certain ranges etc.) This is the dynamic behavior one would expect from a web page, but this behavior makes the code hard to read by requiring scriptlet programming with funny brackets embedded in the code. Scriptlet code obviously can’t be removed from JSP pages completely, and nor would you want that. In fact, writing scriptlets, with JavaBeans, (or any kind of scripting language with any kind of component) is an excellent way to build an application, as long as it is not abused. So far, we have highlighted two problems, the need to separate presentation code from business logic, and the need to prevent the kind of complexity that creeps into our presentation code when we mix HTML and scriptlet code. We can also see, that as useful as JavaBeans are, they are not always the solution to these problems and may lead to bad design. That is where the custom tag comes into play. A JSP tag can be thought of as an action, or a handler for a number of events. These events are actually triggered by the JSP container reading the JSP source and parsing each tag. The different methods that correspond to these events, are amongst others, doStartTag() and doEndTag(), the point at which they are called should be obvious from their names. There are of course more than just 2 methods you will need to create custom tags, but when writing our own tags we have various classes and interfaces we can use which provide us with more or less functionality depending on our needs. Let us have a look at a simple tag, a “Hello World” tag will do nicely. What would be ideal is a tag that would display Hello World. The tag should look something like this: <tijtags:helloworldtag/>
Note that its namespace is tijtags and its name is helloworldtag. Note also that there is a forward slash at the end of the tag name. This means that the tag is a start and end tag all in one. This makes use of the short hand notation defined in XML. It could also be written like this: <tijtags:helloworldtag> </tijtags:helloworldtag>
In either case, the tag clearly has no body, and as you might have guessed, needs the very minimum of programming to make it work. You will need to tell the JSP container how to find your Java classes, though, so in order to do this bare minimum the following tasks need to be performed: 1. Write a class that implements the Tag interface, found in the package javax.servlet.jsp.tagext.Tag 2. implement the methods “setPageContext(), doStartTag() and doEndTag()” 3. create a TLD file, or tag library descriptor for the tag. Let’s take care of the first 2 tasks: package cx2.tags; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.JspException; import java.io.IOException;
public class HelloWorldTag implements Tag { PageContext pageContext; public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; } public void setParent(Tag parent) {}
public Tag getParent() { return null; } public int doStartTag() throws JspException { try { pageContext.getOut().println("Hello World!"); } catch(IOException ioe) { ioe.printStackTrace(); } return Tag.SKIP_BODY; } public int doEndTag() throws JspException { return Tag.EVAL_PAGE; } public void release() {} }
You will notice that there is no constructor defined, which means that this class has a default, parameterless constructor. This is one of the prerequisites of writing a tag handler class. You will notice that a property called pageContext has been defined, which is of type PageContext, found in the javax.servlet.jsp package. This is initialized in the method setPageContext(). The container calls this automatically and passes through a reference to the PageContext when it first reads the tag. This reference has to be stored because it is needed later on. The JSP Tag Extension specification guarantees that the setPageContext() method will be always be called before the doStartTag() method. Next, the method doStartTag() is implemented. This method is where all of the work for this particular tag is done. Using the pageContext object, which has already been initialized, the JSP output stream is requested. This is the output stream that echoes back to the browser which is reading the JSP page, and its println() method is called, in exactly the same way it would be if you were using System.out. Notice that the doStartTag() method returns the value Tag.SKIP_BODY. This tells the container that it should ignore anything between the start and end tags. Since this tag does not even have a body this is all that is needed for now. The doEndTag() method is implemented simply by returning the value Tag.EVAL_PAGE. This tells the container to continue processing the JSP page as it was until it came across this tag. Again, with a tag this simple, that is all that is needed. There are some other methods of the Tag interface that must be implemented, but only the three mentioned above are important for now. All that is left to do now for the HelloWorld tag, is to describe to the container what your new tag is called and which class will be implementing it. To do this you need to write a tag library descriptor, an XML file which the container uses to gain information about the tag or tags you have defined. This file is saved with a .tld extension and is placed on your server with your JSP files. <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>htl</shortname> <uri>http://www.eckelobjects.com/tagtut/tags1.0</uri> <info> Library of tags on increasing complexity to demonstrate the use of tag libraries.</info> <tag> <name>helloworldtag</name> <tagclass>cx2.tags.HelloWorldTag</tagclass> <bodycontent>empty</bodycontent> <info> echo's hello world to the browser. </info> </tag> </taglib>
Don’t be intimidated by all of this. The tags in this file are less arcane than they seem. They will be presented in greater detail later on, for now, all you need to worry about is the tag tag. This tag, unsurprisingly, tells the container things it needs to know about the new tag that you have just created. There are four things that are important with this particular tag; its name, which class contains the tag implementation, what kind of its body content it should have and lastly, a little description of what the tag does. The description should be short and clear, the kind of thing you might expect to see on the toolbar of a GUI tool giving you the option to use this tag in your application. To use the new tag in a JSP page you would specify something like this: <%@ taglib uri="/tijtags.tld" prefix="tijtags"%> <b> <tijtags:helloworldtag/> </b>
That is all you need to do to send “Hello World” back to the browser! The first line is the JSP taglib directive. The uri attribute tells the container that your tag library descriptor can be found in a file called “tijtags.tld” in the current directory. The prefix attribute tells the container what namespace you are going to use to refer to your tags. The <b> tag is just for decoration and to emphasize the point that you can use HTML freely with JSP tags. This combination becomes very powerful when you are writing iterative tags. Using Tags and JavaBeansThe “hello world” tag was not a very powerful tag. It certainly didn’t save anyone any effort. In this case, it would have course been easier just to type the words “Hello World” into the text yourself. Let’s look at an example that does a little bit more in the way of programming, and at the same time illustrates how tags can make objects available to the JSP page. This time, the intention is to create a greeting tag that is slightly more useful than “hello world”, and therefore a little more general. Imagine a greeting tag, that when used would create a greeting object and make it available on the JSP page. If this object, a Javabean, had a greeting property that produced a random greeting, such as “Hi there!” or “Hello”, you might use it something like this.. <tijtags:greetingtag id="randomgreeting"/> <jsp:getProperty name="randomgreeting" property="greeting"/>
This is a little bit more involved than the last tag. Let’s look closely at the differences. Firstly, although this is another bodiless tag, it has an attribute, called id. The tag reference above passes the string “randomgreeting” through to the tag. Next there is a JSP action, getProperty which appears to be requesting the value of the property “greeting” from a Javabean called “randomgreeting”. It is no coincidence that the name of this bean is the same as the value of the “id” attribute, you might have guessed by now that it is the tag that has enabled the getProperty action to be used on a JavaBean by this name. Usually you would expect to see the JSP action <jsp:useBean... declared at the top of the JSP file before you could use the getProperty action to access a bean, but in this case it is the tag that has effectively defined the bean and made it accessible from the page. The tasks needed for this tag to work would be the following: 1. Create a Javabean with a property greeting, and a get method that returns a random greeting string, like “Hi there!” or “Hello”. 2. Write a class that implements the Tag interface. 3. Give the class a setId() method to allow the container to set the id attribute. 4. Create an instance of the greeting JavaBean and store it in the page context. 5. create a TLD or tag library descriptor file for the tag. There are a few more things to do this time, but this is still pretty straightforward. You already know how to write a JavaBean, but here is a minimal one that will be sufficient. package cx2.tags;
public class GreetingBean { String greetings[] = {"Hello!","Howdy!","Hi There!","How do you do?"}; public String getGreeting() { return greetings[(int)(Math.random()*greetings.length)]; } }
The idea is that the tag class will make an instance of this JavaBean available so that the JSP page author can use the getProperty action on his page. Here is the Tag class itself. package cx2.tags; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.JspException;
public class GreetingTag implements Tag { private String id; private PageContext pageContext; public GreetingTag() { } public void setId(String id) { this.id = id; } public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; } public void setParent(Tag parent) { } public Tag getParent() { return null; } public int doStartTag() throws JspException { pageContext.setAttribute(id, new GreetingBean(), PageContext.PAGE_SCOPE); return Tag.SKIP_BODY; } public int doEndTag() throws JspException { return Tag.EVAL_PAGE; } public void release() { } }
You will notice that there is a setId() method. This is not on the Tag interface, but the container will call this method anyway. It will be passed the value of the attribute id as it is specified in the JSP file. This highlights another interesting relationship between JavaBeans and tags. A tag which has attributes must have JavaBean style properties which obey the correct naming convention and must match the attribute names. These properties will be set automatically by the container, using the JavaBeans mechanism built into Java. Two additional rules not normally associated with JavaBeans, but which are important here, are that you may only have one setter method per attribute, and you should not call a setter method yourself, i.e. from anywhere else in the tag code. As before, most of the work for this tag is done in the doStartTag() method. It is worth paying slightly closer attention this time, to the fact that the doStartTag() and doEndTag() methods may each throw a JspException. This can be ignored for the time being, but if an exception occurs in your tag implementation, a JspException will be thrown which might end up being displayed on the client browser window, which is rarely desirable. A technique for handling this will be explained later. This time the doStartTag() method uses the setAttribute() method on the pageContext object to create an instance of the greeting bean, and store it in the pageContext, specifying its name and its scope. The name comes from the id attribute, and the scope is the familiar constant PAGE_SCOPE, a final property of the class PageContext. If that sounds complicated, think of it in two parts. The tag class has already been passed the name via the setId() method, and stored it in the variable id. Now it creates a GreetingBean object and adds it to the pageContext, giving it the name stored in the id variable. This is the programmatic equivalent of the JSP action: <jsp:useBean...>. The JavaBean is now available for use with the <jsp:getProperty..> action on the JSP page. All that is left to do now, is to create the TLD file. Since one exists already, all you need to do is add another tag tag before the final </taglib> .. <tag> <name>greetingtag</name> <tagclass>cx2.tags.GreetingTag</tagclass> <bodycontent>empty</bodycontent> <info> Adds a HelloWorld Bean to the page context. </info> <attribute> <name>id</name> <required>true</required> </attribute> </tag> ..
Notice that in this tag tag there is a subtag, called attribute. The name subtag of attribute tells the container what that attribute is called, and the required subtag tells the container whether that attribute is mandatory or not. Mandatory subtags must be specified, i.e in this case, <tijtags:greetingtag id="randomgreeting"/>
otherwise the container will throw an exception when an attempt is made to load the JSP page. In order for your tag to properly declare and initialize an attribute, the name of that attribute, the name in the tag library descriptor file and the name of the JavaBean property (and setter methods) must all be the same. To use the random greeting tag, and the bean object it creates, you would need to specify the tag: <tijtags:greetingtag id="randomgreeting"/>
which would create a JavaBean in the page context for you to use. Then you would need to get the property from the bean: <jsp:getProperty name="randomgreeting" property="greeting"/>
which would echo the greeting back to the browser. This latter line can then be used as often as you like on the JSP page after the declaration above it. Each time it appears, it will produce a different greeting. Refreshing the page in your browser will also produce new random greetings, because every time the container processes the getProperty action, it will make a call to the method getGreeting() on the GreetingBean class, which will return a new, random greeting. (Note that that the use of a get method on a JavaBean that returns a random value might offend some purists. It is used here as a good demonstration of working with beans.) Tags that manipulate their body contentUp until now, the two tags that we have looked at ignore their body content, or to be more accurate, they are defined as not having any body content at all. This kind of tag is very simple, and fairly limited in its usefulness, although, as you can imagine, making a bean available to the page author can be pretty useful. Tags which manipulate their body content are generally much more powerful, if slightly harder to program. Let’s look at a tag that actually interacts with its body content. This time, suppose you wanted to generate a tag that gives you a nice looking drop capital for your text. For example.. It was a dark and stormy night... This can be done in HTML in a somewhat primitive fashion, by using heading text and tables, which serves our purposes, but rather than write out a table every time you want a drop capital, why not create a tag to do it for you? Ideally it should be possible to do something like the following: <tijtags:dropcapitaltag color = "black">
it was a dark and stormy night, the rain fell in torrents -- except at occasional intervals, when it was checked.... </tijtags:dropcapitaltag>
The color attribute would be a nice thing to have so that a giant capital could be displayed in the specified color. To create this tag,. the important tasks you would need to perform would be the following: Write a class that implements the Tag interface. Give the class a setColor() method to allow the container to set the color attribute. Write the code that reads in the body content and inserts the relevant HTML tags so that the first letter is displayed as a drop capital. Create a tag library descriptor file for the tag. Lets have a look at the code for this tag: package cx2.tags; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.TryCatchFinally; import javax.servlet.jsp.JspException; import java.util.StringTokenizer; public class DropCapitalTag extends BodyTagSupport implements TryCatchFinally { String color = "black";
public void setColor(String color) { this.color = color; }
public int doAfterBody() throws JspException { int period; StringBuffer result = new StringBuffer(); String body = bodyContent.getString().trim(); result.append("<table><tr><td><h1><font color=\""+color+"\">"); result.append(Character.toUpperCase(body.charAt(0))); result.append("</font></h1></td><td>"); period = body.indexOf('.'); result.append (body.substring(1, period+1)); result.append ("</td></tr></table>"); result.append (body.substring(period +1, body.length())); try { if (result.length() > 0) { bodyContent.clearBody(); bodyContent.println(result.toString()); } bodyContent.writeOut(bodyContent.getEnclosingWriter()); } catch(Exception e) { e.printStackTrace(); } return SKIP_BODY; } public void doCatch(Throwable t) { System.out.println( "An error occurred with the message" + t.getMessage()); } public void doFinally() {} public void release() { color = "black"; } }
The first thing you will notice is that unlike the previous tags, this one does not implement the Tag interface. This is because when you need to manipulate your body content, it is more useful to extend the BodyTagSupport class, which takes care of storing the pageContext object and providing default implementations of the doStartTag() and doEndTag() methods. This class implements the Tag interface so you don’t have to. The doAfterBody() method of this tag is where everything happens. You will see that this class references a handle called bodyContent. This is a reference to the BodyContent object, which is found in the javax.servlet.jsp.tagext package. This is provided by the container via a setBodyContent() method and is something else we get for free when we extend the BodyTagSupport class. This container will always provide this object before it calls the doInitBody() method, so you are always guaranteed that you have a valid BodyContent object in your doInitBody(), doAfterBody(), doStartTag and doEndTag() methods. The BodyContent object is an encapsulation of the body content of this particular tag, it contains all of the text from the JSP page that is in between the start and end tag. It is a quite a lot like an output stream, but with some extra functionality. This object gives you access to the JSP text. This is what the drop capital tag does, and is what you will need to do if you are going to manipulate the body content. You can get the entire body as a string, via a call to the getString() or as a stream, using the getReader() method if that is more appropriate for your needs. In this example a simple algorithm is used to trim off any white space that comes from the JSP source, capitalize the first letter, and add a few HTML tags, to format it into a drop capital effect. After the HTML tags have been added (using a StringBuffer object to append strings) there is one new, long string which needs to replace the old body text. To do this, the method clearBody() on the BodyContent is called first. If you don’t do this, the body content will appear twice on the browser. Next we use the println() method to add our new string to the BodyContent, and finally, the writeOut() method is called. This method tells the BodyContent object to direct its output back to the browser, but you will notice that the method takes a JspWriter as a parameter, and in this case the writer is obtained by a call to getEnclosingWriter(). You have to do this, because the body content object only includes the body of your particular tag and you need access to the output stream that directs output back to the client’s browser. If you look closely, you will see that the release() method does nothing. This method will be called by the container to release its state, so it is best used to tidy up any resources that you might have used in the tag. Be aware that there might be multiple calls to doStartTag() and doEndTag() in between each call to release, so this is not the method to use if you want to perform an operation each time the tag processing has completed. If you want to do that, you are better off using the doFinally(), described in the next paragraph. You might have noticed that this class implements the TryCatchFinally interface, which is in the javax.servlet.jsp.tagext package. When the container sees that your tag implements this interface, it knows to put a try/catch block around your tag handler, and passes the processing on to you if an exception occurs. This means that you have the ultimate control over the exception handling code, and if you wish, you can prevent weird exceptions being displayed on the browser window. The methods on the TryCatchFinally interface are doCatch() and doFinally() and they correspond to the catch and finally keywords in Java. The doCatch() method is called if there is an exception with the exception passed as a parameter, and the doFinally() is always called, regardless of what happens in the other tag handler methods. In this example, if there is an exception, the message is just displayed on the console on the server, not the client browser. This is a slightly lazy design approach used to demonstrate the interface. The algorithm used here is not very robust so an exception could easily occur. In the doFinally() method above, the color is set to black so that that is always the default value. Use this interface with caution. Its chief purpose is to give you more control when handling resources, like open streams etc. Remember that exceptions are all about recovery and it might be more appropriate to handle exceptions in your doAfterBody(), or doInitBody() methods and produce some meaningful output to display on the client’s browser, for example an error page which asks the user to re-enter some details. You might just want to forward the browser to a generic error page if that is more appropriate. Now that you have seen how the class is implemented, lets look at the tag entry in the tag library descriptor file. It looks like this: .. <tag> <name>dropcapitaltag</name> <tagclass>cx2.tags.DropCapitalTag</tagclass> <bodycontent>JSP</bodycontent> <info> Transforms text to have a drop capital. </info> <attribute> <name>color</name> <required>false</required> </attribute> </tag> ..
Notice that the color attribute is not required. As you can see in the source code, the tag will default to black if no color is specified, so it is not enforced here. That is all you need to do to manipulate the body of a tag! Tags that iterateOne of the most powerful features of custom tags in JSP is that they can iterate like a for loop or while loop in Java and produce dynamic output this way. Lets look at a more complicated tag that actually iterates over its body content, producing variable output depending on its attributes. Imagine you wanted to generate a list of prime numbers (numbers divisible only by themselves and 1) and display them in an HTML unordered list. What you would really like is a tag that would generate all of the prime numbers within a specified range, and allow you to access each value and put it in your preferred list format. Since you don’t know how many numbers there will be within the given range, and there could be quite a few, you don’t want to have to type out the HTML list item tags, <li> and </li>, for each one. Assuming that your tag is called primetag, you would want your JSP file to look something like this: <ul> <tijtags:primetag start = "1" end= "25"> <li><%=value%></li> </tijtags:primetag> </ul>
Notice that there is a start and end <ul> HTML tag round the entire block. **(An HTML lesson is beyond the scope of this chapter, but briefly, this defines an unordered list and within the body of this tag, any data found between a <li> and </li> pair, will be displayed as a bulleted list item.) Next you will notice the now familiar tijtags namespace reference, specifying the new custom tag, primetag, with two attributes, start and end. In this tag, unlike the two previous tags, not only is an end tag specified separately, </tijtags…, but there is also some body content between the start and end tags. That is what makes this tag so interesting. The <li> tags are just HTML as explained above, but in between them, enclosed in JSP scriptlet brackets, is a reference to the variable value. There are two very powerful properties of this custom tag. Firstly it has made the variable value available to us for use in a scriptlet, or simple JSP expression, like <%= value%>. Secondly, everything within the body of our custom tag is repeatedly processed and added to the output stream to be presented back to the browser. This means that not only will the tag above keep looping until it has found every prime number within the specified range, but it will display the <li> and </li> tags as well as the value of the variable for each number! In other words, the JSP code above will be all you need to do to display the prime number values in a neat list. And you don’t even need to know how many numbers there are going to be. This has suddenly become very useful. It is a tag that helps reduce the need to embed scriptlet code in our neat tags, but gives us full programming functionality, like looping. In order to implement such a tag you need to perform the following tasks: Create (or locate) a class with the appropriate logic for generating prime numbers. Write a tag class which implements the relevant tag interface. Write setter methods for the start and end properties. Program a looping mechanism to process the body content and for each iteration, make a variable available to the JSP page with the current prime number value. Create a TLD or tag library descriptor file for the tag. You can find the PrimeUtilities class on the CD (??)or in appendix (??). This example makes use of the sievePrimes() method, which finds prime numbers. There are many resources on the Internet for finding such algorithms if you are interested in this type of thing. Let’s look at the actual tag class. package cx2.tags; import java.util.ArrayList; import java.util.Iterator; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import com.bruceeckel.PrimeUtilities;
public class PrimeNumTag extends BodyTagSupport { private int start = 0; private int end = 0; ArrayList primeList; Iterator primeIterator; public void setStart(int start) { this.start = start; } public void setEnd(int end) { this.end = end; } public int doStartTag() throws JspException {
try { primeList = PrimeUtilities.sievePrimes(start, end); primeIterator = primeList.iterator(); } catch (Exception e) { e.printStackTrace(); return SKIP_BODY; } return EVAL_BODY_BUFFERED; } public void doInitBody() throws JspException { try { if (primeIterator.hasNext()) { pageContext.setAttribute("value", primeIterator.next()); } } catch (Exception e) { e.printStackTrace(); } } public int doAfterBody() { try { if (primeIterator.hasNext()) { pageContext.setAttribute("value", primeIterator.next()); return EVAL_BODY_BUFFERED; } else { bodyContent.writeOut(bodyContent.getEnclosingWriter()); return SKIP_BODY; } } catch (Exception e) { e.printStackTrace(); return SKIP_BODY; } } public void release() { primeList = null; start = 0; }
The first thing you will notice is that this tag class doesn’t implement the Tag interface directly any more. This is because the tag has a little more functionality now and it is more useful to extend the BodyTagSupport class. This class implements the Tag interface and provides some extra functionality. The various Tag classes and interfaces will be discussed in greater detail later. This class again makes use of the the PageContext object, supplied by the container using the setPageContext() method. Since this tag class inherits from BodyTagSupport, it is no longer necessary to store the pageContext object yourself. That will be taken care of by the parent class. This is a good example of reuse using inheritance. The doStartTag() method has now become the first method you need worry about. In the implementation above, the PrimeUtilities class is used to obtain and store an Iterator object which contains the prime numbers. Note that unless an exception occurs, this method will return the value EVAL_BODY_BUFFERED, unlike the two previous examples which returned SKIP_BODY in all cases. As you might have guessed, this is the key to implementing a tag which processes its body content. Next you will notice that the method doInitBody(), has been implemented. This method is called by the JSP container before the body of your tag has been processed, and is the method in which you will perform any initialization code required before processing the body content. In the previous example, this wasn’t necessary, as there wasn’t really anything to do. In the example above, however, this method queries the prime number iterator to make sure there are prime numbers available in the list, and if there are, the method setAttribute()is used to add the first available prime number value to the page context. As you can see, the value is associated with the name value. You came across a similar form of the setAttribute() earlier, but this time you will notice it has only two parameters that is because this class makes use of the default scope which is PAGE_SCOPE. The job of making this object available to the JSP page is actually in part the responsibility of a special class called a TagExtraInfo class which will be discussed a bit later on. The looping construct is now initialized and provided no exceptions have occurred, the tag will read in the body text at this point. The method doAfterBody()is not dissimilar to the doInitBody() method. It checks to see whether there are any more prime numbers in the iterator, and if there are, it adds the available prime number value to the page context. If there are no more prime numbers available, it writes the body content of the tag to the output stream that echoes it back to the browser. If you look closely you will see that this is not quite straightforward. The object referenced by bodyContent is in fact an instance of the BodyContent object, found in the javax.servlet.jsp.tagext package. This is an encapsulation of the body content of this particular tag, and is a bit like an output stream, but with some extra functionality. If the PrimeNumTag object had not extended the BodyTagSupport class, then a setBodyContent() method would have had to be implemented and the bodyContent object stored “manually” in the same way that we did with the pageContext object in the previous examples. Because the body content object only includes the body of your particular tag, you will need to make a call to the getEnclosingWriter() method in order to get to the right output stream. What actually causes the loop to iterate is the return value. If the doAfterBody() method returns the constant EVAL_BODY_BUFFERED, then the container will process the body of the tag and call that method again. If the method returns SKIP_BODY, then the loop will terminate, and provided you have sent your body content to the enclosing writer stream, your values will be displayed on the browser screen. All that is necessary now, is to create the tag entry in the TLD file. <tag> <name>primetag</name> <tagclass>cx2.tags.PrimeNumTag</tagclass> <bodycontent>JSP</bodycontent> <info> Generates Prime Number sequences </info> <attribute> <name>start</name> <required>false</required> </attribute> <attribute> <name>end</name> <required>true</required> </attribute> <variable> <name-given>value</name-given> <variable-class>Integer</variable-class> <declare>true</declare> <scope>AT_BEGIN</scope> </variable> </tag>
If you look at the attribute tag, you will see that the attribute start is not required, but the attribute end is. This was just a case of design choice for the class. It makes sense to default to 0 if no start point is specified, but since there are (apparently) an infinite number of prime numbers, it is a good idea to enforce an end point. You will remember that if the JSP page author does not conform to this constraint when writing the JSP page, and supply at least an end value, the container will throw an exception back to the web browser. After the attribute tag, there is a new tag that you are unfamiliar with, which is the <variable> tag, with its sub-tags <name-given>, <variable-class> and <declare>. These, as you might expect, tell the JSP container about the variable which is going to be added to the page context by your tag. Since this variable is an object which is not a JavaBean, there is no automatic mechanism for telling the container what type it is, so you need to do it with this tag. The meaning of these tags is listed at the end of this chapter, but let’s look at some of them now. The <name-given> tag tells the container what name to give the variable that it uses. You could use another tag, <name-from-attribute> in its place, which would allow you to specify the name of an attribute whose translation time value will contain the name of your variable. This way you could make the name dependent on some other translation time value. The <variable-class> tag tells the container what type to make the variable, and the class name specified must be in the classpath at translation time, which is when your JSP file is compiled for the first time on the server. Mostly you will use the standard types found in java.lang anyway. The <declare> tag tells the container whether or not this variable is declared. This appears to be intended for future JSP development. For now you will always want it to be declared which is the default value. The <scope> value tells the container at what point your scripting variable should be available to the JSP author. Possible values are NESTED, which makes the variable available only between the start and end tag in the JSP page, AT_BEGIN which makes it available between the start tag and the end of the page, or AT_END which makes it available after the end tag until the end of the page. At time of writing, there seems to be a problem with the current implementation of Tomcat (4.0.4 ) reading the <attribute> tag. For this reason you might have to use the more advanced and powerful technique of the TagExtraInfo class. This will entail replacing the entire <variable> tag, with a tag called <teiclass> or tag extra info class tag. The details of this are explained later in this chapter. Tags within TagsTags can also be nested within other tags which gives us a powerful structuring facility and also the ability to create conditional output, by having child tags which are only evaluated if certain conditions apply within their parent tag. The JSTL, Java Standard Tag Libraries, make full use of this, but let’s have a look at the highlights of how we might create such a tag ourselves. Now that you are getting more comfortable with the tag extension API in JSP we only need look the highlights of the next tag. Imagine that you are using the prime number generation tag and you want to check each prime number in turn to see if it is a “Fermat” prime number, and display that to the browser. A Fermat number is a number which can be expressed as “2 to the power 2 to the power n plus 1”, where n is an integer. If your eyes glaze over at mathematical descriptions, don’t worry. Suffice it to say that some prime numbers are Fermat prime numbers, and some aren’t. In fact, the numbers 3, 5, 17, 257, 65537 are the only Fermat prime numbers known. Since the Fermat prime checker tag is going to have the job of checking each number generated by the prime number tag, it obviously doesn’t make any sense for a fermatprimetag to exist outside of a primenumtag. That means it needs to be defined as a child tag which will prevent users of the tag library containing this tag incorrectly and means that you can make certain assumptions. These will be illustrated in the code. Here is the tag class: public class FermatPrimeTag extends BodyTagSupport { public int doStartTag() throws JspException { PrimeNumTag parentTag =(PrimeNumTag)findAncestorWithClass(this, PrimeNumTag.class); if (parentTag == null) { throw new JspException("Tag should be nested in \"primenumtag\" Tag"); } return EVAL_BODY_TAG; }
public int doAfterBody() throws JspException {
Integer prime =(Integer)pageContext.getAttribute("value"); String s = bodyContent.getString(); try { if (PrimeUtilities.isFermatPrime(prime.intValue())) { bodyContent.clearBody(); bodyContent.println(s + " (is a Fermat Prime Number) "); } bodyContent.writeOut(bodyContent.getEnclosingWriter()); } catch(IOException ioe) { throw new JspException(ioe.getMessage()); } return SKIP_BODY; } }
Notice the findAncestorWithClass() method. This traverses the hierarchy of tags, finding the parents recursively, until one is found which matches the class you are looking for. The way this method works is by calling the getParent() method recursively. This is another bit of tag management that we inherit from the BodyTagSupport class. If you don’t inherit from this class, you will need to implement the setParent() and getParent() methods yourself. The former is called by the container and will pass you a reference to the parent tag. You would have to store this in a handle for retrieval by the getParent() method. There might be cases where it is necessary to do all of this by yourself, but they will probably be pretty few and far between. By now you should be convinced of the wisdom of creating your own tags via inheritance from BodyTagSupport. If the findAncestorWithClass() method does not find a parent tag of the correct type, it will throw an exception that will appear on the client’s browser window. This will tell the user of the JSP library that they have used the tag incorrectly. The other important thing to notice with this tag is that it is calling the getAttribute() method on the pageContext object to get the value of an attribute called value. This is the attribute that is added to the page context by the parent tag, primenumtag. We have access to this because our child tag, fermatprimetag and our parent tag primenumtag are on the same page, and therefore share the same pageContext object. Remember though, that you still need to clear the body content and get the enclosing writer. What you are actually doing here is replacing the existing prime number with a string displaying the prime number and a message saying “.. is a Fermat Prime Number.” This tag is much simpler than its parent because it doesn’t need to define any of the looping mechanism. This tag will be treated as a brand new tag each time the parent tag iterates, so the doAfterBody() and other methods will be called repetitively. The Tag ClassesKnowing whether it is better to use an interface or a class to implement your tag handler can be tricky. It might help to look at a diagram of the classes and interfaces you have at your disposal. The following table describes some of the useful interfaces in the tag handler API:
This table describes some of the useful classes in the tag handler API:
Once you have chosen the appropriate class with which to implement your tag handler, you will need to work with the companion classes in the API. This table describes the two companion classes most often needed by tag handlers.
Some Advanced Tag Features Using TagExtraInfo classesSometimes, the variables that you want to make available from your tag for the JSP page author are a little bit too complicated to define in a static TLD file. The names of the variables might be dependent on some set of conditions, or you might want to validate the JSP page. For instance, you might want to make sure that the JSP author hasn’t specified incorrect attributes or nested a child tag in the wrong parent tag. For this kind of functionality, the <variable> tag in the tag library descriptor file is no longer adequate. In the primenumbertag above, instead of having a <variable> tag, we could have had the following: <teiclass>cx2.tags.PrimeNumTagExtraInfo</teiclass>
This tag tells the container that you have an entirely separate class to describe your attributes for you. Actually this isn’t as bad as it sounds, the class you need is very simple and you generally don’t need to override more than one method. In the case of the PrimeNumTag class, you would have named the class called PrimeNumTagExtraInfo, to follow the convention, and implement it like this: package cx2.tags; import javax.servlet.jsp.tagext.TagExtraInfo; import javax.servlet.jsp.tagext.TagData; import javax.servlet.jsp.tagext.VariableInfo;
public class PrimeNumTagExtraInfo extends TagExtraInfo { public VariableInfo[] getVariableInfo(TagData data) { VariableInfo[] vi = new VariableInfo[1]; vi[0] = new VariableInfo("value", "Integer", true, VariableInfo.AT_BEGIN); return vi; } }
Notice that the class extends the class TagExtraInfo, found in the javax.servlet.jsp.tagext package. The getVariableInfo() method creates an array of VariableInfo objects describing the name, type, whether or not it should be declared, and its scope. These correspond with the similarly named elements of the <variable> tag. The array of VariableInfo objects is only of size 1 because there is only one variable. The TagData object is used as a parameter to the getVariableInfo() method, but this has been designed with future development in mind. Some of the functionality it is intended to support is not yet available in JSP. Tag Library Descriptors RevisitedIf you have another look at the tag library descriptor we used for the tags above, you will find that you are familiar with the first two lines after reading the chapter on XML in this book, The <taglib> tag is self explanatory, defining the start and end of the tag library. Typically you would have one of these per TLD descriptor. It can have several sub elements: tlibversion - defines a version number which can help the programmer apply some validation at translation time by making it possible to read the version no. jspversion - defines a version number which helps the container determine which version of JSP is being used, so that if necessary it can turn off more advanced features or perform any special operations that need to be performed for backward compatibility. shortname - defines an easy-to-use name which a GUI based builder tool might use as the preferred prefix to any generated tags or directives.. uri - defines a unique identifier for the tag library. Typically it is useful to define it in the form of an HTTP URL like the one in the example in this chapter, but it doesn’t have to resolve to a web page, as long as it is unique. displayname – defines a human readable name that would be useful to display on the toolbar of of a GUI based authoring tool. small-icon - defines an optional image file, suitable for a builder tool to display on a tool bar. large-icon - defines an optional image file, suitable for a builder tool to display on a menu panel. description - defines a description of the tag library which a GUI based build tool might use to describe this library on a tool bar or menu. validator - defines an optional class that can be used to validate the tag by checking through its parameters and even other tags on the same JSP page, to make sure that the JSP author has used it correctly. listener - defines an optional class that implements a listener class for the servlet created from the JSP page. The class must implement one of the servlet listener interfaces, e.g. javax.servlet.http.HttpSessionListener. A <taglib> tag must have at least one <tag> subelement defined. This makes sense, you wouldn’t want to have a tag library with no tags. It wouldn’t be very useful. The tag element itself has several subelements, some of which you have already come across earlier in this chapter: name - defines a unique name for this tag, or action. tagclass - defines the fully qualified name of the class which implements the tag handler interface javax.servlet.jsp.tagext.Tag. teiclass – defines an optional extra info class, which contains information for validation of the variables for this tag. Must implement the interface javax.servlet.jsp.tagext.TagExtraInfo. bodycontent – The type of content to be found in the body of the tag, valid values are empty, JSP and tagdependant. If tagdependant is specified, then content will be passed uninterpreted to the tag handler. This would be useful for embedding other languages, e.g. SQL queries. displayname – A short, human-readable name that can be displayed by a GUI based authoring tool. small-icon - defines an image file, suitable for a builder tool to display on a tool bar. large-icon - defines an image file, suitable for a builder tool to display on a menu panel. description - defines more, optional tag specific information about the tag and how it may be used by other tags. It does this by providing a class which can apply constraints. The class must be a sub-class of the one that implements the tag. example - defines an optional example of how to use the tag, suitable for a builder tool to display on a help menu. The last two subelements of the <tag> tag, have subelements themselves. variable – defines information for a scripting variable defined on this tag. Can be substituted by using the teiclass tag, and providing a tag extra info class. The subelements of variable are: name-given – defines the variable name as a constant name-from-attribute – defines the name of an attribute which will give the name of the variable at translation time. variable-class – defines the type of the variable. The default is java.lang.String. declare – whether the variable is declared or not. True is the default. scope – the scope of the variable. NESTED, AT_BEGIN, or AT_END. attribute - defines information for an attribute used by this custom tag. The subelements of attribute are: name – defines the attribute’s name. required – defines whether or not the attribute is optional. rtexprevalue – defines whether or not the attribute may be passed as an expression which can be calculated at run time. type – defines the type of the attributes. String is default and the most useful. description – an optional description of the attribute. Deploying Tag LibrariesDeploying tag libraries takes a fair bit of administration but like any administrative task, the more you understand requirements of each application, the easier it becomes. In the case of tags, there is more than one way to deploy a tag library and you will ultimately have to make the decision as to which is the most appropriate for your application. This would apply whether you were deploying your own tag libraries or ones you were using from a third party vendor. You have already seen that a tag library descriptor file needs to be created for each tag library, and obviously you want to put that somewhere where the server can find it. You also need to put the Java classes somewhere that the container can find them. One easy way to do this is as follows: Put your type library descriptor file, or .tld file on the server in the WEB-INF directory, under your web application directory. e.g. ../webroot/tijtags/WEB-INF, using the path character most suitable for your operating system. Specify the location of the .tld file in your JSP page using the taglib directive, e.g. <%@ taglib uri="/WEB-INF/tijtags.tld" prefix="tijtags" %>. The uri attribute here indicates the relative path of the tag library descriptor file. Put your JSP files where you normally would, say in the jsp directory. Place your classes in the classes directory of your WEB-INF directory, e.g. ../webroot/tijtags/WEB-INF/classes/ making sure that you use subdirectories for the package names, as you would for any other Java application. That is all you need to do. When you restart your server, and access the JSP page, e.g., by typing http://localhost/tijtags/index.jsp, assuming you are running your server locally, the page will be able to access the tag library descriptor and classes. This is all right for testing, but it is much more typical to keep your classes in a jar file and put the jar file in the /WEB-INF/lib directory. If your tag library descriptor file is in the jar file with the handler classes, then the container will be able to locate it, and will resolve the tags at translation time and runtime. If you are deploying your tag libraries in a release scenario, or if you are using a third party tag library, you will want to have a more consistent directory structure and you might want to keep all of your tag libraries in one place. This would allow you to share tag libraries across different web applications. To do this, you can use a second approach, which is to make use of the <taglib> element of the web.xml file associated with your web application by adding the following lines: <taglib>
This creates a mapping between the URI and the location of the tag library descriptor file. Once this mapping exists, your JSP page can reference the tag library by its URI, rather than via its Tag Library Descriptor file: <%@ taglib uri="http://www.eckelobjects.com/tagtut/tags1.0" prefix="tijtags" %>
This allows a web administrator to move tag libraries around on the server, should that be necessary, without the web applications being affected. As long as the server has created that mapping, any web application will be able to make a reference to the tag library via the URI. This makes more sense when deploying third party tag libraries which need to be in a shared directory where they can be accessed by all web applications. Remember that the URI doesn’t actually need to be in the form of an HTTP URL as above, but this is quite a good convention which guarantees its uniqueness. You will notice in the example above that the mapping specified in the web.xml file is between a .tld file and a URI. If your tag library classes are in a jar file, then this means having a tag library descriptor which is outside the jar file. This could be a nuisance, so the tag container specification defines an automatic mapping directly to a jar file which contains a tag library descriptor. To make use of this, you need to ensure that your tag library descriptor is in a file called taglib.tld and that it appears in the tag library jar file under the directory META-INF. If that is the case, then you can define the mapping in your web.xml as follows: <taglib> http://www.eckelobjects.com/tagtut/tags1.0 </taglib-uri>
Notice that the jar file is specified as the location of the tag library. This is probably the best way to deploy tag libraries, it allows you to share libraries between applications, refer to the tag library by a unique URI, and keep the tag library descriptor file neatly packaged with the classes. Actually the specification of how a JSP container should handle mappings to tag libraries is pretty flexible. The container will try and build an implicit mapping if it can find your tag library descriptor and there is no explicit mapping in your web.xml file. It is not recommended that you leave too much to the container, though. The more you do that, the more you run the risk of losing portability, when, say, moving your application to another application server, you are also more subject to experiencing different behavior on different platforms. Using Third Party Tag LibrariesNow that you understand how to create and deploy tag libraries, you might be happy to discover that you don’t have to create your own. As with any other type of library development, there will always be times when you are forced to write your own code, but there are large and very powerful libraries already available for you to use, and you should always make sure that you are not reinventing the wheel when you embark on new development. The JCP, (Java Community Process) have, at time of writing, just published the first public draft of the JSP Standard Tag Library, JSTL, which defines a large number of powerful, multi-purpose tags. These provide standardized solutions for some of the most common problems one faces as a developer and will be discussed shortly. The Apache Jakarta group have another large collection of very useful tags freely available to developers these are grouped under the project name “taglibs” and serve the same purpose as the JSTL. Although there is some common functionality across the two libraries, this group have a close working relationship with the JCP and consistently been producing excellent open source Java products for some years now. The Jakarta projects are always worthwhile keeping an eye on. Detailed explanations of these libraries are beyond the scope of this chapter but lets have a look at a selection of some of the popular tag libraries that are available. Here are a few of the tag libaries available via the Jakarta “Taglibs” project, which should give you an idea of the kind of thing you can expect from a tag library.
Enterprise JavaBeansEnterprise JavaBeans (EJB) are managed, server-side components for the modular construction of enterprise applications[7]. We’ll start our tour of Enterprise JavaBeans by exploring the meaning of these three words. “Component” means that EJBs are distributed in binary format and are configurable, so that the client programmer can use them to create custom applications. It’s the same concept that you see with a JavaBean graphical component: you buy a JavaBean component to create pie chart graphs, you instantiate it in your application (probably using a RAD tool such as JBuilder), you set the component’s properties to your liking (for example the background color), and you use it in your reporting application. You don’t have the source code for the pie chart component, nonetheless you can customize it to your needs. The way you instantiate, customize and use Enterprise JavaBeans is not the same as with plain JavaBeans, but the concept of being a component is the same. It’s important to make a terminological distinction between the component and its instances: we use the term Enterprise JavaBean to refer to a type of component – for example an EJB that represents a bank account; and we use the term EJB instance to refer to an object that represents a specific bank account with a unique account number. “Server-side” means that EJB objects are allocated in a process on some server, not on the client machine. EJBs can offer a remote view, a local view, or both. The term “view” doesn’t refer to a graphical view; here we are talking about the way an EJB exposes its interface. If an EJB offers a remote view, all method invocations between the client code and the remote instance happen via a remote procedure call protocol, most likely RMI-IIOP. If an EJB offers a local view, the client code must be in the same process as the EJB object, and all calls are direct method calls. As you have seen in Chapter 16, the ability to perform remote procedure calls implies the presence of two fundamental architectural pieces: a naming service and RPC proxies. A naming service is a network service that client applications use to locate heterogeneous resources on the network. An RPC proxy is a programmatically‑generated Java class, instantiated on the client side, that exposes the same interfaces as those of a specific remote component. Since it exposes the same interfaces, the client can’t tell one from the other, and the proxy can pretend to the be the remote instance. But what the proxy does, in fact, is delegate all calls to the remote component, implementing the networking code and hiding all the complexity from the client. In EJB, we have the same concepts of naming service and RPC proxies, but they are slightly different from what you’ve seen with Java Remote Method Invocation (RMI). Finally, and most important, EJBs are managed. This means that when an EJB object is active in memory, its hosting process is doing with it much more than what the plain JVM does. The process hosting an EJB object is called an EJB Container, and it’s a standardized runtime environment that provides management functionalities. Since the EJB specification standardizes the services provided by an EJB Container, we have vendors implementing these functionalities in commercial products, like WebSphere and WebLogic, two well-known commercial EJB Containers by IBM and BEA Systems, respectively. In an EJB Container, services like remote objects and client-protocol neutrality are implicit in the use of Java RMI; other services (listed below) are standard. Services like clustering and fail-over support are additional values offered by certain vendors. These are the services offered by all EJB Containers: · Object Persistence · Declarative Security Control · Declarative Transaction Control · Concurrency Management · Scalability Management Object Persistence means that you can map the state of an EJB instance to data in some persistent storage – typically, but not only, a relational database. The Container keeps the state in the persistent storage synchronized with the state of the EJB instance, even when the same object is accessed and modified concurrently by multiple clients. Declarative Security Control gives you the option of letting the Container check that the client invoking a specific method on a specific EJB has been authenticated and belongs to a security role that you expect; if it doesn’t, an exception is generated and the method is not executed. The benefit of declarative security control is that you don’t have to code any security logic in your EJB – you simply define security roles and “tell” the Container which roles are allowed to invoke which methods. Since there is no security logic hard-coded in your EJB, it’s easy to specify changes to the security requirements with no recompilation. Declarative Transaction Control is a similar mechanism: you tell the Container to do something on your behalf, but the information you provide is what should happen in terms of transaction demarcation when a specific method is called. For example, you could instruct the Container to start a new transaction when the method is called, or you could instruct it to use an existing transaction and refuse the method call if one isn’t already active (transactions propagate in a chain of method calls). The Container will automatically commit a transaction when the method that started the transaction terminates gracefully, or it will roll the transaction back if it catches any exception thrown while the transaction was active. Again, the benefit of declarative transaction management is that there is no transactional logic in your EJB source code, so not only does that makes life simpler for the developer, but it also makes it easy to modify the transactional behavior of your EJB without recompilation. If you remember that EJBs are components, you’ll also see why these two features are so important. Being able to declaratively control the security and transactional logic is a fundamental requirement in a component model, because it allows people who don’t have the source code, or don’t want to work at that level, to adapt the component to the application that is being built with it. Concurrency Management synchronizes concurrent method invocations coming from different remote clients and directed to the same EJB object. In practice, it guarantees that the component can be safely used in the inherently multithreaded environment of an application server (quite a valuable feature). Scalability Management addresses the problem of the increased resource allocation that occurs when the number of simultaneous clients increases. The resources allocated by a client are not only EJB objects, but are also all supporting resources like database connections, threads, sockets, message queues and so on. For example, if the number of simultaneous clients increases from 100 to 1,000, you may end up 1,000 EJB objects in memory, and perhaps 1,000 open database connections; this may be too much for the amount of memory that you have, and it’s certainly a heavy load on your database engine. An EJB Container may decide to address these problems by offering EJB instance pooling and database connection pooling. That is, the Container would keep only a limited amount of instances or connections alive in memory, and would assign them to different clients, only for the time the client actually needs one. Enterprise JavaBean FlavorsWe know that EJBs are components. However, the term “component” is one of the most overloaded in the industry, and different people (and different vendors) have different ideas of what a component is. On the Microsoft platform, including .NET, a component is something that complies with the (D)COM(+) binary specification, and the nature and type of a component is determined by the standard interfaces that it exposes. However, there is no architectural model enforced by the Microsoft platform, or at least it is intentionally very loose. In other words, there are very few enforced architectural guidelines that tell you how to develop and assemble components in order to create an enterprise application. The J2EE platform, on the other hand, provides you with a more precise architectural framework in which you create and use components. This is especially true with EJBs, where the specification defines three different EJB types, with different responsibilities and different areas of applicability. The three EJB types are: 1. Entity Beans 2. Session Beans 3. Message-Driven Beans Entity beans are persistent objects, in the sense that the Container transparently keeps their state synchronized with data in some persistent storage, typically a relational database. For this reason, entity beans are used to represent business entities, like a customer, a shopping cart and so on. Entity beans don’t implement business logic, except for self-contained logic directly associated with the internal data. Although all entity beans are exposed to the client code in the same way, they can be implemented using two different persistence strategies. The developer has two options: 1) let the Container take care of moving the state between an EJB object and the database, or; 2) take over this mechanism and implement the code that moves the EJB’s state from and to the persistent storage. In the first case, we say that we are employing Container Managed Persistence (CMP), so the entity bean is a CMP bean; in the second case we say that we are using Bean Managed Persistence (BMP), and we have a BMP bean. Again, although there are substantial practical differences between CMP and BMP, they are implementation strategies that do not affect the way an entity bean is used by clients. Discussing all the implications of choosing CMP over BMP is beyond the scope of this chapter. However, it’s important to explain that the most valuable benefit of CMP is not, as you may think, that you don’t have to code the persistence logic yourself. The real benefit of CMP is component portability across different persistent storages. If you think about it, CMP works because the Container generates all the code necessary to move state between an EJB object and the persistent storage, and vice versa. This means that the Container knows how to communicate with that specific storage. An EJB Container implementation supports multiple storages, typically all major RDBMS like Oracle, DB2, MySQL, etc. Since the persistence logic is not hard-coded in a CMP entity bean, but is provided by the Container, you can use the same binary component in different operating environments and still get object persistence support from the Container. If you use BMP, the persistence logic (for example the SQL statements, if you are coding for a specific RDBMS) is built into your component and that makes it harder to use it with a different storage. So, in general, you use CMP to promote portability, ; and you use BMP if your entity bean has to persist on some system not supported by the J2EE platform (for instance, a CICS application on an IBM mainframe) or under other special circumstances that we can’t cover here. Session beans are a different breed. They are not persistent, but are instead discrete components that implement business logic, for example the steps required to checkout and purchase some product from a virtual shopping cart. Session beans may cooperate with other session beans to access additional business logic, and they use entity beans when they need to access persistent information. Session beans come in two different variations: Stateless session beans (SLSBs) and Stateful session beans (SFSBs). The difference between the two is that Stateful session beans keep a conversational state during the communication with the client, whereas Stateless session beans don’t. The conversational state is the information that is passed from the client to the session bean in a sequence of method calls. For example, you could have a session bean implementing the logic to reserve and purchase movie tickets over the network. Clients would connect to and use one of this Bean’s instances; the instance would expose two methods, reserveSeats(…) and purchase(…). The first method receives the number of seats that the customer wants to purchase, and reserves those seats in the system; the second method receives the customer’s credit card information, validates the credit and completes the purchasing process. If the Bean is a Stateful session bean, once reserveSeats(…) has been called, the session bean instance “remembers” the requested number of seats, and you don’t need to pass that information again to purchase(…). If the session bean is stateless, on the other hand, the Bean has no memory of the information passed from previous method calls, so the client state needs to be passed with every call. There are several strategies to implement and optimize the state transfer, but state would still need to be passed with every method call. The reason for these two types of session beans is quite simple: certain business processes are inherently stateless (especially those that are closely mapped to an HTTP front-end) and others are inherently stateful; the architecture is designed to reflect this. There are technical implications in the use of one session bean type versus the other, but as in the case of CMP versus BMP, a detailed discussion is beyond the scope of this chapter. One thing that you want to remember though, is that Stateless session beans tend to work better with the Container’s instance pooling mechanism than Stateful session beans. Since a Stateless session bean instance is not supposed to remember any state information passed by the client once a method completes, the same instance can easily be reassigned to a different client for another method invocation. If the session bean instance is Stateful, the Container cannot assign it to a different client, unless it first moves the instance state to some temporary storage for later retrieval (a process called, in EJB, activation and passivation). It’s a common misconception that due to instance pooling, Stateless session beans make for better scalability, but this is not always the case. Your Container could have a very highly optimized activation and passivation mechanism, so that moving a Stateful session bean’s state to and from some secondary storage has very little effect on performance. Second, if you use a Stateless session bean, you must pass the client’s state into the session bean with every call, and if the client and the session bean are on two different distribution tiers, the act of constantly transferring state, and serializing and deserializing the method parameters as required by RMI, could become critical. An interesting side note about instance pools is that your Container may not employ them at all. With the recent optimizations introduced in the Java compilers and JVMs, modern Containers have discovered that allocating and garbage‑collecting raw memory is more efficient than managing a pool. Finally, the third type of Enterprise JavaBean: Message-Driven Beans (MDB). MDBs work in cooperation with the Java Messaging System (JMS), which is an abstraction API on top of Message-Oriented Middleware (MOM) systems, more or less in the same way that JDBC is an abstraction API on top of SQL databases. Once again, we don’t have the space in this chapter for a full discussion on MOM systems. Briefly, MOM systems provide a publish-subscribe messaging model based on asynchronous, distributed message queues. A MOM message is a packet of information that someone publishes and someone else is interested in receiving. MOM messages are published to, and retrieved from, a queue or channel. The publisher and the subscriber can be in two separate processes, and messages sent into a MOM queue are guaranteed to be delivered, even in the case of a system crash. MOM systems are extremely valuable for implementing any form of distributed, asynchronous processing – something similar to event handling in a standalone application. MDBs are receivers of MOM messages coming through the JMS API. An MDB is usually implemented to perform some kind of action when a message is received, and acts as an object-oriented connection point between subsystems cooperating using JMS. For example, an MDB could be implemented to send an email to the administrator (using the JavaMail API), when a message that notifies certain events is received. One other thing about MDBs is that, unlike session beans and entity beans, they do not expose any remote or local view. In other words, client code can not access an MDB, but the MDB can use other EJBs and other services. EJB RolesThe fact that the EJB is a component architecture implicitly means that there are different moments in the lifetime of an EJB component: development, installation, configuration and use. The EJB specification goes to the extent of defining the organization of labor and the different roles involved in the lifetime of an EJB component. Specifically, the following roles are defined: · Enterprise Bean Provider. Implements an EJB component and packages it for distribution. Knows about the application domain, but not necessarily about the operating environment in which the component will be used. · Deployer. In EJB, deployment is the act of installing one or more EJB components in a specific EJB Container. The Deployer is an expert on the specific operating environment, and is responsible for associating the EJB with all the resources it needs to operate (database connections, tables, other EJBs and so on). · Application Assembler. Uses different components deployed in a specific environment to create a complete application. · System Administrator. Is responsible for creating and maintaining users, databases and in general all the infrastructure resources needed by a specific operating environment. It’s important to remember that these are roles, not persons. On a small project, the same person may play any or all of these roles. On a large project, where components could be developed by other departments or bought from thirds parties, different persons play different roles. The other interesting thing is that the specification not only defines the responsibilities and expected skills of each role, but it even defines which source files and tasks are assigned to each role. In the same way, the EJB specification makes sure that every piece of non‑standard configuration information is defined in separate source files. This is because different EJB Container implementations may offer different features, typically configurable by the mean of XML files. If certain features are specific to one Container, they will be specified in Container-specific files. The Basic APIsThe EJB API is not the only one on the Java2 Enterprise Edition platform. There are many more: the Java Transaction API (JTA), the Java Messaging System API (JMS), Servlets, JavaServer Pages (JSP) and Java Database Connectivity (JDBC) to name a few. Before we can look at how to implement and use an EJB, we need to briefly cover a couple of fundamental APIs: the Java Naming and Directory Interface (JNDI) and the actual EJB API. JNDIJNDI is an abstraction API on top of different naming services, like the RMI Naming Service or the COS Naming Service in CORBA, and directory services like the Lightweight Directory Access Protocol (LDAP). A naming service and a directory service are not conceptually the same thing, but once again this is not the right place to discuss the differences. What we’ll do is to look at what they have in common. All naming and directory services let you populate and search some sort of repository. More specifically, they let you associate (or bind, if you wish) a name with an object, and then search for that object (or look it up) using that name. By analogy, they can be used as a white pages directory, where the physical telephone that you want to place a call to (uniquely identified by a number) is associated to a customer name. A more Java‑related example, is RMI: you can register an object with a name (a String) in the RMI Naming Service, so that other applications can locate it looking that name up in the service. But this is also the exact same thing that you can do with the COS Naming Service. So that’s why JNDI is such a convenient abstraction: it provides you with a uniform interface to access different naming and directory services, just like you can use JDBC to access different databases. Like JDBC, JNDI is an abstraction API, and what you find in the JNDI package javax.naming is primarily Java interfaces. The actual implementation of those interfaces must be provided by some vendor that wants to provide JNDI support for their service. To actually use that service, you need a JNDI Service Provider – just like you need an appropriate JDBC driver to access a specific database. JDK 1.4 comes with four standard JNDI Service Providers that provide support for RMI, DNS, COS Naming Service and LDAP. There is an additional JNDI Service Provider, that you can get from Sun’s web site, that provides a JNDI view over your local file system (so you can locate files and directories using JNDI). JNDI supports the concept of a namespace, which is a logical space in which names can be defined. The same two names defined in different namespaces will generate no ambiguity or name clashing, and namespaces can be nested. This is a concept that you see in a number of different situations — your local file system uses nested namespaces (directories), and the Internet DNS uses nested namespaces (domains and sub‑domains). In JNDI a namespace is represented by the Context interface, the most frequently used element in the API. There are various classes implementing the Context interface, depending on the actual service you are accessing via JNDI. The Context interface has methods to bind a name to an object, to remove the binding, to rename it, to create and delete sub‑contexts, to look names up, to list names and so on. You should also note that since a context is a Java object, it can be registered in another context with its own name. In other words, the way we express nested sub‑contexts in JNDI is by starting with the parent context, and creating a binding in it between a sub‑context name and a nested Context object. Another fundamental concept in the JNDI API is that, regardless of the actual service that you use, to be able to create bindings, perform lookups and so on you need to start from some “root” context. The InitialContext class is what you use to get a Context instance that represents the parent of all the sub-contexts you want to access. Although certain operations in JNDI are only applicable to certain Service Providers, the concepts expressed so far are general and widely applicable. Let’s see an example. The code snippet below shows how to list all the names registered under the root of the service you are using. You’ll notice that the InitialContext constructor receives an argument of type Property. I’ll explain that bit in a second. For the moment, just take a look at the code below. Context context = new InitialContext(props); Enumeration names = context.list("");
while(names.hasMoreElements()) System.out.println(names.nextElement());
You see that it’s quite simple. We create a Context object that represents the root of your naming or directory service, get an enumeration of all the elements in that context (the empty string in the list() method call means that you are not searching for a specific name), then iterate and print out all the elements in the enumeration. The abstractions and the programming model are quite simple. The real question though is: which naming or directory service are we using? The answer is in the property bag that we pass to the InitialContext() constructor. The JNDI API defines quite a few standard property names (declared as constant Strings in the Context interface) and the value of those properties determines the nature of the service that you’ll be using. Of these properties, two are fundamental: INITIAL_CONTEXT_FACTORY and PROVIDER_URL. The first one specifies the class that will produce JNDI Context instances. If you want to use DNS, for example, you’ll need to specify a class that produces Contexts capable of interacting with a DNS server. The second property is the service location, and is hence a URL. The format of this URL depends on the specific service. Below is the complete example that uses JNDI to browse the contents of the root context in a DNS server (you may need to use a different IP address for your DNS, depending on your network configuration). //: c18:jndi:SimpleJNDI.java import javax.naming.*; import java.util.*;
public class SimpleJNDI { public static void main(String [] args) throws Exception { Properties props = new Properties(); props.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory" );
props.put( Context.PROVIDER_URL, "dns://207.155.183.72" );
Context context = new InitialContext(props); Enumeration names = context.list("");
while(names.hasMoreElements()) System.out.println(names.nextElement()); } } ///:~
If you wanted to use a different DNS, or a completely different type of service, in most cases you would just put different information in the property bag, but the rest of the code would be the same. There is another way of providing the JNDI property values. You can use an external property file, that is a text file that associates property names with their values. This file has to be named jndi.properties, and it must be in the classpath of your JNDI application. The only difference is that you cannot use the property name constant defined in the Context interface, but you must use their “raw” value instead (which you can find in the standard JDK documentation). The content of our jndi.properties file is: java.naming.factory.initial=com.sun.jndi.dns.DnsContextFactory java.naming.provider.url=dns://207.155.183.72
If you take this approach, you will no longer need to pass a property bag to the InitialContext constructor. In other words, what you place in the jndi.properties file are your default JNDI settings. The last and most important thing we have to cover about JNDI is how to look up names. As I mentioned, there is lookup() method in the Context interface. In the following example we’ll assume the presence of an external jndi.properties file that defines which service you are browsing. //: c18:jndi:SimpleJNDI2.java import javax.naming.*;
public class SimpleJNDI2 { public static void main(String [] args) throws Exception { System.out.println( new InitialContext().lookup(args[0]) ); } } ///:~
We create a new InitialContext and call the lookup() method on it, passing a String as the name argument. Since the lookup() method is designed to work with different services, it returns a generic Object. However, the actual run‑time type returned from lookup() depends on the specific service you are using. For the sake of this example though, we ignore the type and just print the result. In EJB programming, we use JNDI to locate all kinds of resources, including EJBs, database connection pools, environment information and more. In other words, from within an EJB Container your only window on the world is JNDI. Client applications also use JNDI to obtain connections to EJB factories (more about this later). So, if we use JNDI with EJBs, which is the JNDI Service Provider? The answer is that an EJB Container runs and exposes its own JNDI service, specialized to work with resources managed by that Container. In other words, this EJB JNDI service is designed is to let clients and internal Enterprise JavaBeans locate resources by JNDI names. So remember, when you start your EJB Container, you are also implicitly starting an EJB JNDI service, which is available to you through the standard JNDI API. EJBThe other API we need to take a look at is the EJB API itself. It’s defined in the javax.ejb package which, interestingly enough, is composed just of interfaces and a few exception classes. The diagram below shows the main interfaces in the package. Three of them represent the different EJB types: EntityBean, SessionBean and MessageDrivenBean. Depending on which type of EJB you are coding for, your class will have to implement one of these interfaces. There are also the EJBHome and EJBObject interfaces which you use as base interfaces when you define your bean’s remote view (if you want one) – for this reason EJBHome and EJBObject are derived from the RMI Remote interface. The remaining two interfaces, EJBLocalHome and EJBLocalObject, you use to provide the local view of your bean (again, assuming you want to have a local view). In the next section we’ll see how to actually code using these interfaces. For the moment just keep the design in mind.
The other set of elements that we need to cover briefly is the exception classes. You can see below a diagram with the most relevant exceptions (there are a few more in the package, please refer to the JDK documentation for the details).
As you can see, there are two major categories: exceptions derived from java.lang.Exception directly, and others derived from java.lang.RuntimeException. Or, in the Java parlance, checked and unchecked exceptions, respectively. In EJB all checked exceptions are considered application-level exceptions. That is, they spread multiple tiers of a distributed application, and when generated by an EJB, they cross network distribution tiers and propagate to the remote client. In fact, the use of EJB checked exceptions in the definition of the EJB interfaces that clients use, is enforced by the specification. For example, CreateException must be in the exception specification of methods that the clients use to instantiate an EJB. Similarly, FinderException has to be in the exception specification of methods that clients use to locate existing, persistent EJB objects. And RemoveException must be specified by methods that remove an EJB object. Unchecked exceptions, instead, are used in the internal implementation of an EJB. In other words, if something your EJB is attempting fails, you throw an EJBException or one of its subclasses. The reason why EJBException is unchecked is because in most cases it represents some error that propagates from a sub-system to another inside the EJB Container. Even if you were forced to catch it there isn’t much you could do about it – an EJB instance exists only inside an EJB Container, which manages the instance and takes care of what happens to it. Here’s an example: you have implemented an EJB that accesses a database and at a certain point the database generates an SQLException. It would be pointless to return this exception to the remote client, because the client wouldn’t know what to do with it. On the other hand, you want to abort the current operation and notify the Container that something went wrong, so that it can take some corrective action like rolling back the current transaction. You can’t simply let the SQLException propagate into the Container, because the Container has a generic way to receive system-level exceptions – so that it can consistently receive exceptions from different, even future, sub-systems. What you do is wrap the checked SQLException in an unchecked EJBException, using its constructor that takes a java.lang.Exception, and then you throw the EJBException. All exceptions that propagate out of your EJB object are intercepted by the Container. The action taken at this point by the Container may vary depending on the circumstances, but in general the Container will automatically rollback the current transaction (if there is one) and will propagate the exception to the client. If the exception generated inside of your EJB was an EJBException, the client will receive a generic RMI RemoteException to inform it that the method failed. If the exception generated in the EJB was an application-level exception, like FinderException, that will be the exception that the Container passes on to the client. EJB Container internalsYou know that EJBs are managed components, and it’s now time to take a closer look at how the Container manages your EJB objects. That will help us to better understand the services that the Container provides, the code examples and the development process. The basic idea is quite simple. Whenever the client application asks for a reference to an EJB object, the Container actually returns a reference to a Container‑generated proxy that intercepts all client calls, performs some housekeeping and eventually delegates to the object implemented by the Bean Provider. We call the former EJB Object, and the latter EJB Instance. Please make sure you don’t confuse the two: the EJB Object is generated by the Container, whereas the EJB instance is implemented by the Bean Provider. You should also note that the presence and role of the EJB Object is a standard part of the EJB specification. Also note that its implementation strategy and the way it cooperates with the EJB instance is Container‑specific. Finally, the Container-generated proxy (the EJB Object) is not to be confused with the RMI proxy, which is also present. The diagram below should help clarify the architecture.
The diagram shows the architectural positioning of the EJB object relative to other major pieces. In the diagram, I’m showing the case of a remote client application, but you should keep in mind that there is always an intercepting EJB object, even when the method calls come from code in the same Container (another EJB, for example). The RMI proxy and stub, on the other hand, are present only when the client accesses the remote view of the EJB component. Please note that the RMI proxy and stub are automatically generated by the Container, although different Containers do so employing different strategies. The dashed arrows represent dependencies, and they mean that if, for example, the implementation of the EJB Instance changes, the EJB Object should also be modified, because it relies on specific methods implemented by the EJB Instance. The fact that an EJB Instance is never accessed directly is the basic mechanism by which the Container manages your bean instances. In the EJB parlance we say that the Container injects code between the client (whatever that is) and the EJB Instance, and we call the EJB Object a Container artifact. The code injected by the Container provides the EJB instances with middleware services like instance pooling, concurrency management, security management, transaction management and object persistence. This takes a big burden off your shoulders – imagine how much code you would need to write to implement some or all of these services yourself. But since you have an EJB Container, you can simply tell it what you want it to do on your behalf – for example, start a new transaction when a specific method is called. In EJB we refer to the declarative control of the transactional and security logic as meta-programming. The idea is that you are, in fact, programming your component or application, but part of the behavior you don’t code yourself – you just tell the Container what to do. At this point you have all the architectural background that you need to start looking at how we implement and use an Enterprise JavaBean. I’ll give you more information about the EJB Object and the way the Container works internally as we go through the code examples. SoftwareBefore we start looking at the code, let’s briefly cover the software you’ll need to install to run the examples. All the code for the examples is provided with the book. I recommend that you use the code and the build scripts provided, since the build process involves several steps and multiple source files. All the EJB examples in this chapter have been tested on the JBoss 3.0.3 application server (JBoss is the leading open-source EJB Container, and it can be downloaded for free from http://www.jboss.org ). Although I used JBoss, and more specifically the version that comes with the embedded Tomcat Servlet container, the amount of JBoss-specific information in this chapter and in the examples has been kept to the minimum, so porting these examples to a different Container should require very little or no code modification. Please note, however, that if you use a different JBoss version you may need to adjust the Ant build scripts accordingly. The other software tools that you’ll need are: Java SDK1.4 or above; Ant and JUnit (which you have probably already installed if you have run other examples from this book); and XDoclet, another open source utility that will help us in the development of our EJBs. The installation guide that you’ll find in the c18 code directory will provide all the additional details. The example applicationAll the examples in this chapter follow a common theme to exemplify the concepts. We will build a simple application, called JavaTheater, to sell and buy movie tickets. The application will be incrementally built, example by example, and we’ll have to address movies, shows, tickets, customers, credit cards and so on. I don’t have the space to show you how to create a full-fledged application, so I’ll focus on its core functionalities. There will be classes that represent persistent entities like a movie and a show, and other classes that implement the bulk of the application logic . For example the steps required to actually purchase one or more movie tickets for a particular show. Before we see the actual code, I’d like to mention a few things about the source file structure. All the examples are in the c18 directory of the book source code. Each subdirectory is a separate, self-contained example built on top of the previous one. At the top level of each example subdirectory there is the Ant build script. At the same level, there is a src subdirectory, which contains all the source code for that example. The src directory contains the ejb-tier and rmiclients subdirectories which contain the code for the EJB implementation and for the client application (including JUnit test), respectively. Also please note when you build the example, the Ant script will create working directories for compilation and building (refer to the comments in the Ant script for details), but nothing is created or modified in the src directory. Finally, all of our classes are defined in the javatheater package, with a few subpackages that are worth mentioning: javatheater.client contains the client applications; javatheater.test contains the JUnit test cases; javatheater.ejb contains our EJBs’ interfaces and related classes, and javatheater.ejb.implementation contains the EJB implementation classes. Our first example, example01, doesn’t use any EJB functionality. It’s a plain and simple Java application that we use to prototype some of the fundamental domain classes. The simplest class is Movie, and you can see its implementation below: //: c18:example01:src:javatheater:Movie.java // package javatheater;
public class Movie { int id; String title;
public Movie(int id, String title) { this.id = id; this.title = title; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String toString() { return "[" + id + "] " + title; } } ///:~
It defines a Movie class with two properties: an id (an int) and a title (a String). The class also defines a constructor plus setters and getters to access the property values. Of course, a more realistic movie object would need to contain a lot more information like the cast, the director, the rating, synopsis and so on; but implementing those would have added unnecessary complexity to the example. Another class is Show, which is also pretty simple: it has an id (an int), a show time (a String) and the number of available seats (an int). It also contains a reference to a Movie object, which means that there is a uni-directional, many-to-one relationship between shows and movies: a movie can be associated to many shows, but a show has only one movie. In other words, it’s easy to navigate from a show to a movie, but there is no way to get the list of related shows directly out of a movie. Here is the implementation of the Show class: //: c18:example01:src:javatheater:Show.java // package javatheater;
public class Show { int id; Movie movie; String showtime; int availableSeats;
public Show( int id, Movie movie, String showtime, int availableSeats ) { this.id = id; this.movie = movie; this.showtime = showtime; this.availableSeats = availableSeats; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public Movie getMovie() { return movie; }
public void setMovie(Movie movie) { this.movie = movie; }
public String getShowtime() { return showtime; }
public void setShowtime(String showtime) { this.showtime = showtime; }
public int getAvailableSeats() { return availableSeats; }
public void setAvailableSeats(int availableSeats) { this.availableSeats = availableSeats; }
public String toString() { return "[" + id + "] " + movie + ", " + showtime + ", " + availableSeats; } } ///:~
Since example01 is a simple Java application, it doesn’t employ the many services offered by the EJB architecture. Specifically, we don’t have any persistence support. I didn’t want to use JDBC to store and retrieve the object state from a database (that would have implied object/relational mapping, something too complex for our first example), so there is a class in this example, called Storage, that simulates the presence of a persistent datastore. //: c18:example01:src:javatheater:Storage.java // package javatheater;
public class Storage { private static Storage ourInstance; private Movie [] movies; private Show [] shows;
public synchronized static Storage getInstance() { if (ourInstance == null) { ourInstance = new Storage(); } return ourInstance; }
private Storage() { movies = new Movie[] { new Movie(1, "Return of the JNDI"), new Movie(2, "A Bug's Life"), new Movie(3, "Fatal Exception"), new Movie(4, "Silence of the LANs"), new Movie(5, "Object of my Affection") };
shows = new Show[] { new Show(1, movies[0], "5:30pm", 100), new Show(2, movies[0], "7:00pm", 300), new Show(3, movies[1], "6:00pm", 200), new Show(4, movies[4], "9:00pm", 200) }; }
public synchronized Movie findMovieById(int id) { for (int i = 0; i < movies.length; i++) { Movie movie = movies[i]; if (movie.id == id) return movie; }
return null; }
public synchronized Movie findMovieByTitle(String title) { for (int i = 0; i < movies.length; i++) { Movie movie = movies[i]; if (movie.title == title) return movie; }
return null; }
public synchronized Movie [] findAllMovies() { return movies; }
public synchronized Show findShowById(int id) { for (int i = 0; i < shows.length; i++) { Show show = shows[i]; if (show.id == id) return show; }
return null; }
public synchronized Show findShowByMovie(Movie movie) { for (int i = 0; i < shows.length; i++) { Show show = shows[i]; if (show.movie.id == movie.id) return show; } return null; }
public synchronized Show [] findAllShows() { return shows; } } ///:~
This class implements the Singleton design pattern (there would only be one data store in our system). Its private constructor populates a fictitious database with “Java-related” movies and shows. It also exposes public methods to retrieve movies and shows from the fictitious database using different criteria. There is no method to update our fake database, but you are free to add those as an exercise, if you feel so inclined. The last class in example01 is our main class, ShowListing, which simply uses Storage to locate a bunch of shows, and prints them out. //: c18:example01:src:javatheater:ShowListing.java // package javatheater;
public class ShowListing { static Storage storage = Storage.getInstance();
public static void main(String[] args) { Show [] shows = storage.findAllShows(); for (int i = 0; i < shows.length; i++) { Show show = shows[i]; System.out.println(show); } } } ///:~
Again, this example is intentionally simple, but it introduces a few fundamental concepts that we’ll apply using the EJB architecture: object persistence, separation of entity classes from business logic classes, and object relationships. Plus, it gives you an idea of what the application we are about to build is all about. Your first Enterprise JavaBeanThe first EJB we’ll implement represents a movie in your ticketing system. I chose this type of object because it contains no business logic and very little persistent information, so it will not distract us from the actual practice of implementing an EJB. Since a movie contains information (id and title) that must be persistent, we’ll implement it as an entity bean, using Container Managed Persistence. This EJB will be called, not surprisingly, Movie. Please note that this example is fundamental, since although we are going to implement a specific type of EJB (an entity bean), most of the information that you are going to see applies both to session beans and entity beans in their different variations. To implement the Movie bean, you will need to define two interfaces, the home interface and the component interface, and one implementation class. Depending on which kind of view you want your bean to expose, the home and component interfaces can be implemented as remote or local. We’ll define the Movie interfaces as remote for the moment. You will also need to provide an XML file, called the deployment descriptor, that you will use to tell the Container about some characteristics of your EJB, including persistence, transactional and security attributes. Finally, since the bean we are implementing is an entity bean, we may want to supply a class for the bean’s primary key (or you can just use some predefined class, which is what we will do). I’m going to cover each of the five elements listed above (home and component interfaces, implementation class, deployment descriptor and primary key) in the next sections. I’ll also give you a bit more information about the Container internals and Bean deployment. Home InterfaceWe our going to provide our Movie bean with a remote view. That means that when the client instantiates an EJB, the actual instance is created in the memory space of a process on the server, and the client gets a reference to that instance. Since the EJB instance is going to be remote, the client code can’t instantiate an EJB using the Java new operator, because new always allocates instances in the local address space. You could in theory use the new operator to instantiate a bean that exposes a local view, but the EJB specification makes the remote/local instantiation differences disappear by means of a factory object. A factory exposes the methods to instantiate your beans, and its implementation, generated by the Container, provides the logic to instantiate an EJB object in the Container’s address space. But that just shifts the problem: how do we get a reference to the factory object? The answer is JNDI. As you may remember, JNDI is our universal discovery mechanism in EJB, and all EJB Containers run an internal JNDI Service that clients can access across the network. When an EJB is made available to the Container, it is also given a JNDI name by either the Component Provider or by the Deployer. Client applications use that JNDI name to locate the factory object for that EJB (our Movie, for example), and then use the factory to instantiate Movie objects. The factory will expose the bean’s home interface, that you arbitrarily define (not completely arbitrarily though, it must conform to the EJB specification). The fact that you define the interface lets you specify which arguments to pass with method calls. For example, you can decide what information is required to instantiate a Movie. The implementation of that interface will be dynamically synthesized by the Container, which will find out about the interface methods using Reflection. If you are defining the home interface for an entity bean, there is another thing you can do with it in addition to creating instances. You can find existing ones. That makes sense if you consider that entity beans are, by definition, persistent in some data store; so being able to get a reference to one or more beans, created by someone, some time ago, is what you would expect. In a home interface, the methods that you use to instantiate new EJBs are called the create methods, and the methods that you use to retrieve entity bean instances are called the finder methods. Below is the definition of MovieHome, the home interface for the Movie entity bean. //: c18:example02:src:ejb-tier:javatheater:ejb:MovieHome.java package javatheater.ejb;
import javax.ejb.*; import java.util.Collection; import java.rmi.RemoteException;
public interface MovieHome extends EJBHome { public Movie create(Integer id, String title) throws RemoteException, CreateException;
public Movie findByPrimaryKey(Integer id) throws RemoteException, FinderException; } ///:~
You should note that this interface is derived from javax.ejb.EJBHome, which is in turn derived from java.rmi.Remote. This is because we decided to provide our Movie bean with a remote view, and the implication is that all methods in your home interface will have to conform to the Java RMI specification. In particular, all of them will have to include java.rmi.RemoteException in their exception specification. The EJB specification describes all the syntactical and semantic requirements for the create and finder methods. If you want all the details, please refer to the EJB specification that you can download from the Sun’s web site. In this chapter however, due to the limited space, I will just describe the meaning of the method signatures. The first method in the interface is a create method that clients can use to instantiate new Movie EJBs. It returns a Movie reference. Movie is the component interface of our Movie bean, and I will describe it in the next section. The first argument to the create() method is what we’ll use as the primary key for our bean. In this case, we decided to use an Integer to uniquely identify Movie instances. Primary keys will be described in more detail in one of the next sections. As the second argument, we’ll pass information that represents the Movie’s state – in this case, just the movie title. Finally, the method’s exception specification states that create() may throw a RemoteException and a CreateException. RemoteException is required by RMI, and should be no surprise to you. CreateException is an application-level exception that is part of the EJB API, and is generated when the bean’s instantiation fails inside of the Container. A specific reason why this may fail is if you try to instantiate an entity bean with the same primary key as another existing entity bean of the same type. This specific case is represented by DuplicateKeyException, a subclass of CreateException. The second method in the interface is a finder method that clients use to retrieve one existing instance of an entity bean. It’s called findByPrimaryKey(), and not surprisingly, it takes an Integer as the only argument (Integer is the primary key type) and returns a Movie reference. It also throws a FinderException, in case something goes wrong inside of the Container. If the specific problem is that no instance was found with that primary key value, the Container will generate an ObjectNotFoundException, a subclass of FinderException. All other finder methods, which return Java collections rather than a single reference, will not generate an ObjectNotFoundException, but simply return null. Also, the findByPrimaryKey() method is mandatory in the home interface of an entity bean. You can have as many finder methods as you like, to search persistent instances by whatever criteria you fancy. However, all finder methods must have a name starting with find…, must return a collection and must throw FinderException. The only finder method that returns a single instance is findByPrimaryKey(), since only the primary key guarantees a unique result – I will cover finder methods in more detail later in this chapter. There can also be multiple create methods in a home interface, and even EJB business methods (something similar to Java static method, which doesn’t operate on a specific instance). We’ll talk about these additional methods later; for the moment, let’s move on to the next interface. Component InterfaceThe component interface contains the business methods that clients invoke on a specific EJB instance, like getTitle() on a Movie object. For this reason, the component interface is arbitrarily defined by the Bean Provider, but it must still conform to the EJB specification. The only requirements though, are that the interface is derived from javax.ejb.EJBObject and that all methods throw RemoteException. Below is the definition of the Movie entity bean component interface. //: c18:example02:src:ejb-tier:javatheater:ejb:Movie.java package javatheater.ejb;
import javax.ejb.*; import java.rmi.RemoteException;
/** * A movie, with id and title. * * Note that there is no setId() method in the * interface, to prevent clients from arbitrarily * changing a movie's primary key. */ public interface Movie extends EJBObject { public Integer getId() throws RemoteException; public String getTitle() throws RemoteException; public void setTitle(String title) throws RemoteException; } ///:~
You see that the interface just provides setters and getters for the movie’s attributes (there is rarely business logic in entity beans). However, it’s missing the setter for the movie’s id. The reason being that you do not want to give clients the option to modify the primary key on an existing persistent instance, since that could very easily compromise the referential integrity of your system if that instance participates in any relationship. Primary KeyAt the conceptual level, a primary key in EJB is the same as it is in a relational database. It’s what you use to uniquely identify a group of information: a record in a database, or an entity bean instance in an EJB Container. However, in EJB this concept is intentionally more abstract than in a relational database, and the reason is that the EJB architecture is designed to work with a number of different back‑end systems including, but not limited to, a relational database. For example, your back-end persistence storage may be an object-oriented database, where there is no primary key as in a relational database, but object identifiers instead. So in EJB you can use any kind of object as your primary key. In other words, you can use any class derived from Object, but not primitive types. That’s why we used an Integer instead of an int as the Movie’s primary key. EJB primary keys can contain one single value, or multiple values (to have a compound primary key). They can also be classes whose definition is deferred until deployment time. For more information, including implementation requirements, please refer to one of the recommended readings at the end of this chapter. In this chapter, I will just use simple standard classes as primary keys. Implementation ClassNow that we have defined our home and component interfaces, we can proceed to implementing the Movie bean. You may expect to define a class that implements both interfaces but, interestingly enough, you don’t. Instead, you will need to define a class that implements one of the EntityBean, SessionBean or MessageDrivenBean interfaces, depending on which kind of bean you are implementing. So, who’s going to implement the home and component interface that you defined? The Container is, of course. The diagram below should help you understand how and why the Container dynamically synthesizes implementation classes for your home and component interface. In the diagram below we assume that the client application works using a TCP/IP connection, although I’ve omitted it from the diagram.
If you look carefully at the diagram above, you’ll see that you don’t actually implement any of the interfaces you define. All of them are implemented by Container‑generated classes: the RMI components, the Home object and the EJB Object. There is a very good reason for not having the Bean Provider implementing those interfaces. If you inspect the interface hierarchy, you’ll discover that your interfaces contain several methods, inherited from the base interfaces, that are not supposed to be implemented manually, because they are part of the RMI or Container infrastructure. The Container provides the implementation of the home interface (the Home object), and the implementation of the component interface (the EJB object), so that all client calls will be intercepted. Eventually, the Container will delegate those calls to your Movie instance, but the Movie implementation class will not implement MovieHome and Movie. Which interface then is the EJB instance supposed to expose, so that the EJB Object can delegate client calls to it? For example, the Movie’s getTitle() method is defined in the Movie interface, which is not implemented by EJB Movie instance. So which interface defines the semantic contract between the Movie EJB object and the Movie EJB instance? You must remember that the EJB Object implementation is synthesized by the Container. That implementation is modeled on the definition of the component interface that you provide, which the Container discovers using reflection. What you have to do is conform to a naming convention defined by the EJB specification, that describes which methods the EJB object expects to find on your EJB instance (a Movie, in our case). This naming convention describes the semantic rules that you must follow so that the Container can communicate with your EJB instance. In this chapter, I refer to the outcome of applying this rule to the component meta-interface. It’s not a Java interface in a strict sense, but it’s still a set of methods that, in practice, defines the contract between the Container‑generated EJB object and the programmer‑defined EJB instance. There are two categories of methods in the component meta‑interface: Container notification methods and business methods. Container notification methods are methods in your bean implementation class that the Container calls under special circumstances. They are easy to spot because their names all start with the ejb<…> prefix – for example, ejbCreate(). The only exceptions to this rule are the Context‑related notification methods: setEntityContext(), unsetEntityContext(), setSessionContext() and setMessageDrivenContext(). I’ll explain each of the Container notification methods later, when we look at the source code of the implementation class. Business methods are simply the methods that you have defined in your component interface. All those methods must be in your EJB implementation class with exactly the same signature, except for RemoteException, which you do not include in the methods’ exception specification. There is however one important architectural part of the EJB 2.x specification which affects the actual business methods that you have to implement. Starting with EJB 2.0, the architecture provides an abstract programming model for CMP entity beans. It means that the implementation of the persistent fields of an entity bean is not a Bean Provider’s responsibility, but is instead delegated to the Container. We refer to Container‑generated persistent fields as virtual fields. Let’s take for example the Movie bean. You can tell by the presence of the setters and getters in the component interface that Movie has two properties: id and title. You may expect: a) that you have to implement the getters and setters; b) that you have to declare an Integer and a String in your implementation class to hold the value of the id and title respectively, and; c) that the state of those variables will then be kept in sync by the Container with the corresponding state in the persistent storage. That would be exactly the case if you were coding for EJB 1.x. However, EJB 2.0 introduces a simple concept, which is that the Container can do a much better job than the developer at providing the implementation of those persistent properties. The reason for this assumption is that the Container may have intimate knowledge of that specific storage which the developer doesn’t have, so it can optimize better (for example if you use the WebSphere container with a DB2 database, both from IBM). So, in the case of methods representing persistent properties of an entity bean, you don’t provide those method implementations, because the Container will generate them for you. In your code you declare the implementation class of your entity bean as abstract, and it will be used as the base class for a Container-generated one (yes, another one!) that implements the persistence logic. You simply have to declare the methods representing the persistent properties as abstract methods in your implementation class. Let’s take a look at MovieBean, the implementation class for our Movie CMP entity bean. //: c18:example02:src:ejb-tier:javatheater:ejb:implementation:MovieBean.java package javatheater.ejb.implementation;
import javax.ejb.CreateException; import javax.ejb.EntityBean; import javax.ejb.EntityContext;
public abstract class MovieBean implements EntityBean { // Container notifications methods public Integer ejbCreate(Integer id, String title) throws CreateException {
if (id == null) throw new CreateException("Primary key cannot be null");
if (id.intValue() == 0) throw new CreateException("Primary key cannot be zero");
setId(id); setTitle(title);
return null; }
public void ejbPostCreate(Integer id, String title) {} public void ejbLoad() {} public void ejbStore() {} public void ejbRemove() {} public void ejbActivate() {} public void ejbPassivate() {} public void setEntityContext(EntityContext ctx) {} public void unsetEntityContext() {}
// Business methods public abstract void setId(Integer id); public abstract String getTitle(); public abstract void setTitle(String title); public abstract Integer getId(); } ///:~ < | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||