| home / programming / tapestry / 1 | [previous][next] |
|
|
The Virtual Library makes use of Tapestry features to organize the application sensibly. This organization takes the form of specific responsibilities for the engine, the Visit object, and the Global object. The Global object is similar to the Visit object but is shared by all sessions. Figure 10.2 shows how these central objects are stored on the server. The engine and the Visit object are stored within the HttpSession as attributes; there will be many engine and Visit instances, one pair for each concurrent user of the application.
The Global object, on the other hand, is global to (and shared by) all engine instances, stored as a ServletContext attribute. In the Virtual Library, the Global object is responsible for performing Java Naming and Directory Interface (JNDI) lookups on behalf of the engine, locating home interfaces for the Operations and BookQuery EJBs. This is an excellent use for the Global object, since it can cache references to the EJB home interfaces. JNDI lookups of home interfaces are a notoriously slow operation, so caching the results for quick access is an effective performance enhancement.
As you’ll see shortly, locating these lookup operations centrally leads to not only a better-performing application but also a more robust one. Having a single, authoritative location for JNDI lookups means that there will be a single, autho¬ritative approach to handling JNDI lookup errors. It also provides a single place to manage recovery from RemoteExceptions. A traditional servlet application can have JNDI lookups and cached home interface references scattered across many servlets and JSPs, but Tapestry makes it easy to centrally locate these important operations.

Figure 10.2 The engine is responsible for common EJB operations.
The Visit object is responsible
for authentication. The Global object, which is responsible for
JNDI lookup, is a singleton, shared
by all engines.
The Visit object is responsible for authentication. It simply
tracks the ID of the currently logged-in user. This ID is an Integer,
the primary key type of all three entities used by the Virtual Library (Person,
Book, and Publisher). Additionally, the Visit object retains the
matching instance of Person, so that full details about the user
(such as name, email address, and administrative privilege) can be made available
to the application.
The majority of interaction between the two layers involves the Operations
bean. This is a stateless session bean, and it consists of a number of methods
for creat¬ing, reading, and updating back-end data. The application uses
a subclass of the BaseEngine class. The subclass has extensions
for obtaining a reference to the Operations bean’s remote
interface as needed, as well as implementing several of the most common operations,
such as reading a Person value object corresponding to a person
ID.
As with JNDI lookups in the Global object, having operations
implemented in the engine centralizes handling of, and recovery from, remote
exceptions. This leads to much greater application stability, especially during
redeployment of the application. In the code excerpts that follow, you’ll
see how the engine provides support for retry loops used in every location where
remote object access occurs.
The specific requirements for the Visit object in the Virtual
Library are that it track the following:
Listing 10.1 shows how this class is implemented.
| Listing 10.1 Visit.java: Java class for the Virtual Library Visit object |
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.vlib.ejb.Person;
public class Visit implements Serializable
{
private static final long serialVersionUID =
8589862098677603655L;
private transient Person _user; ![]()
private Integer _userId;
private Timestamp _lastAccess;
public Timestamp getLastAccess()
{
return _lastAccess;
}
public Person getUser(IRequestCycle cycle)
{
if (_user != null)
return _user;
if (_userId == null)
return null;
VirtualLibraryEngine vengine =
(VirtualLibraryEngine)cycle.getEngine();
_user = vengine.readPerson(_userId);
return _user;
}
public Integer getUserId()
{
return _userId;
}
public void setUser(Person value)
{
_lastAccess = null;
_user = value;
_userId = null;
if (_user == null)
return;
_userId = _user.getId();
_lastAccess = _user.getLastAccess();
}
public boolean isUserLoggedIn()
{
return _userId != null;
}
public boolean isUserLoggedOut()
{
return _userId == null;
}
public boolean isLoggedInUser(Integer id)
{
if (_userId == null)
return false;
return _userId.equals(id);
}
public void clearCache()
{
_user = null;
}
}
| home / programming / tapestry / 1 | [previous][next] |
Created: March 27, 2003
Revised: May 8, 2004
URL: http://webreference.com/programming/tapestry/1