Developing the Cabin bean and the TravelAgent bean should have raised your confidence, but it should also have raised a lot of questions. So far, we have glossed over most of the details involved in developing, deploying, and accessing these beans. In this chapter and the ones that follow, we will slowly peel away the layers of the Enterprise JavaBeans onion to expose the details of EJB application development.
This chapter focuses specifically on the client's view of an EJB system. The client, whether it is an application or another bean, doesn't work directly with the beans in the EJB system. Instead, clients interact with a set of interfaces that provide access to beans and their business logic. These interfaces consist of the JNDI API and an EJB client-side API. JNDI allows us to find and access beans regardless of their location on the network; the EJB client-side API is the set of interfaces and classes that a developer uses on the client to interact with beans.
The best approach to this chapter is to read about a feature of the client view and then try to use that feature in the Cabin bean and TravelAgent bean client applications you worked with in Chapter 4, "Developing Your First Enterprise Beans". This will provide you with hands-on experience and a much clearer understanding of the concepts. Have fun, experiment, and you'll be sure to understand the fundamentals.
In Chapter 4, "Developing Your First Enterprise Beans", the client application started by creating an InitialContext, which it then used to get a remote reference to the homes of the Cabin and TravelAgent beans. The InitialContext is part of a larger API called the Java Naming and Directory Interface ( JNDI). We use JNDI to look up an EJB home in an EJB server just like you might use a phone book to find the home number of a friend or business associate.
JNDI is a standard Java extension that provides a uniform API for accessing a wide range of services. In this respect, it is somewhat similar to JDBC, which provides uniform access to different relational databases. Just as JDBC lets you write code that doesn't care whether it's talking to an Oracle database or a Sybase database, JNDI lets you write code that can access different directory and naming services, like LDAP, Novell Netware NDS, CORBA Naming Service, and the naming services provided by EJB servers. EJB servers are required to support JNDI by organizing beans into a directory structure and providing a JNDI driver, called a service provider, for accessing that directory structure. Using JNDI, an enterprise can organize its beans, services, data, and other resources in a large virtual directory structure, which can provide a very powerful mechanism for binding together normally disparate systems.
The great thing about JNDI is that it is virtual and dynamic. JNDI is virtual because it allows one directory service to be linked to another through simple URLs. The URLs in JNDI are analogous to HTML links. Clicking on a link in HTML allows a user to load the contents of a web page. The new web page could be downloaded from the same host as the starting page or from a completely different web site--the location of the linked page is transparent to the user. Likewise, using JNDI, you can drill down through directories to files, printers, EJB home objects, and other resources using links that are similar to HTML links. The directories and subdirectories can be located in the same host or can be physically hosted at completely different locations. The user doesn't know or care where the directories are actually located. As a developer or administrator, you can create virtual directories that span a variety of different services over many different physical locations.
JNDI is dynamic because it allows the JNDI drivers (a.k.a. service providers) for specific types of directory services to be loaded at runtime. A driver maps a specific kind of directory service into the standard JNDI class interfaces. Drivers have been created for LDAP, Novell NetWare NDS, Sun Solaris NIS+, CORBA Naming Service, and many other types of naming and directory services. When a link to a different directory service is chosen, the driver for that type of directory service is automatically loaded from the directory's host, if it is not already resident on the user's machine. Automatically downloading JNDI drivers makes it possible for a client to navigate across arbitrary directory services without knowing in advance what kinds of services it is likely to find.
JNDI allows the application client to view the EJB server as a set of directories, like directories in a common filesystem. After the client application locates and obtains a remote reference to the EJB home using JNDI, the client can use the EJB home to obtain a remote reference to a bean. In the TravelAgent bean and the Cabin bean, which you worked with in Chapter 4, "Developing Your First Enterprise Beans", you used the method getInitialContext() to get a JNDI InitialContext object, which looked as follows:
public static Context getInitialContext() throws javax.naming.NamingException { Properties p = new Properties(); // ... Specify the JNDI properties specific to the vendor. return new javax.naming.InitialContext(p); }
An initial context is the starting point for any JNDI lookup--it's similar in concept to the root of a filesystem. The way you create an initial context is peculiar, but not fundamentally difficult. You start with a properties table of type Properties. This is essentially a hash table to which you add various values that determine the kind of initial context you get.
Of course, as mentioned in Chapter 4, "Developing Your First Enterprise Beans", this code will change depending on how your EJB vendor has implemented JNDI. For Gemstone/J, getInitialContext() might look something like this:
public static Context getInitialContext() throws Exception { Properties p = new Properties(); p.put(com.gemstone.naming.Defaults.NAME_SERVICE_HOST,"localhost"); String port = System.getProperty("com.gemstone.naming.NameServicePort", "10200"); p.put(com.gemstone.naming.Defaults.NAME_SERVICE_PORT, port); p.put(Context.INITIAL_CONTEXT_FACTORY,"com.gemstone.naming.GsCtxFactory"); return new InitialContext(p); }
For BEA's WebLogic Server, this method would be coded as:
public static Context getInitialContext() throws Exception { Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.T3InitialContextFactory"); p.put(Context.PROVIDER_URL, "t3://localhost:7001"); return new InitialContext(p); }
For a more detailed explanation of JNDI, see O'Reilly's Java Enterprise in a Nutshell, by David Flanagan, Jim Farley, William Crawford, and Kris Magnusson.
Copyright © 2001 O'Reilly & Associates. All rights reserved.