Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E

..pdf
Скачиваний:
41
Добавлен:
24.05.2014
Размер:
6.28 Mб
Скачать

604

 

 

M A S T E R I N G E N T E R P R I S E J A V A B E A N S

Table B.3

Continued

 

 

 

CLASS OR INTERFACE

DESCRIPTION

class javax.naming.Reference

A JNDI Reference is a placeholder for an actual

 

 

 

 

object that is located outside of the JNDI directory

 

 

 

 

tree being parsed. You should store references

 

 

 

 

when you don’t want to serialize and store your

 

 

 

 

Java objects directly, which stores copies of Java

 

 

 

 

objects. You also can use references when an

 

 

 

 

object is not the correct manifestation of the

 

 

 

 

information you want to store in a directory.

 

 

 

 

The Reference class contains two pieces of

 

 

 

 

information: the object factory used to create the

 

 

 

 

real object that the Reference represents and a set

 

 

 

 

of RefAddr objects (described later).

class javax.naming.RefAddr

These objects represent location information about

class javax.naming.BinaryRefAddr

JNDI Reference. Location information can be any

class javax.naming.StringRefAddra

kind of information the corresponding object fac-

 

 

 

 

tory needs to create the actual object. The RefAddr

 

 

 

 

class is the abstract base class. BinaryRefAddr and

 

 

 

 

StringRefAddr extend it. For example, you can store

 

 

 

 

the hostname of a machine on which the actual

 

 

 

 

object is located in a StringRefAddr. You can serial-

 

 

 

 

ize an object’s handle and store it as a BinaryRefAddr.

Interface javax.naming.spi.ObjectFactory

An ObjectFactory is responsible for creating object

 

 

 

 

instances from a given Reference. When you

retrieve a referenceable object from a JNDI tree, an ObjectFactory is called to actually construct the object behind-the-scenes for you.

EJB Design Strategies

JNDI, EJB, and the Singleton Design Pattern

A singleton is a very useful design pattern in software engineering. In a nutshell, a singleton is a single instantiation of a class with one global point of access. Normally, you would create a singleton in Java by using the static keyword when defining a class. However, one restriction of EJB is that you cannot use static fields in your beans. This precludes the use of the singleton design pattern. But we’d still like to use singletons—how can we?

The answer is JNDI. You can use JNDI to store arbitrary objects to simulate the singleton pattern. If all your objects know of a single, well-known place in a JNDI tree where a particular object is stored, they can effectively treat the object as a single instance. You could perform this by binding a serializable RMI remote stub to a single object in a JNDI tree. Any client code that accessed the JNDI tree would get a copy of that remote stub, and each copy would point back to the same object.

Go back to the first page for a quick link to buy this book online!

Understanding the Java Naming And Directory Interface (JNDI) 605

to connect to that remote object, the client needs to hard-code the location of that RMI registry. If that machine changes or if it goes down, your clients need to be redeployed. This is definitely not a suitable situation for a scalable, enterpriseclass deployment.

JNDI’s RMI registry service provider can alleviate this situation. The RMI registry service provider allows you to bind RMI remote objects, or an entire RMI registry’s worth of remote objects, to a JNDI tree. When a client wants to acquire a reference to a remote object, it goes through JNDI rather than connecting through standard means via an RMI naming.lookup().

The RMI registry service provider’s advantage is that it enables clients to be unaware of where exactly your remote objects are located. No physical names of machines are ever used when looking up remote objects. With the RMI registry service provider, you specify a well-known location in a JNDI tree that is the binding point for your remote objects. Clients simply connect to this well-known location via JNDI, rather than hard-coding a specific machine name and going through the RMI naming.lookup(). If a machine goes down, another machine can replace the old machine’s remote objects with a new one in the JNDI tree, yielding a level of fault-tolerance to your deployment. Note that this level of faulttolerance relies on remote objects being activatable, or loaded when needed.

In the EJB world, EJB containers may use the RMI Registry service provider behind the scenes. The service provider allows home objects to be stored and accessed, with clients unaware of their real locations. The RMI Registry service provider is ideally suited for locating EJB Objects.

Let’s take the familiar RMI Flip example we used in Appendix A and convert it to use JNDI.

IFlip.java

First we must define our RMI remote interface, IFlip.java. IFlip is the remote interface for our remote object, which is defined in Flip.java. Client code performs all invocations on the IFlip interface because RMI separates interface from implementation.

The IFlip remote interface hasn’t changed since we introduced it in Appendix A. It’s shown in Source B.5.

Flip.java

Our remote object, Flip.java, is the networked RMI object that implements the remote interface. Flip has changed a bit. It still binds itself to an RMI registry, but now it has an additional method for then binding the RMI registry to a JNDI tree, named JNDIbind(). Source B.6 details the code.

Go back to the first page for a quick link to buy this book online!

606

 

M A S T E R I N G E N T E R P R I S E J A V A B E A N S

package com.wiley.compBooks.roman.jndi.rmi;

import

