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: * Presence packet. Presence packets are used to express an entity's current
014: * network availability and to notify other entities of that availability.
015: * Presence packets are also used to negotiate and manage subscriptions to the
016: * presence of other entities.<p>
017: *
018: * A presence optionally has a {@link Type}.
019: *
020: * @author Matt Tucker
021: */
022: public class Presence extends Packet {
023:
024: /**
025: * Constructs a new Presence.
026: */
027: public Presence() {
028: this .element = docFactory.createDocument().addElement(
029: "presence");
030: }
031:
032: /**
033: * Constructs a new Presence with the specified type.
034: *
035: * @param type the presence type.
036: */
037: public Presence(Presence.Type type) {
038: this ();
039: setType(type);
040: }
041:
042: /**
043: * Constructs a new Presence using an existing Element. This is useful
044: * for parsing incoming presence Elements into Presence objects.
045: *
046: * @param element the presence Element.
047: */
048: public Presence(Element element) {
049: super (element);
050: }
051:
052: /**
053: * Constructs a new Presence using an existing Element. This is useful
054: * for parsing incoming Presence Elements into Presence objects. Stringprep validation
055: * on the TO address can be disabled. The FROM address will not be validated since the
056: * server is the one that sets that value.
057: *
058: * @param element the Presence Element.
059: * @param skipValidation true if stringprep should not be applied to the TO address.
060: */
061: public Presence(Element element, boolean skipValidation) {
062: super (element, skipValidation);
063: }
064:
065: /**
066: * Constructs a new Presence that is a copy of an existing Presence.
067: *
068: * @param presence the presence packet.
069: * @see #createCopy()
070: */
071: private Presence(Presence presence) {
072: Element elementCopy = presence.element.createCopy();
073: docFactory.createDocument().add(elementCopy);
074: this .element = elementCopy;
075: // Copy cached JIDs (for performance reasons)
076: this .toJID = presence.toJID;
077: this .fromJID = presence.fromJID;
078: }
079:
080: /**
081: * Returns true if the presence type is "available". This is a
082: * convenience method that is equivalent to:
083: *
084: * <pre>getType() == null</pre>
085: *
086: */
087: public boolean isAvailable() {
088: return getType() == null;
089: }
090:
091: /**
092: * Returns the type of this presence. If the presence is "available", the
093: * type will be <tt>null</tt> (in XMPP, no value for the type attribute is
094: * defined as available).
095: *
096: * @return the presence type or <tt>null</tt> if "available".
097: * @see Type
098: */
099: public Type getType() {
100: String type = element.attributeValue("type");
101: if (type == null) {
102: return null;
103: } else {
104: return Type.valueOf(type);
105: }
106: }
107:
108: /**
109: * Sets the type of this presence.
110: *
111: * @param type the presence type.
112: * @see Type
113: */
114: public void setType(Type type) {
115: element.addAttribute("type", type == null ? null : type
116: .toString());
117: }
118:
119: /**
120: * Returns the presence "show" value, which specifies a particular availability
121: * status. If the <show> element is not present, this method will return
122: * <tt>null</tt>. The show value can only be set if the presence type is "avaialble".
123: * A <tt>null</tt> show value is used to represent "available", which is the
124: * default.
125: *
126: * @return the presence show value..
127: * @see Show
128: */
129: public Show getShow() {
130: String show = element.elementText("show");
131: if (show == null) {
132: return null;
133: } else {
134: return Show.valueOf(show);
135: }
136: }
137:
138: /**
139: * Sets the presence "show" value, which specifies a particular availability
140: * status. The show value can only be set if the presence type is "available".
141: * A <tt>null</tt> show value is used to represent "available", which is the
142: * default.
143: *
144: * @param show the presence show value.
145: * @throws IllegalArgumentException if the presence type is not available.
146: * @see Show
147: */
148: public void setShow(Show show) {
149: Element showElement = element.element("show");
150: // If show is null, clear the subject.
151: if (show == null) {
152: if (showElement != null) {
153: element.remove(showElement);
154: }
155: return;
156: }
157: if (showElement == null) {
158: if (!isAvailable()) {
159: throw new IllegalArgumentException(
160: "Cannot set 'show' if 'type' attribute is set.");
161: }
162: showElement = element.addElement("show");
163: }
164: showElement.setText(show.toString());
165: }
166:
167: /**
168: * Returns the status of this presence packet, a natural-language description
169: * of availability status.
170: *
171: * @return the status.
172: */
173: public String getStatus() {
174: return element.elementText("status");
175: }
176:
177: /**
178: * Sets the status of this presence packet, a natural-language description
179: * of availability status.
180: *
181: * @param status the status.
182: */
183: public void setStatus(String status) {
184: Element statusElement = element.element("status");
185: // If subject is null, clear the subject.
186: if (status == null) {
187: if (statusElement != null) {
188: element.remove(statusElement);
189: }
190: return;
191: }
192:
193: if (statusElement == null) {
194: statusElement = element.addElement("status");
195: }
196: statusElement.setText(status);
197: }
198:
199: /**
200: * Returns the priority. The valid priority range is -128 through 128.
201: * If no priority element exists in the packet, this method will return
202: * the default value of 0.
203: *
204: * @return the priority.
205: */
206: public int getPriority() {
207: String priority = element.elementText("priority");
208: if (priority == null) {
209: return 0;
210: } else {
211: try {
212: return Integer.parseInt(priority);
213: } catch (Exception e) {
214: return 0;
215: }
216: }
217: }
218:
219: /**
220: * Sets the priority. The valid priority range is -128 through 128.
221: *
222: * @param priority the priority.
223: * @throws IllegalArgumentException if the priority is less than -128 or greater
224: * than 128.
225: */
226: public void setPriority(int priority) {
227: if (priority < -128 || priority > 128) {
228: throw new IllegalArgumentException("Priority value of "
229: + priority
230: + " is outside the valid range of -128 through 128");
231: }
232: Element priorityElement = element.element("priority");
233: if (priorityElement == null) {
234: priorityElement = element.addElement("priority");
235: }
236: priorityElement.setText(Integer.toString(priority));
237: }
238:
239: /**
240: * Returns the first child element of this packet that matches the
241: * given name and namespace. If no matching element is found,
242: * <tt>null</tt> will be returned. This is a convenience method to avoid
243: * manipulating this underlying packet's Element instance directly.<p>
244: *
245: * Child elements in extended namespaces are used to extend the features
246: * of XMPP. Examples include a "user is typing" indicator and invitations to
247: * group chat rooms. Although any valid XML can be included in a child element
248: * in an extended namespace, many common features have been standardized
249: * as <a href="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a>
250: * (JEPs).
251: *
252: * @param name the element name.
253: * @param namespace the element namespace.
254: * @return the first matching child element, or <tt>null</tt> if there
255: * is no matching child element.
256: */
257: public Element getChildElement(String name, String namespace) {
258: for (Iterator i = element.elementIterator(name); i.hasNext();) {
259: Element element = (Element) i.next();
260: if (element.getNamespaceURI().equals(namespace)) {
261: return element;
262: }
263: }
264: return null;
265: }
266:
267: /**
268: * Adds a new child element to this packet with the given name and
269: * namespace. The newly created Element is returned. This is a
270: * convenience method to avoid manipulating this underlying packet's
271: * Element instance directly.<p>
272: *
273: * Child elements in extended namespaces are used to extend the features
274: * of XMPP. Examples include a "user is typing" indicator and invitations to
275: * group chat rooms. Although any valid XML can be included in a child element
276: * in an extended namespace, many common features have been standardized
277: * as <a href="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a>
278: * (JEPs).
279: *
280: * @param name the element name.
281: * @param namespace the element namespace.
282: * @return the newly created child element.
283: */
284: public Element addChildElement(String name, String namespace) {
285: return element.addElement(name, namespace);
286: }
287:
288: /**
289: * Returns a deep copy of this Presence.
290: *
291: * @return a deep copy of this Presence.
292: */
293: public Presence createCopy() {
294: return new Presence(this );
295: }
296:
297: /**
298: * Represents the type of a presence packet. Note: the presence is assumed
299: * to be "available" when the type attribute of the packet is <tt>null</tt>.
300: * The valid types are:
301: *
302: * <ul>
303: * <li>{@link #unavailable Presence.Type.unavailable} -- signals that the
304: * entity is no longer available for communication.
305: * <li>{@link #subscribe Presence.Type.subscribe} -- the sender wishes to
306: * subscribe to the recipient's presence.
307: * <li>{@link #subscribed Presence.Type.subscribed} -- the sender has allowed
308: * the recipient to receive their presence.
309: * <li>{@link #unsubscribe Presence.Type.unsubscribe} -- the sender is
310: * unsubscribing from another entity's presence.
311: * <li>{@link #unsubscribed Presence.Type.unsubcribed} -- the subscription
312: * request has been denied or a previously-granted subscription has been cancelled.
313: * <li>{@link #probe Presence.Type.probe} -- a request for an entity's current
314: * presence; SHOULD be generated only by a server on behalf of a user.
315: * <li>{@link #error Presence.Type.error} -- an error has occurred regarding
316: * processing or delivery of a previously-sent presence stanza.
317: * </ul>
318: */
319: public enum Type {
320:
321: /**
322: * Typically short text message used in line-by-line chat interfaces.
323: */
324: unavailable,
325:
326: /**
327: * The sender wishes to subscribe to the recipient's presence.
328: */
329: subscribe,
330:
331: /**
332: * The sender has allowed the recipient to receive their presence.
333: */
334: subscribed,
335:
336: /**
337: * The sender is unsubscribing from another entity's presence.
338: */
339: unsubscribe,
340:
341: /**
342: * The subscription request has been denied or a previously-granted
343: * subscription has been cancelled.
344: */
345: unsubscribed,
346:
347: /**
348: * A request for an entity's current presence; SHOULD be
349: * generated only by a server on behalf of a user.
350: */
351: probe,
352:
353: /**
354: * An error has occurred regarding processing or delivery
355: * of a previously-sent presence stanza.
356: */
357: error;
358: }
359:
360: /**
361: * Represents the presence "show" value. Note: a <tt>null</tt> "show" value is the
362: * default, which means "available". Valid values are:
363: *
364: * <ul>
365: * <li>{@link #chat Presence.Show.chat} -- the entity or resource is actively
366: * interested in chatting.
367: * <li>{@link #away Presence.Show.away} -- the entity or resource is
368: * temporarily away.
369: * <li>{@link #dnd Presence.Show.dnd} -- the entity or resource is busy
370: * (dnd = "Do Not Disturb").
371: * <li>{@link #xa Presence.Show.xa} -- the entity or resource is away for an
372: * extended period (xa = "eXtended Away").
373: * </ul>
374: */
375: public enum Show {
376:
377: /**
378: * The entity or resource is actively interested in chatting.
379: */
380: chat,
381:
382: /**
383: * The entity or resource is temporarily away.
384: */
385: away,
386:
387: /**
388: * The entity or resource is away for an extended period (xa = "eXtended Away").
389: */
390: xa,
391:
392: /**
393: * The entity or resource is busy (dnd = "Do Not Disturb").
394: */
395: dnd;
396: }
397: }
|