| Red Hat Docs > Manuals > Red Hat Web Application Framework > |
The Red Hat Web Application Framework messaging service is intended to be used as a building block for "messaging applications": that is, Red Hat Web Application Framework applications that use messages to represent various types of communication between users. Messages can represent an email from one user to another, or a bboard post, or a comment on another object in the system. They can also store attachments like images or other files that are relevant to the message. Using the Red Hat Web Application Framework notification service, you can send a Message object as in email to another User or Group.
To use the messaging service, you should be familiar with the following classes:
This class models a persistent text message with optional attachments. The message body should have a MIME type of text/plain or text/html. Each attachment to the message can have an arbitrary MIME type and format. Messages can also refer to another object on the system, and in this way be attached to ContentItems, discussion forums, and so forth.
This interface stores the set of legal MIME types for message bodies. The primary MIME type of a message body must be "text".
This represents a message part (an attachment) in the sense of a multipart MIME message. Each part has some content represented as an arbitrary block of bytes and a MIME type that identifies the format of the content. Message parts use a simplified DataHandler mechanism for processing content.
A ThreadedMessage is an extension of Message that allows messages to be organized into discussion threads with a tree structure. A typical discussion might be organized as follows:
msg-0 msg-0.0 msg-0.1 msg-0.1.0 msg-0.1.1 msg-0.2 msg-1 msg-1.0 msg-2 |
where msg-0.0 and msg-0.1 are replies to msg-0, msg-0.1.0 is a reply to msg-0.1, and so forth. Messages at the first level (msg-0, msg-1, and msg-2) are referred to as "root" messages, and higher-level messages contain a pointer to their common root. If a root message is deleted, all of its children are deleted.
ThreadedMessage simplifies the task of creating and retrieving these types of tree structures.
By default, a new Message has a MIME type of "text/plain", so creating and storing simple text messages is straightforward:
Party from; Message msg = new Message(from, "the subject", "the body"); msg.save(); |
To create a message in a different format, like "text/html", the API provides a method to set the MIME type when the Message is created:
Message msg = new Message(from, subject);
msg.setBody("<p>this is the body</p>", MessageType.TEXT_HTML);
msg.save(); |
Finally, a Message can also be instantiated by retrieving it from the database by supplying its unique ID:
Message msg = new Message(new BigDecimal(1234)); |
Note that the Message class only support bodies with a primary MIME type of "text". The MessageType interface defines legal MIME types for use in specifying a message body.
Messages can store an optional reference to an ACSObject. This is useful for "attaching" messages to other items in the system. For example, a discussion forum might implement a Topic class to represent a collection of related messages. The process of adding a message to a given topic can be implemented by setting a reference to that topic:
// One topic in a discussion forum
class Topic extends ACSObject {
// Add a new posting for this topic
addNewPosting (User postedBy, String subject, String post) {
Message msg = new Message(postedBy, subject, post);
msg.setRefersTo(this);
msg.save();
}
} |
Additional pieces of content can be attached to a message. These content items can be any media type with a supported DataHandler. Convenience methods are provided for attaching plain text documents directly to a message:
Message msg = new Message(from, subject);
msg.setText("See the attached document.");
msg.attach("A simple document", "simple.txt");
msg.save(); |
To attach more complex types of content, you use a MessagePart and an appropriate data source or DataHandler. There are convenience methods to attach content retrieved from a File or a URL. The following example shows how to attach an uploaded image to a message:
File file = new File("image.gif");
MessagePart part = new MessagePart();
part.setContent(image, "image.gif", "An image");
Message msg = new Message(from, subject, "See attached image");
msg.attach(part);
msg.save(); |
The code for downloading the image from a remote server is almost identical:
URL url = new URL("http://mysite.net/image.gif");
MessagePart part = new MessagePart();
part.setContent(url, "image.gif", "An image from mysite");
Message msg = new Message(from, subject, "See attached image");
msg.attach(part);
msg.save(); |
Note that the above two examples do not explicitly set a MIME type for the content. This is determined automatically when the content is handed off to a DataHandler for processing. In both cases shown above the content will be of type "image/gif".
A Message object can store a reference to another Message object to implement basic threading. A reply is created using the reply() method of the parent Message:
Message parent = new Message(new BigDecimal(1234));
Message reply = parent.reply();
reply.setFrom(from);
reply.setText("I do not agree, because...");
reply.save(); |
When a reply is created this way, the subject is initialized as appropriate for a reply to the parent, and a reference to the parent message is stored internally. The client code must set other message properties, including the body of the reply.
Many applications need to store a more complex, structured set of responses than the flat organization provided by Message. The ThreadedMessage class provides support for organizing messages into a tree structure as outlined above. The API for ThreadedMessage is identical, but the reply() also takes care of setting a special sort key that determines the proper location of a message in the tree.
The following example shows a simple discussion thread and the technique used to retrieve all messages from the database for display in the correct order. The structure of the underlying tree is as follows:
msg0
msg2
msg4
msg5
msg3
msg6
msg1 |
Although in a real application the structure of messages and replies would be generated over time, the following example shows the sequence of calls that produces the same organization, for illustration purposes.
// A common object that all messages refer to.
// In practice this might a forum or a content
// item that is being discussed by a group of
// collaborators.
ACSObject anchor;
// Create the message
ThreadedMessage msg[];
msg[0] = new ThreadedMessage();
msg[0].setRefersTo(anchor);
msg[1] = new ThreadedMessage();
msg[1].setRefersTo(anchor);
msg[2] = msg[0].replyTo(from,body);
msg[3] = msg[0].replyTo(from,body);
msg[4] = msg[2].replyTo(from,body);
msg[5] = msg[2].replyTo(from,body);
msg[6] = msg[3].replyTo(from,body); |
Note that the two root-level messages (0 and 1) explicitly set the reference to our anchor object, but the replies do not. This information is automatically transferred to the replies when they are created, as are the subject and other properties, in the same way as Message.reply().
In addition, ThreadedMessage.replyTo() also sets a special sort key that determines the correct position of the message in the tree. Details of the sort keys are not important, but they are generated so that all common messages can be retrieved in the correct order using a single order by clause. A special query provided by the messaging package is used to reconstruct the tree structure shown above:
Session session = SessionManager.getSession();
DataQuery query = session.retrieveQuery
("com.arsdigita.messaging.getMessageTree");
query.addEqualsFilter("object", anchor);
while (query.next() {
ThreadedMessage msg = new ThreadedMessage
((BigDecimal) query.get("id"));
System.out.println("message " + msg.toString());
}
|
The addEqualsFilter is required to retrieve only those messages that refer to the same ACSObject.