| Sign In/My Account | View Cart |
|
Java Enterprise Breakthroughs, Part 1by Jim Farley, coauthor of Java Enterprise in a Nutshell, 2nd Edition05/22/2002 |
The second edition of Java Enterprise in a Nutshell includes an enormous amount of new material, reflecting the significant milestones that enterprise Java has achieved since the first edition was published in 1999. These milestones include the release of the full J2EE 1.2 spec in December 1999, the release of the J2EE 1.3 spec in the summer of 2001, the recent wave of Java support for Web services, and numerous other achievements in between.
In this article, I'll highlight just a few of the powerful new features found in the Java enterprise APIs that are described in the second edition.
As of JDK 1.3, the Java Naming and Directory Interface (JNDI) was added as
a standard part of the core Java environment. (Previously, it was available separately
as a "standard extension" API.) In this release, the JNDI API was
also extended to include support for event notification. Some naming and directory
services, such as LDAP, are capable of issuing notifications of changes to registered
listeners. The JNDI API provides support for this in the form of the javax.naming.event
sub-package.
If your JNDI provider supports event notification, its Context
or DirContext implementation will extend the javax.naming.event.EventContext
and/or javax.naming.event.EventDirContext interfaces. If you're
using the LDAP provider supplied with either JDK 1.3 or 1.4 to connect to an
LDAP server, for example, you can cast a Context generated from
this provider to an EventDirContext:
// Obtain Context from LDAP provider through a lookup
Context ctx = (Context)initCtx.lookup("ou=people");
EventDirContext evCtx = (EventDirContext)ctx;
The EventContext and EventDirContext interfaces provide
the additional functionality needed to register event listeners with the underlying
JNDI provider. All JNDI event listeners implement the javax.naming.event.NamingListener
interface. JNDI provides two subclasses of this interface: NamespaceChangeListeners,
to listen for changes in the namespace of the JNDI provider, and ObjectChangeListener,
to listen for changes to the actual objects stored in the JNDI provider.
To receive notifications of changes in a naming/directory service, you simply
implement a concrete subclass of one or both of these types of NamingListeners
and register them with a Context obtained from the JNDI provider.
If, for example, you wanted to log a message each time the namespace changed,
you could implement a NamespaceChangeListener such as the following:
import javax.naming.*;
import javax.naming.event.*;
public class NSChangeLogger implements NamespaceChangeListener {
// Default constructor
public NSChangeLogger() {}
// Callback for object addition events
public void objectAdded(NamingEvent ev) {
Binding b = ev.getNewBinding();
System.out.println("--> ADD: Object of type " + b.getClassName() +
" added at binding \"" + b.toString() + "\"");
}
// Callback for object removal events
public void objectRemoved(NamingEvent ev) {
Binding b = ev.getOldBinding();
System.out.println("--> REMOVE: Object of type " + b.getClassName() +
" removed from binding \"" + b.toString() + "\"");
}
// Callback for object rename events
public void objectRenamed(NamingEvent ev) {
Binding bNew = ev.getNewBinding();
Binding bOld = ev.getOldBinding();
System.out.println("--> RENAME: Object of type " + bNew.getClassName() +
" renamed from binding \"" + bOld.toString() +
"\" to binding \"" + bNew.toString() + "\"");
}
// Callback for errors in the naming service
public void namingExceptionThrown(NamingExceptionEvent ev) {
System.out.println("--> ERROR: An error occurred in the naming service:");
ev.getException().printStackTrace();
}
}
Each method on our NSChangeLogger is a callback that will be invoked
by the JNDI provider whenever a corresponding event occurs in the naming/directory
service. To register this listener with the JNDI provider, you invoke the addNamingListener()
method on either the EventContext or EventDirContext interface.
For example, to log namespace change events for any objects in the "people"
branch of an LDAP server that belongs to the organization "O'Reilly and
Associates", you might register one of our NSChangeLogger
listeners like so:
EventDirContext evCtx = (EventDirContext)initCtx.lookup("ou=people");
NSChangeLogger nsLogger = new NSChangeLogger();
evCtx.addNamingListener(“o=O'Reilly and Associates”,
EventContext.SUBTREE_SCOPE, nsLogger);
As of JDK 1.4, Java IDL (the standard implementation of the Java binding of
the CORBA specifications) supports the Interoperable Naming Service (INS) extensions
to the CORBA Naming Service. These extensions were added circa CORBA 2.3.1,
and they provide new, simpler approaches for clients to locate CORBA objects
registered in CORBA Naming Services. CORBA has always provided a scheme for
obtaining a "stringified object reference" for a registered object,
using the object_to_string() method on the ORB interface:
// Initialize the ORB
ORB myORB = ORB.init(...);
// Initialize a remote object and connect it to the ORB
org.omg.CORBA.Object myRmtObject = . . .;
// Get a stringified reference to the object and print it
String ior = myORB.object_to_string(myRmtObject);
System.out.println("The IOR for the object is:\n" + ior);
Running this example code (with the missing bits filled in, of course) will generate output like the following:
The IOR for the object is:
IOR:000000000000002349444c3a6f7265696c6c792f6a656e742f636f7262612f416
3636f756e743a312e300000000000010000000000000068000102000000000a313237
2e302e302e3100046600000021afabcb0000000020363f810b0000000100000000000
000000000000400000000030000000000000100000001000000200000000000010001
00000002050100010001002000101090000000100010100
A client can generate a remote reference to this CORBA object by passing this
"IOR:" string into the string_to_object() method on its
ORB:
Object rmtRef = clientORB.string_to_object("IOR:000...");
INS supports simpler, human-readable object URLs, similar to the URLs used
to locate RMI objects stored in an RMI registry. If a CORBA object is registered
in a CORBA Naming Service under the name "myObject" on a server named
inshost.org, for example, a client can obtain a remote reference
to this object by constructing a corresponding corbaname URL:
Object rmtRef2 = clientORB.string_to_object("corbaname:iiop:inshost.org#myObject");
Among other things, these human-readable object URLs can be much more easily assembled in a programmatic way, based on the component parts (protocol, host, object name). These simplified URLs are also easier to manage and distribute than the more complicated IORs. It also helps a great deal in eyeballing configuration parameters for distributed systems -- manually checking an IOR for correctness is akin to reading the machine code for an operating system kernel to find a bug.
Pages: 1, 2 |