|
|||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
Egg | The interface that must be implemented by each egg. |
EggContext | The execution context of an egg. |
Message | Used to wrap an application message that is being sent from one egg to another. |
Port | An egg message port. |
Class Summary | |
EggBase | A convenience base class for a concrete egg implementation. |
Exception Summary | |
PortException | Exception raised if a port can not accept a message for any reason. |
UnableToInitializeException | Raised by an egg that fails to initialize when the framework invokes
the egg's init() method. |
The main JEgg package
The intent of JEgg is to provide an application development framework that directly supports the Active Object pattern in such a way that multithreaded applications can be implemented without the application code having to manage (create, assign, destroy, or monitor) any physical execution threads. The approach used to achieve this goal is to restrict active objects to a message-based communication mechansim that the framework seeks to make as intuitive and simple to use as possible. Consequently, active objects do not interact via synchronous method calls. Instead, they communicate by sending each other messages which are delivered completely asynchronously, one-at-a-time, to the target object (two objects may receive messages concurrently, but each object will never receive its next message until it has completed handling of its current message). The public interface of each active object is featureless - all active objects look the same (from an API point-of-view) like eggs.
In addition to supporting message-based communication, the framework also takes care of loading, and instantiating the application eggs and "hooking them up" so that they can communicate (using messages). The framework "configures" each egg at runtime with references to the message ports of the other eggs it needs to message, as described in an application descriptor which is an XML file that you provide that describes the eggs composing the application and their interdependencies. A popular term for this "runtime configuration of dependencies" is Dependency Injection.
The end result of the message-based communication scheme and the absence of explicit dependence on physical threads is that each egg is highly cohesive and decoupled from the other eggs in the application. Notice that the interaction model is more peer-to-peer than client-server. The only distinguishing difference between eggs is the set of messages that each one will recognize and respond to. However, that difference is not exposed as a set of methods in a public interface. The only interface of an egg that matters is the set of message types (which are just ordinary application-supplied Java classes) that the egg supports.
An obvious consequence of the asynchronous messaging scheme is that it is
not an obvious and immediate error if one egg sends a message to another egg
that the latter doesn't recognize. It's up to the receiving egg to respond
with an appropriate error (e.g. an "exception" delivered to the sender as
a message rather than "raised"). In fact, since all application eggs must
at least be able to handle messages of type java.lang.Object
(even if it is just to emit an error log entry), it is not possible to provoke
a runtime error simply by sending an incorrect message to an egg (of course
the receiving egg may be in an inappropriate state for the message which
may result in an error in the receiver).
Developers who naturally think in terms of active objects will have no difficulty in designing egg-based applications. Others, may find it more challenging. However, it is hoped that the effort may be found to be worthwhile and lead to simpler and more robust applications at the same level of sophistication as your requirements demand.
The jegg
package contains the primary classes in the
JEgg framework.
jegg.Egg
and jegg.impl.EggBase
Classes
An egg is developed by implementing the jegg.Egg
interface.
Alternatively, the jegg.impl.EggBase
convenience class is provided
as a shortcut which should be utilized unless there is some reason not to.
Extending jegg.impl.EggBase
, and implementing at least the
abstract public void handle(Object)
is a completely adequate
egg implementation. However, to tailor the egg to your application, you
should implement additional handle
methods. Each
handle
method takes a single argument corresponding to the
type of message that method is able to process. There are no restrictions
(at this time) on the types of the messages. They can be any Java
object. When a message of a given type arrives at the egg, it will be
delivered to the handle method whose argument type most closesly matches
the concrete type of the message. As already stated, messages are delivered
one-at-a-time.
At startup, the JEgg framework reads a description of the application eggs that it should instantiate from the application descriptor. The Egg Lifecycle section below describes the egg initialization in detail.
jegg.Port
Class
Eggs communicate with one another by sending messages over
messsage ports, which are instances of jegg.Port
.
Each egg has a only one message port. To initiate a message dialogue,
an egg must have a reference to the port of the egg that it will send
a message to. However, a message receiver can always respond to the
sending egg without having a reference to the sending egg's port if the
response is emitted during the handling of the message. Alternatively, the
receiver egg can obtain a reference to the sending egg's port from the
environment during the handling of the message, and save the port
for sending a response at a later time (see jegg.EggContext.getFromPort()
).
The jegg application descriptor is used not only to describe to the JEgg framework
which eggs to instantiate at startup, but also to declare the dependencies of
each egg on any other application egg, if any. A dependency only needs to
be declared for eggs that will initiate a message exchange with one or
more other eggs in the application. Eggs that only always respond to messages
do not need to declare any dependencies. For eggs that declare a dependency,
the ports of any eggs they depend on will be delivered as messages (of type
jegg.Port
) before any other application message is delivered
to the egg. The section Egg Lifecycle below describes egg initialization
in detail.
More details on egg message sending is given in the section Egg Messaging below.
jegg.EggLoader
class:
java jegg.EggLoader [application-descriptor]where application-descriptor is the optional path to the application descriptor that describes the application to load. If the application descriptor is not specified on the command line, the framework will search the classpath for a file named jegg.xml. If the command-line argument does not include a path and can't be found in the current directory, it is searched for along the class path.
<jegg> <basket name="unique-name" > <egg name="unique-egg-name" class="concrete-egg-class" > <uses name="other-egg-name" /> <property name="prop-name" value="prop-value" /> </egg> : : </basket> : : </jegg>
The <jegg> Tag
The <jegg> tag encloses the contents of the descriptor.
The <basket> Tag
The <basket> tag is used to group eggs together. Eggs in the same
lt;basket> are assigned to the same message dispatcher.
See
The <egg> Tag
The <egg> tag describes an application egg and takes the following
attributes:
jegg.Egg
interface.
The <uses> Tag
The <egg> tag can have an optional nested <uses> tag that specifies the
name of another egg that the current egg expects to exchange messages with. Any
number of <uses> tags can be specified. The message port corresponding to
the egg specified by the <uses> tag is delivered to the egg before the
first application message is delivered. The message port is delivered to the
egg as a message of type jegg.Port
, before the egg's
jegg.Egg.init()
method is invoked.
An egg may lookup the port of any egg using the JEgg framework egg
locator service. See the jegg.EggContext.requestPort()
method for details.
The <property> Tag
The <egg> tag also can take an optional nested <property> tag
used to make configuration properties, name-value pairs, available to the
egg at runtime. Any number of <property> tags can be specified.
The values specified in the <property> tag can be accessed by the
egg at runtime through the jegg.EggContext
instance passed
to the egg by the framework through the jegg.Egg.setContext
method which the egg must implement.
One egg sends a message (any Java object) to another by passing the
message object to the jegg.Port.send()
method on the
message port that belongs to the egg. The message port is delivered
to the dependent egg at startup as a result of a <uses> tag
associated with the egg in the application descriptor, or because the
egg called the jegg.EggContext.requestPort()
method
(for instance from the body of its init
method).
A message that is sent to an egg via its message port is delivered to
the egg by the message dispatcher assigned to it in the application
descriptor (the <egg> tag's enclosing <basket> tag). The
message dispatcher will never deliver more than one message at a time to
a given egg. The message is delivered to the egg by invoking the handle
method that has an argument whose type is the same as the concrete type of
the message, or its nearest ancestor (which may be the base
handle(java.lang.Object)
method).
The port of the message sender can be accessed during the handling of
a message via the jegg.EggContext.getFromPort
of the egg's
context instance.
An egg can send a response message to the egg that sent the currently
handled message by passing the response message object to the
jegg.EggContext.respond
method of the its context instance.
An egg can bind to another egg's message port by passing the
message port to the jegg.EggContext.bindToPort
method on
the its context instance. This allows the binding egg to receive all messages
broadcast by the port's owner. An egg can broadcast a message
to all bound eggs by passing the message to the jegg.EggContext.broadcast
method on its context instance.
An egg can send a message to itself by passing the message to the
send
method on its own message port. The egg can get a
reference to its own message port by calling the jegg.EggContext.getPort
on its context instance.
Self-messaging is a useful way for an egg to trigger an action. For instance,
a timer can be used (see jegg.EggContext.createSingleShotTimer
)
to have a timeout message delivered to the egg at some time in the
future. The handler for the timeout message can serve as the notice to
send the special trigger message.
|
|||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |