JEgg is a framework designed to reduce the complexity and cost of developing robust, multithreaded Java applications. Simpler code is faster to get into production, and saves development dollars.
Effective use of the Active Object design pattern, in which each active object has its own logical thread of execution, can facilitate the development of simpler, more robust multithreaded applications. JEgg provides a framework that supports this pattern and takes it a step further by supporting asynchronous, message-based communication between active objects.
The message-oriented aspect is essential to writing better code. Passing a message to an object is much safer than calling a method on it, and message-oriented objects are intrinsically loosely coupled and highly cohesive. Morever, the restriction to message-passing active objects is really no restriction at all; any Java object can be a message. The central difference is that an object's public interface is really the set of message types that it can "handle" instead of its public methods.
Multithreaded development in terms of JEgg active objects is much simpler
than "straight Java" because the framework allows each active object to
be implemented as if it
were executing on its own distinct thread, without using the
Design of a complex application is never easy, but the execution independence of JEgg active objects, together with one-at-a-time message handling semantics, dramatically simplifies multithreaded application development without reducing the sophistication that you require. In fact, higher levels of sophistication become cost effective because your code is more focused.
The essential steps in a constructing a JEgg-based application are:
Designing an application in terms of messaging active objects may require you to think a little differently, but it should quickly feel natural since it's completely object-oriented. Additionally, the JEgg framework includes facilities to make the implementation easy so that you spend more time write application code and much less time writing "infrastructure" and error-handling code. Error handling is always necessary - no framework can avoid that - but the error handling that's left for you to implement should be at the application level.
JEgg objects are called eggs because their external aspect is featureless, like an egg. They have essentially no program API (public methods) because they aren't needed - eggs only communicate by sending and receiving messages. Each message is delivered by the framework to the egg it's addressed to and handled by your application logic. One-at-a-time message semantics is enforced by the framework which ensures that a given egg is not delivered its next message until it has finished handling the current message. The framework provides a way for an egg to send a message in response to the current message without having to explicitly reference the egg that sent the current message being handled. Also, a mechanism is supported to allow message "broadcast" to a group of eggs.
The physical artifacts of a JEgg application are the application eggs, the message types they exchange, and whatever other passive classes your application needs. Relationships between the eggs are expressed not in code but in the JEgg application descriptor which is a simple XML file that essentially enumerates the application eggs and describes which eggs will exchange messages with which other eggs. The framework also allows these relationships to be specified dynamically, or not at all. Eggs can register themselves with a built-in naming service that other eggs can use to look them up in order to send them messages.
The XML descriptor also allows you to assign eggs to one or more message dispatchers. In JEgg parlance, a message dispatcher is called a "basket" (really, what else would you call it?). Sometimes you can put all of your eggs in one basket, in which case they will all execute on the same physical thread, having their messages delivered by the same message dispatcher. jEggs that can take a long time to handle a message should be assigned to their own individual message dispatcher, or basket, but this assignment is made in the application descriptor, not code, so it's easy to change. Often, though, the application will have eggs that execute relatively infrequently, and those eggs can certainly all go in the same basket.
During execution, the message dispatcher assigned to an egg queues incoming
messges for that egg and delivers them one-at-a-time to the egg by using
reflection to deliver a given message to the egg's overloaded
So, where are the threads? They are the message dispatchers that deliver the messages to your eggs, one at a time. Conceptually, each egg executes completely independently of all other eggs, and this dramatically simplifies application design. Behind the scenes, Java threads are assigned to the message dispatchers that deliver messages to the eggs, and the application descriptor allows you to assign eggs to the same dispatcher or a different one. Consequently,