Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
There exists a large body of legacy enterprise applications built around existing messaging products. Given this fact, the JMS architects decided it was more important to allow enterprise Java developers to develop applications that worked within the context of an existing messaging infrastructure than to try to get them to adopt an entirely new product. Of course, developers should be able to create applications without creating additional dependencies on any particular vendor -- thus the JMS spec would be vendor neutral but compatible with existing products.
I've decided to create an implementation of the JMS API in Java for two reasons:
I'll begin by presenting the JMS API as it would appear to someone creating an implementation -- that is, as it would appear from the inside.
But I need to share with you one caveat before I begin.
While the JMS API isn't the most complicated of the Java Enterprise APIs, it isn't the least complicated, either. Due to time and space constraints, I haven't made a heroic effort to implement the entire JMS API Specification. I have, however, taken the time to implement a workable subset. Just to be on the safe side, I'll let you know where my implementation comes up short.
You might find it useful to begin with a refresher. Last month I built the classes that implemented the basic underlying functionality of a message service and I presented the basic philosophy behind the JMS API. If you already feel comfortable with that material, then please continue.
Recall that the elements of the JMS API are divided into two domains, each representing one of the two leading models of messaging provided by existing messaging products. The two models are the point-to-point model and the publish/subscribe model.
While the behavior of the classes within each domain differ, their APIs are nearly identical. It's the APIs and their use that we're interested in this month.
If you glance at the relationship between the point-to-point and publish/subscribe interfaces, you'll see what I mean.
| Point-to-point | Publish/subscribe | Parent interface |
| Queue | Topic | Destination |
| QueueConnectionFactory | TopicConnectionFactory | ConnectionFactory |
| QueueConnection | TopicConnection | Connection |
| QueueSession | TopicSession | Session |
| QueueSender | TopicPublisher | MessageProducer |
| QueueReceiver | TopicSubscriber | MessageConsumer |
The first column lists the principle interfaces that define the point-to-point half of the API. The second column lists the principle interfaces that define the publish/subscribe half of the API. The third column lists the parent interfaces from which both the point-to-point and the publish/subscribe interfaces inherit. Note how similar the two domains are from the standpoint of these interfaces.
Since the two APIs are nearly identical, you can get a good feel for the use of both interfaces by looking at either.
The Destination, Queue, and Topic interfaces represent administered objects. Administered objects are created by an administrator and are registered with a directory. They represent globally accessible
resources. In this case, they are used to encapsulate the identity (or address) of a message destination such as a queue or
a topic. They are not themselves a destination. They provide a platform-independent way to encapsulate provider-specific addresses.
Destination objects support concurrent use.
The following code demonstrates how the Queue interface and associated implementation class Queue_Impl are implemented. The code for the Topic interface is nearly identical.
First the Queue interface:
public
interface Queue
extends Remote
{
public
String
getQueueName()
throws RemoteException;
}
Then the Queue_Impl interface:
public
class Queue_Impl
extends UnicastRemoteObject
implements Queue
{
private String _stringQueueName = null;
public
Queue_Impl(String stringQueueName)
throws RemoteException
{
_stringQueueName = stringQueueName;
}
public
String
getQueueName()
throws RemoteException
{
return _stringQueueName;
}
public
int
hashCode()
{
return _stringQueueName.hashCode();
}
public
boolean
equals(Object object)
{
return object.equals(_stringQueueName);
}
}
The ConnectionFactory, QueueConnectionFactory, and TopicConnectionFactory interfaces represent administered objects. They encapsulate a set of configuration parameters that have been defined by an administrator. A client uses a ConnectionFactory to create a Connection with a JMS provider. They simplify the administration of a message service in a large-scale enterprise setting. ConnectionFactory objects support concurrent use.
Since our implementation has no interesting administrative infrastructure, the only method implemented is the method that returns a connection. The following interface and implementation classes illustrate how this looks within the queue domain. Once again, the topic source code is nearly identical.
First the QueueConnectionFactory interface:
public
interface QueueConnectionFactory
extends Remote
{
public
QueueConnection
createQueueConnection()
throws RemoteException;
}
Then the QueueConnectionFactory_Impl interface:
public
class QueueConnectionFactory_Impl
extends UnicastRemoteObject
implements QueueConnectionFactory
{
public
QueueConnectionFactory_Impl()
throws RemoteException
{
}
public
QueueConnection
createQueueConnection()
throws RemoteException
{
return new QueueConnection();
}
}
The Connection, QueueConnection, and TopicConnection interfaces represent an active connection to a JMS provider. They are the conduit through which communication flows. A client
uses them to create a Session with the JMS provider. They provide a single point for all communication activities -- thus enabling resource (such as connection)
pooling as well as authentication and security. Connection objects support concurrent use.
The following code illustrates the implementation within the queue domain.
public
class QueueConnection
implements Serializable
{
private Hashtable _hashtable = new Hashtable();
private
HQueue
lookup(Queue queue)
throws MalformedURLException,
NotBoundException,
UnknownHostException,
RemoteException,
IOException
{
HQueue hqueue = null;
if ((hqueue = (HQueue)_hashtable.get(queue)) != null)
{
return hqueue;
}
hqueue = (HQueue)Naming.lookup(queue.getQueueName());
_hashtable.put(queue, hqueue);
return hqueue;
}
void
send(Message message, Queue queue)
throws NotBoundException,
RemoteException,
IOException
{
lookup(queue).send(message);
}
Message
receive(Queue queue)
throws NotBoundException,
RemoteException,
IOException
{
return lookup(queue).receive();
}
public
QueueSession
createQueueSession()
{
return new QueueSession(this);
}
}
The Session, QueueSession, and TopicSession interfaces represent a single threaded context for sending and receiving messages. A client uses them to create one or more
MessageProducers or MessageConsumers. They also provide a factory for creating messages and define a serial order for the messages they consume or produce. Sessions
provide a natural way for clients to organize interactions with a provider.
The following code illustrates an implementation.
public
class QueueSession
implements Serializable
{
private QueueConnection _queueconnection = null;
QueueSession(QueueConnection queueconnection)
{
_queueconnection = queueconnection;
}
void
send(Message message, Queue queue)
throws NotBoundException,
RemoteException,
IOException
{
_queueconnection.send(message, queue);
}
Message
receive(Queue queue)
throws NotBoundException,
RemoteException,
IOException
{
return _queueconnection.receive(queue);
}
public
QueueSender
createSender(Queue queue)
{
return new QueueSender(this, queue);
}
public
QueueReceiver
createReceiver(Queue queue)
{
return new QueueReceiver(this, queue);
}
}
The MessageProducer, QueueSender, and TopicPublisher interfaces represent objects that are used to send messages to a destination.
public
class QueueSender
implements Serializable
{
private QueueSession _queuesession = null;
private Queue _queue = null;
QueueSender(QueueSession queuesession, Queue queue)
{
_queuesession = queuesession;
_queue = queue;
}
public
void
send(Message message)
throws NotBoundException,
RemoteException,
IOException
{
_queuesession.send(message, _queue);
}
}
The MessageConsumer, QueueReceiver, and TopicSubscriber interfaces represent objects that are used to receive messages sent to a destination.
public
class QueueReceiver
implements Serializable
{
private QueueSession _queuesession = null;
private Queue _queue = null;
QueueReceiver(QueueSession queuesession, Queue queue)
{
_queuesession = queuesession;
_queue = queue;
}
public
Message
receive()
throws NotBoundException,
RemoteException,
IOException
{
return _queuesession.receive(_queue);
}
}
I've provided the complete source code for those readers who can't sleep until they see it all. For instructions on downloading, extracting, setting up, and running the code, please read the accompanying sidebar.
With the close of this month's column, I begin a short vacation. After over two years of writing, it's time to step back and reorient myself. In the two years since I started writing this column, Java has grown from a fledgling to an adult. It now seems poised to bury itself within the heart of the enterprise. When I return, I plan to continue to show you how to use the Java platform to solve your problems. Until then.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq