JSP Tag Libraries
JSP tag libraries provide a simple, elegant way of embedding dynamic server-side request handling into a JSP page. WebLogic Server provides a tag library with custom tags that you may use in your JSP pages; this library defines the cache, repeat, and process tags. Other tags also are supplied, though these are not discussed, as much of their functionality can now be found in more standard tag library implementations, such as the Java Standard Template Library (JSTL). WebLogic also provides a tool to automatically generate a tag library for an EJB.
2.4.1 WebLogic's Tag Library
WebLogic's tag library JAR (weblogic-tags.jar) is located in WL_HOME/server/ext. It packages the tag library descriptor, the tag handler classes, and several other support classes. In order to use these tags in your JSP pages, you need to make the library available to your web application. Copy the JAR to the /WEB-INF/lib folder under the document root of the web application, and define a taglib element in the standard web.xml deployment descriptor:
/weblogic-tags /WEB-INF/lib/weblogic-tags.jar
Now you can import the tag library into your JSP pages as follows:
<%@ taglib uri="/weblogic-tags" prefix="wl" %>
Let's take a closer look at the features and capabilities of these three tags.
2.4.1.1 The cache tag
The cache tag enables you to cache the output generated within the body of the tag. Because the output is usually some function of parameter or attribute values, the tag also allows you to cache the values of input parameters or attributes that uniquely generate a particular response. The caches are implemented using soft references to prevent the cache mechanism from hogging memory. Let's examine important attributes of the cache tag.
A cache tag may specify a unique name for the cache, if it is to be used across multiple JSP pages. A random name is generated if you do not specify one. By default, the cache tag uses an application-wide scope. You may specify a custom scope for the cache tag using one of the following values for the scope attribute: page, request, session, or application. For example, if you need to cache the contents of the tag's body for each HTTP session, you should use the cache tag as follows:
...
The tag's body content will be evaluated once when the JSP is requested after an HTTP session has been created, and then cached forever until the session is invalidated (or the cache is manually flushed).
You may also specify a timeout value, after which the cache contents become invalid. The tag content is not refreshed automatically after the timeout. Instead, it is reevaluated only when the JSP is invoked for the first time after the timeout occurs. You may use any of the following time units, as appropriate: ms (milliseconds), s (seconds), m (minutes), h (hours), or d (days). The default timeout value is -1, which implies that the cache data will never be refreshed. The following example illustrates how you can use the cache tag to refresh news content every 15 minutes:
<%-- HTML News Feed --%>
Often the contents of the tag's body will be evaluated based on the value of a certain request parameter or perhaps an object associated with the request or session attribute. For instance, you could generate news items on the basis of a URL submitted via a request parameter to the JSP. In that case, you need to be able to associate the content generated with the name of that parameter or the object attribute used to evaluate the content. The key attribute allows you to specify the name of a parameter/attribute, whose value will be used as a key to locate the cached response generated within the tag's body. In fact, you may specify a comma-separated list of key values. The following example shows how to cache the tag contents, using the value of the url request parameter as the key:
key="parameter.url" timeout="15m" size="10"> <%-- JSP body that uses the url parameter, perhaps to fetch a news item --%>
The contents of the tag's body are evaluated the first time a JSP is invoked, and the response is cached using the specified value for the url parameter. If the JSP is subsequently invoked with the same value for the url parameter, the cached response will be returned as long as it's not more than 15 minutes old. Otherwise, the contents of the tag will be reevaluated and the cache updated. The size attribute instructs the JSP container to cache the content for no more than 10 unique url values. The least recently used items are expelled from the cache if new items need to be inserted and the cache has reached maximum capacity. The default value for the size attribute is -1, which means the cache supports an unlimited number of entries.
The following example caches the contents of the tag's body based on the value of a session attribute:
key="session.userid"> <%-- JSP body that generates HTML form with details of current user --%>
In this case, the output is cached until the particular session is invalidated. Notice how the key uses a prefix to specify a scope for the parameter or attribute. You can choose from the following prefixes: parameter, page, request, session, and application. If the key does not have a scope prepended to it, the container will search through the scopes in the same order listed earlier.
The cache tag also supports input caching, whereby the tag caches values that are calculated within the tag's body. The vars attribute allows you to specify a list of the names of variables whose values should be cached along with the body of the tag. Just like the key attribute, you may prefix the variable name with a scope. When the cache is retrieved, the values that were cached are restored, allowing you to access them from their respective scopes outside the cache tag body. For instance, say that we calculate some value, calculatedvalue, and store it as a request attribute. The calculated value will then be made available after the cache tag:
Attribute value before is: <%= request.getAttribute("calculatedvalue") %> <% request.setAttribute("calculatedvalue", new Date( ).toString( )); %> Attribute value after is: <%= request.getAttribute("calculatedvalue") %>
Here is the output when we access this page a number of times over a 10-second window:
Attribute value before is: null Attribute value after is: Mon Feb 10 09:27:58 GMT 2003 Attribute value before is: null Attribute value after is: Mon Feb 10 09:27:58 GMT 2003 Attribute value before is: null Attribute value after is: Mon Feb 10 09:27:58 GMT 2003 Attribute value before is: null Attribute value after is: Mon Feb 10 09:28:08 GMT 2003
Notice how the attribute value is retained by the cache and reinserted into the request scope after execution of the cache tag, making it available to the rest of the JSP page.
You also can set the async attribute to true, which means WebLogic will attempt to update the cache asynchronously if the cached entries are set to time out. In this case, a JSP request that generates a cache hit may still use the old cached response while the new values are concurrently evaluated and cached for future use.
Finally, the cache tag enables you to flush all cached values. If you set the flush attribute's value to true, the JSP container will flush all entries associated with the cache. Whenever you set the flush attribute, the cache tag must have an empty body. The following example shows how to flush a cache with session scope:
If the cache does not have a name, you must identify the cache using its vars, keys, and scope attributes.
You can refresh all caches in a particular scope by setting the _cache_refresh attribute's value to true. For instance, if you want to refresh all caches associated with a user's session, you should invoke the following from a session-aware JSP page:
<% session.setAttribute("_cache_refresh", "true"); %>
If you want all caches to be refreshed, you should set the attribute in the application scope. And, if you want to flush all caches associated with the current request, you should set the request attribute (or parameter) to true.
Table 2-3 provides a summary of the cache options.
Parameter name |
Description |
---|---|
name |
You can use this parameter to provide a unique name for the cache, allowing it to be shared across multiple JSP pages. |
timeout |
The timeout determines the time after which the cache will be refreshed if accessed again. |
scope |
The scope determines the scope in which the data is cached. It can be one of page, parameter, request, session, or application. |
key |
The key specifies additional values that should be used when evaluating whether to cache the values contained within the tag. |
async |
If this parameter is true, the cache will be updated asynchronously if possible. |
size |
This parameter determines the maximum size of the cache. If set to -1, it is unlimited. Otherwise, an LRU scheme is used to maintain the cache. |
vars |
This parameter specifies a set of scoped variables that should be cached along with the contents of the cache tag, and made available to the rest of JSP after execution of the tag. |
flush |
If this parameter is set to true, the cache is flushed. |
2.4.1.2 The process tag
The process tag allows you to customize the flow control within a JSP page using query parameters supplied to it. You can configure the tag to include the body based on the following:
- The existence (or absence) of a query parameter (the value of the name attribute defaults to submit, if it isn't specified):
name="foo"> notname="foo">
- A condition that a specific parameter has a particular value (or doesn't have a specific value):
Clearly, process tags provide a simple, declarative way of including/excluding JSP portions.
2.4.1.3 The repeat tag
The repeat tag allows you to repeatedly evaluate the body of a tag, while iterating over the elements in a collection. The tag supports all kinds of collections arrays, vectors, enumerations, JDBC result sets, hash-table keys, etc. The set attribute allows you to specify the collection that will be used to iterate over. The body of the tag will be evaluated for each iteration, using the current element of the configured set. Let's look at few examples of how you can use the repeat tag:
- Display the details of the first 10 users:
" type="com.foo.bar.AUser" count="10"> <%--print details of each user--%> Username: <%= user.getUsername( ) %> Full Name: <%= user.getFullname( ) %> DOB: <%= user.getDob( ) %>
- List all product items in an HTML dropdown:
"> <%--print all products--%><%= product %>
The id attribute defines the name of the object that holds a reference to the element of the set during each iteration. You can specify the type of each element in the collection using the type attribute. By default, the repeat tag expects the type of each element to be String. You also can specify a count attribute, which forces the tag to iterate only over the first count entries.
2.4.2 Building Tag Libraries for EJBs
WebLogic Server provides a tool that generates a tag library from an EJB JAR file one for each EJB in the JAR file. The custom tags in the library provide an easy, elegant way for invoking methods on the enterprise bean. Take, for example, the following remote interface for a session bean:
public interface User extends javax.ejb.EJBObject { public AUser[] list(int realmid) throws java.rmi.RemoteException; public boolean add(int realmid, AUser user) throws java.rmi.RemoteException; public boolean update(int realmid, AUser user) throws java.rmi.RemoteException; public boolean delete(int realmid, String userid) throws java.rmi.RemoteException; }
Using the EJB-to-JSP integration tool, you can generate a tag library that is custom-made for the session bean. The tag library will contain a tag for each method, so you can invoke the EJB from within a JSP page as follows:
<% taglib uri="/WEB-INF/user-tags.tld" prefix="user" %> List Users: <%-- value of _return attribute is the scripting variable that will hold the return value for the EJB method --%> Username: <%= user.getUsername( ) %> Full Name: <%= user.getFullname( ) %> DOB: <%= user.getDob( ) %>
The attributes for the tags correspond to the parameters for the EJB method call. The tag handlers for the custom tags provide the implementation for the actual EJB invocations. Because the custom tag hides away all the messy details of invoking an EJB method, the resulting JSP is clean and elegant. The EJB-JSP integration tool supports tag libraries for session beans (stateful and stateless) and for entity beans.
2.4.2.1 The ejb2jsp tool
You can run the EJB-to-JSP integration tool in graphical mode as follows:
java weblogic.servlet.ejb2jsp.gui.Main
Initially, no project files are loaded, so you need to create a new ejb2jsp project by choosing an EJB JAR file. Once you have created an ejb2jsp project, you can modify the project settings, save the project, and reload ejb2jsp projects created earlier. The structure of the tag library is fairly straightforward:
- The ejb2jsp tool inspects the EJB JAR file to determine the type of the EJB, home and bean interfaces, and the JNDI name needed to look up the EJB home object.
- A custom tag is generated for each remote method of the EJB. Tag implementation consists of the tag handler and tag-extra info classes.
- The EJB specification allows an EJB home interface to declare methods that are neither create( ) nor find( ) methods. The ejb2jsp tool generates custom tags for these methods as well. By default, the tool adds home- prefixes to the names for custom tags associated with EJB home methods.
You can use the Project Build Options panel to configure how the ejb2jsp tool will generate the associated tag library. In fact, you must specify the following items:
- The Java compiler to be used during the build process (defaults to javac)
- Additional compilation flags for the compiler
- How you want the tag library to be built (as a tag library JAR under the /WEB-INF/lib folder, or in the directory format, which is where the tag classes go under the /WEB-INF/classes and the TLD file goes in the /WEB-INF folder)
- The package name for the tag handler classes
- The full path of the document root for the web application
- The locations for the TLD file and classes folder (if you're building the project in directory format)
- A location for the tag library JAR (if your tag library will be packaged in a JAR)
- A temporary folder needed during the build process
When you create a new ejb2jsp project using the selected EJB JAR file, the ejb2jsp tool cannot generate the tags based only on information acquired from introspecting the bean interface classes. It needs the source for the EJB classes as well, before it can assign meaningful names for the tag attributes. You can adjust the source path for the EJB JAR under the Project Build Options panel. By default, the ejb2jsp tool assumes that the source files are in the same folder that contains the EJB JAR file. Once you have set the source path, you can select File/Resolve Attributes to resolve the tag attribute names to method parameter names. You can build the tag library only after you have meaningful names for all tag attributes.
2.4.2.2 Resolving conflicts
The ejb2jsp tool tries to resolve attribute names based on the EJB source and compiled classes. Despite this, a project may generate errors or conflicts while building the tag library. This may happen for several reasons:
- The ejb2jsp project is missing important build settings, such as a Java compiler or an invalid location for the web application. Make sure you have specified all the build options needed to generate the tag library.
- The ejb2jsp project contains duplicate tag names because the particular bean interface declares one or more overloaded methods (i.e., methods with the same name but different signatures). You can resolve this in one of two ways:
- Rename the duplicate tag.
- Disable the duplicate tag so that it doesn't participate in the build process.
- A custom tag has duplicate attribute names. This can happen when a method accepts multiple arguments with the same name. You must ensure that every tag has unique attribute names within its definition.
It's perfectly acceptable for two tags to have an attribute with the same name; however, each attribute within a tag must have a unique name.
- A custom tag has meaningless attribute names such as arg0 and arg1. This can happen when the ejb2jsp tool is unable to generate meaningful names after parsing the EJB source files. In such a case, you need to manually supply valid attribute names for the affected custom tags.
Once you have generated the tag library, you can save the current project for later use. You even can configure certain attributes of the custom tag to accept default values. The ejb2jsp tool allows you to set the default value for an attribute in two ways:
- By specifying a simple expression that evaluates to the value of the attribute.
- By supplying a method body that returns a value for the attribute. The method will be embedded within the tag handler for the JSP, so it will have access to the pageContext for the enclosing JSP page.
Attributes with default values need not be specified when their associated custom tag is used in a JSP page.
2.4.2.3 Custom tags for stateful beans and entity beans
In a typical scenario involving stateful beans or entity beans, a client looks up the bean in the JNDI tree and acquires a reference to the EJB's home interface; it then invokes multiple methods on the bean instance. The custom tags generated for the enterprise bean preserve the same semantics. Custom tags corresponding to methods of the bean's remote interface must be nested within the tag associated with the find( ) or create( ) method of the bean's home interface. So, all EJB methods are invoked using the bean instance created (or found) by the enclosing create (or find) tag. WebLogic's JSP container generates a runtime exception if the EJB method tag is not enclosed within the tag of one of the EJB's home methods.
Consider the following EJB code:
/** bean home interface */ public interface UserHome extends EJBHome { public User create(String userid, String fullname, String username, String password, boolean alive); public User findByPrimaryKey(String userid); public Collection findDeadUsers( ); } /** bean remote interface */ public interface User extends EJBObject { public String getUserID( ); public String getFullName( ); public void changePassword(String oldpw, String newpw); }
After generating the tag library, you can invoke the entity bean from a JSP page as follows:
<% taglib uri="/WEB-INF/user-ejb.tld" prefix="user" %> useruserid") %>" fullname="<%= request.getParameter("fullname") %>" username="<%= request.getParameter("username") %>" password="<%= request.getParameter("password") %>" alive="<%= true %>" _return="user"> " newpw="<%= request.getParameter("newpw") %>" /> <%= user.getFullName( ) %>: Your password has been successfully changed.
The _return attribute in the home-create tag determines the name of the page variable that holds a reference to the newly created (or found) bean instance. Entity bean finder methods will typically return a collection of EJB instances that match the select criteria. If a home tag for an entity bean returns a collection of EJB instances, the body of the tag will be evaluated for each item in the collection. In this case, the _return attribute for the find tag corresponds to the bean instance used in the current iteration. The following example generates an HTML list of all deceased users:
All Deceased Users:
- User <%= user.getFullName( ) %> is dead!
The ejb2jsp tool is useful for generating reusable tag libraries for your enterprise beans. It allows for rapid prototyping of JSP pages and provides a quick way for testing EJB functionality. Custom tags for the EJB methods hide all the details of invoking the bean.