java.rmi.Remote;

import

java.rmi.RemoteException;

/**

* The interface for the Remote Object that must be invoked on */

public interface IFlip extends Remote {

public int flip(int i) throws Exception, RemoteException;

}

Source B.5 IFlip.java.

package com.wiley.compBooks.roman.jndi.rmi;

import java.util.*; import java.rmi.*;

import java.rmi.registry.*; import java.rmi.server.*; import javax.naming.*;

/**

*Demonstration Remote Object that is bound to an RMI Registry.

*We then bind the RMI Registry to a JNDI tree. The System

*properties must specify the JNDI Initial Context parameters. */

public class Flip extends UnicastRemoteObject implements IFlip {

public static void main(String args[]) throws Exception { if (args.length != 4) {

System.err.println(

"Syntax: Flip <true|false> <host> <port> <dir>"); System.err.println();

System.err.println("true demarcates to start RMI Registry," + " false demarcates to bind to existing one.");

System.err.println("host is the host for RMI Registry.");

System.err.println("port is the port # for RMI Registry.");

System.err.println(

"dir should specify the location of a directory structure."); System.exit(-1);

}

String host = args[1];

int port = new Integer(args[2]).intValue(); Registry reg = null;

Source B.6 Flip.java (continues).

Go back to the first page for a quick link to buy this book online!

Understanding the Java Naming And Directory Interface (JNDI) 607

/*

* If desired, start RMI Registry at specified port */

if (args[0].equals("true")) {

reg = LocateRegistry.createRegistry(port); System.out.println("Connected to existing registry.");

}

/*

* Otherwise, bind to an existing registry */

else {

reg = LocateRegistry.getRegistry(host, port); System.out.println("Successfully created registry.");

}

/*

* Start up our Flip object. It will auto-bind to reg. */

Flip flip = new Flip(reg);

/*

* Now bind all the objects in the RMI Registry to a JNDI tree */

flip.JNDIbind("rmi://" + host + ":" + port, args[3]);

}

/**

*Constructor performs RMI Initialization, binds object to reg,

*and binds reg to JNDI tree.

*/

public Flip(Registry reg) throws Exception {

super();

/*

* Bind our Flip object to the RMI Registry */

reg.rebind("Flip", this); System.out.println("Flip object bound.");

}

/**

* Binds RMI Registry's objects to JNDI tree */

protected void JNDIbind(String RMIURL, String dir) throws Exception {

Properties env = new Properties();

Source B.6 Flip.java (continues).

Go back to the first page for a quick link to buy this book online!

608 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");

env.put(Context.PROVIDER_URL, RMIURL);

/*

*Obtain an initial context

*(should use RMI Registry service provider).

*/

Context ctx = new InitialContext(env);

/*

*Now use our initial context to look up a _different_

*directory structure (the example in the book uses

*LDAP). This will return a context to that other

*directory structure. We can then bind Remote Objects

*or whole RMI Registries to that context.

*/

Context otherCtx = (Context) ctx.lookup(dir);

/*

*Bind the Context containing RMI Registry info to a

*JNDI tree.

*/

otherCtx.rebind("cn=Flip", this);

System.out.println("Successfully bound object to JNDI tree.");

}

public int flip(int i) throws Exception, RemoteException { return i * -1;

}

}

Source B.6 Flip.java (continued).

Notice what JNDIbind() does. It first sets up some environment variables, and it acquires an Initial Context using the RMI Registry service provider. This Initial Context is then used to perform a lookup() operation on a different directory structure. That is, we’re using the RMI Registry service provider’s Initial Context as a springboard to get a handle to an LDAP context. Once we have the LDAP context, we bind our RMI registry to it. The information bound will be used when future clients try to look up the RMI registry later and retrieve the remote objects from it.

Go back to the first page for a quick link to buy this book online!

Understanding the Java Naming And Directory Interface (JNDI) 609

FlipClient.java

Next, we have the client code that wants to use the remote Flip object. Our client has hardly changed, except that now instead of connecting via RMI’s naming.lookup(), it retrieves the remote object via JNDI. The code is listed in Source B.7.

package com.wiley.compBooks.roman.jndi.rmi;

import java.util.*; import java.rmi.*; import javax.naming.*;

public class FlipClient implements Remote {

public static void main (String[] args) {

IFlip flip = null;

/*

* Set the security manager */

try {

System.setSecurityManager(new java.rmi.RMISecurityManager());

}

catch (java.rmi.RMISecurityException exc) { System.err.println("Security violation " + exc.toString()); System.exit(-1);

}

/*

*Get a handle to a remote Flip object. We do this via

*a JNDI lookup, using the RMI Registry service provider.

*/

try { /*

* Get initial context */

Context ctx = new InitialContext(System.getProperties());

/*

*Get the object from RMI Registry bound to JNDI

*tree. The RMI Registry service provider

*automatically looks into the registry that is

Source B.7 FlipClient.java (continues).

Go back to the first page for a quick link to buy this book online!

610 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

*bound to this JNDI entry. It then returns the

*correct object.

*/

Remote remoteObject = (Remote) ctx.lookup("cn=Flip");

/*

*Perform a quick check to make sure the object is

*of the expected IFlip interface type

*/

if (remoteObject instanceof IFlip) { flip = (IFlip) remoteObject;

}

else {

throw new Exception(

"Bad object returned from remote machine");

}

}

catch (Exception e) {

System.err.println("Error: " + e.toString());

System.exit(-1);

}

/*

* Print the result of flipping 5. */

try { System.err.println(flip.flip(5));

}

catch (RemoteException e) {

System.err.println("Remote error: " + e.toString());

}

catch (Exception e) {

System.err.println("Logical Error: " + e.toString());

}

}

}

