001: /**
002: * Copyright (C) 2004-2007 Jive Software. All rights reserved.
003: *
004: * This software is published under the terms of the GNU Public License (GPL),
005: * a copy of which is included in this distribution.
006: */package org.xmpp.packet;
007:
008: import org.dom4j.Element;
009:
010: import java.util.Iterator;
011:
012: /**
013: * Message packet.<p>
014: *
015: * A message can have one of several {@link Type Types}. For each message type,
016: * different message fields are typically used as follows:
017: *
018: * <p>
019: * <table border="1">
020: * <tr><td> </td><td colspan="5"><b>Message type</b></td></tr>
021: * <tr><td><i>Field</i></td><td><b>Normal</b></td><td><b>Chat</b></td><td><b>Group Chat</b></td><td><b>Headline</b></td><td><b>Error</b></td></tr>
022: * <tr><td><i>subject</i></td> <td>SHOULD</td><td>SHOULD NOT</td><td>SHOULD NOT</td><td>SHOULD NOT</td><td>SHOULD NOT</td></tr>
023: * <tr><td><i>thread</i></td> <td>OPTIONAL</td><td>SHOULD</td><td>OPTIONAL</td><td>OPTIONAL</td><td>SHOULD NOT</td></tr>
024: * <tr><td><i>body</i></td> <td>SHOULD</td><td>SHOULD</td><td>SHOULD</td><td>SHOULD</td><td>SHOULD NOT</td></tr>
025: * <tr><td><i>error</i></td> <td>MUST NOT</td><td>MUST NOT</td><td>MUST NOT</td><td>MUST NOT</td><td>MUST</td></tr>
026: * </table>
027: */
028: public class Message extends Packet {
029:
030: /**
031: * Constructs a new Message.
032: */
033: public Message() {
034: this .element = docFactory.createDocument()
035: .addElement("message");
036: }
037:
038: /**
039: * Constructs a new Message using an existing Element. This is useful
040: * for parsing incoming message Elements into Message objects.
041: *
042: * @param element the message Element.
043: */
044: public Message(Element element) {
045: super (element);
046: }
047:
048: /**
049: * Constructs a new Message using an existing Element. This is useful
050: * for parsing incoming message Elements into Message objects. Stringprep validation
051: * on the TO address can be disabled. The FROM address will not be validated since the
052: * server is the one that sets that value.
053: *
054: * @param element the message Element.
055: * @param skipValidation true if stringprep should not be applied to the TO address.
056: */
057: public Message(Element element, boolean skipValidation) {
058: super (element, skipValidation);
059: }
060:
061: /**
062: * Constructs a new Message that is a copy of an existing Message.
063: *
064: * @param message the message packet.
065: * @see #createCopy()
066: */
067: private Message(Message message) {
068: Element elementCopy = message.element.createCopy();
069: docFactory.createDocument().add(elementCopy);
070: this .element = elementCopy;
071: // Copy cached JIDs (for performance reasons)
072: this .toJID = message.toJID;
073: this .fromJID = message.fromJID;
074: }
075:
076: /**
077: * Returns the type of this message
078: *
079: * @return the message type.
080: * @see Type
081: */
082: public Type getType() {
083: String type = element.attributeValue("type");
084: if (type != null) {
085: return Type.valueOf(type);
086: } else {
087: return Type.normal;
088: }
089: }
090:
091: /**
092: * Sets the type of this message.
093: *
094: * @param type the message type.
095: * @see Type
096: */
097: public void setType(Type type) {
098: element.addAttribute("type", type == null ? null : type
099: .toString());
100: }
101:
102: /**
103: * Returns the subject of this message or <tt>null</tt> if there is no subject..
104: *
105: * @return the subject.
106: */
107: public String getSubject() {
108: return element.elementText("subject");
109: }
110:
111: /**
112: * Sets the subject of this message.
113: *
114: * @param subject the subject.
115: */
116: public void setSubject(String subject) {
117: Element subjectElement = element.element("subject");
118: // If subject is null, clear the subject.
119: if (subject == null && subjectElement != null) {
120: element.remove(subjectElement);
121: return;
122: }
123: // Do nothing if the new subject is null
124: if (subject == null) {
125: return;
126: }
127: if (subjectElement == null) {
128: subjectElement = element.addElement("subject");
129: }
130: subjectElement.setText(subject);
131: }
132:
133: /**
134: * Returns the body of this message or <tt>null</tt> if there is no body.
135: *
136: * @return the body.
137: */
138: public String getBody() {
139: return element.elementText("body");
140: }
141:
142: /**
143: * Sets the body of this message.
144: *
145: * @param body the body.
146: */
147: public void setBody(String body) {
148: Element bodyElement = element.element("body");
149: // If body is null, clear the body.
150: if (body == null) {
151: if (bodyElement != null) {
152: element.remove(bodyElement);
153: }
154: return;
155: }
156: if (bodyElement == null) {
157: bodyElement = element.addElement("body");
158: }
159: bodyElement.setText(body);
160: }
161:
162: /**
163: * Returns the thread value of this message, an identifier that is used for
164: * tracking a conversation thread ("instant messaging session")
165: * between two entities. If the thread is not set, <tt>null</tt> will be
166: * returned.
167: *
168: * @return the thread value.
169: */
170: public String getThread() {
171: return element.elementText("thread");
172: }
173:
174: /**
175: * Sets the thread value of this message, an identifier that is used for
176: * tracking a conversation thread ("instant messaging session")
177: * between two entities.
178: *
179: * @param thread thread value.
180: */
181: public void setThread(String thread) {
182: Element threadElement = element.element("thread");
183: // If thread is null, clear the thread.
184: if (thread == null) {
185: if (threadElement != null) {
186: element.remove(threadElement);
187: }
188: return;
189: }
190:
191: if (threadElement == null) {
192: threadElement = element.addElement("thread");
193: }
194: threadElement.setText(thread);
195: }
196:
197: /**
198: * Returns the first child element of this packet that matches the
199: * given name and namespace. If no matching element is found,
200: * <tt>null</tt> will be returned. This is a convenience method to avoid
201: * manipulating this underlying packet's Element instance directly.<p>
202: *
203: * Child elements in extended namespaces are used to extend the features
204: * of XMPP. Examples include a "user is typing" indicator and invitations to
205: * group chat rooms. Although any valid XML can be included in a child element
206: * in an extended namespace, many common features have been standardized
207: * as <a href="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a>
208: * (JEPs).
209: *
210: * @param name the element name.
211: * @param namespace the element namespace.
212: * @return the first matching child element, or <tt>null</tt> if there
213: * is no matching child element.
214: */
215: public Element getChildElement(String name, String namespace) {
216: for (Iterator i = element.elementIterator(name); i.hasNext();) {
217: Element element = (Element) i.next();
218: if (element.getNamespaceURI().equals(namespace)) {
219: return element;
220: }
221: }
222: return null;
223: }
224:
225: /**
226: * Adds a new child element to this packet with the given name and
227: * namespace. The newly created Element is returned. This is a
228: * convenience method to avoid manipulating this underlying packet's
229: * Element instance directly.<p>
230: *
231: * Child elements in extended namespaces are used to extend the features
232: * of XMPP. Examples include a "user is typing" indicator and invitations to
233: * group chat rooms. Although any valid XML can be included in a child element
234: * in an extended namespace, many common features have been standardized
235: * as <a href="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a>
236: * (JEPs).
237: *
238: * @param name the element name.
239: * @param namespace the element namespace.
240: * @return the newly created child element.
241: */
242: public Element addChildElement(String name, String namespace) {
243: return element.addElement(name, namespace);
244: }
245:
246: /**
247: * Returns a deep copy of this Message.
248: *
249: * @return a deep copy of this Message.
250: */
251: public Message createCopy() {
252: return new Message(this );
253: }
254:
255: /**
256: * Type-safe enumeration for the type of a message. The types are:
257: *
258: * <ul>
259: * <li>{@link #normal Message.Type.normal} -- (Default) a normal text message
260: * used in email like interface.
261: * <li>{@link #chat Message.Type.cha}t -- a typically short text message used
262: * in line-by-line chat interfaces.
263: * <li>{@link #groupchat Message.Type.groupchat} -- a chat message sent to a
264: * groupchat server for group chats.
265: * <li>{@link #headline Message.Type.headline} -- a text message to be displayed
266: * in scrolling marquee displays.
267: * <li>{@link #error Message.Type.error} -- indicates a messaging error.
268: * </ul>
269: */
270: public enum Type {
271:
272: /**
273: * (Default) a normal text message used in email like interface.
274: */
275: normal,
276:
277: /**
278: * Typically short text message used in line-by-line chat interfaces.
279: */
280: chat,
281:
282: /**
283: * Chat message sent to a groupchat server for group chats.
284: */
285: groupchat,
286:
287: /**
288: * Text message to be displayed in scrolling marquee displays.
289: */
290: headline,
291:
292: /**
293: * Indicates a messaging error.
294: */
295: error;
296: }
297: }
|