Source B.7 FlipClient.java (continued).

Only a few lines have changed. The line that used to be:

Remote remoteObject = Naming.lookup(targetMachine);

Has now evolved into:

Context ctx = new InitialContext(System.getProperties());

Remote remoteObject = (Remote) ctx.lookup("cn=Flip");

The difference is that now we don’t hard-code the targetMachine variable.

Go back to the first page for a quick link to buy this book online!

Understanding the Java Naming And Directory Interface (JNDI) 611

Running the Example

First, let’s run the Flip server. This will register the Flip Remote Object with the RMI Registry, then bind it to an LDAP directory:

java com.wiley.compBooks.jndi.rmi.Flip.Flip true edro 1099 ldap://

louvre:389/o=Airius.com

Connected to existing registry.

Flip object bound.

Successfully bound object to JNDI tree.

Now, let’s run the FlipClient. This will connect to the LDAP server, retrieve the Remote Object and compute the inverse of “5”:

java -Djava.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory -

Djava.naming.provider.url=ldap://louvre:389/o=Airius.com

com.wiley.compBooks.jndi.rmi.Flip.FlipClient

-5

Notice that the client code is using the LDAP Context Factory and is unaware of the RMI Registry service provider being used behind the scenes.

In summary, every operation in RMI naming has been cloned in JNDI. JNDI generalizes RMI naming and is able to find arbitrary resources. This is why JNDI is the preferred naming mechanism for enterprise-level deployments.

Summary

In this appendix, you have acquired a breadth of understanding about JNDI. You are now aware of the many intricacies of the JNDI API, and you have seen the File System, LDAP and RMI registry service providers in action. This will give you a solid foundation for using JNDI with EJB, and it will pave the way for you to do serious development with JNDI in the future.

We started this appendix with the basics of naming and directory concepts. You learned about everything from an atomic name to a federated namespace. We then examined the specifics of javax.naming, and we wrote an interactive example that browsed a directory structure.

We then approached JNDI from the EJB perspective. We saw how it was possible to bind serializable Java objects to a JNDI tree while learning a little about how JDBC and JNDI could be used together for robust database access.

Finally, we then saw how JNDI and EJB relate and the many uses JNDI could have in an EJB environment. We concluded with a hands-on example of JNDI as a lookup mechanism for RMI remote objects, which demonstrated the RMI Registry service provider in action.

Go back to the first page for a quick link to buy this book online!

612 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

By reading this appendix, you should have a solid understanding for how naming and directory concepts can be applied globally in an enterprise. Ideally, all Java-based naming operations, whether they involve remote objects, printers, JDBC resources, physical machines, enterprise beans, or Web pages, should use JNDI. Interested readers who want to learn more about JNDI should consult the following references:

The JNDI Tutorial. This tutorial is one of many tutorials available for free on the Sun Microsystems Web site. The JNDI Tutorial is very broad in scope, and it will address almost all of your JNDI needs.

The JNDI Specification. The specification defines the core of JNDI. This is a bit more technical, but it should not be tough now that you’ve read this appendix.

JNDI is leveraged even further in the EJB 1.1 specification, including home objects, resource factories, and references to enterprise beans. We cover EJB 1.1 in Appendix D.

Go back to the first page for a quick link to buy this book online!

A P P E N D I XC

Understanding the Extensible

Markup Language (XML)

his appendix takes a look at the Extensible Markup Language (XML)—a su- Tperb structured document format standard that businesses are using to exchange business data. XML complements EJB nicely as well; in fact, the EJB 1.1 speci-

fication uses XML as a document format for deployment descriptors.

By reading this appendix, you will learn the following:

■■Why businesses need XML

■■The core concepts behind XML programming

■■How EJB and XML are related (which we’ll expand upon in Appendix D, covering EJB 1.1)

XML is an extremely important technology for the Internet, and it is destined to become the de-facto standard for structuring document content. If you already know XML, feel free to skip to the second half of this appendix, where we discuss how XML and EJB are related. Otherwise, read on, and we will explain XML from the ground-up.

This appendix explains enough XML for you to begin programming with EJB 1.1. For a full tour of XML, see the book’s accompanying Web site for links to external resources.

613

Go back to the first page for a quick link to buy this book online!