/** * $RCSfile$ * $Revision: 3160 $ * $Date: 2005-12-04 17:58:57 -0800 (Sun, 04 Dec 2005) $ * * Copyright 2004 Jive Software. * * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xmpp.packet; import org.dom4j.Element; import java.util.Iterator; /** * Presence packet. Presence packets are used to express an entity's current * network availability and to notify other entities of that availability. * Presence packets are also used to negotiate and manage subscriptions to the * presence of other entities.<p> * * A presence optionally has a {@link Type}. * * @author Matt Tucker */ public class Presence extends Packet { /** * Constructs a new Presence. */ public Presence() { this.element = docFactory.createDocument().addElement("presence"); } /** * Constructs a new Presence with the specified type. * * @param type the presence type. */ public Presence(Presence.Type type) { this(); setType(type); } /** * Constructs a new Presence using an existing Element. This is useful * for parsing incoming presence Elements into Presence objects. * * @param element the presence Element. */ public Presence(Element element) { super(element); } /** * Constructs a new Presence that is a copy of an existing Presence. * * @param presence the presence packet. * @see #createCopy() */ private Presence(Presence presence) { Element elementCopy = presence.element.createCopy(); docFactory.createDocument().add(elementCopy); this.element = elementCopy; // Copy cached JIDs (for performance reasons) this.toJID = presence.toJID; this.fromJID = presence.fromJID; } /** * Returns true if the presence type is "available". This is a * convenience method that is equivalent to: * * <pre>getType() == null</pre> * */ public boolean isAvailable() { return getType() == null; } /** * Returns the type of this presence. If the presence is "available", the * type will be <tt>null</tt> (in XMPP, no value for the type attribute is * defined as available). * * @return the presence type or <tt>null</tt> if "available". * @see Type */ public Type getType() { String type = element.attributeValue("type"); if (type == null) { return null; } else { return Type.valueOf(type); } } /** * Sets the type of this presence. * * @param type the presence type. * @see Type */ public void setType(Type type) { element.addAttribute("type", type==null?null:type.toString()); } /** * Returns the presence "show" value, which specifies a particular availability * status. If the <show> element is not present, this method will return * <tt>null</tt>. The show value can only be set if the presence type is "avaialble". * A <tt>null</tt> show value is used to represent "available", which is the * default. * * @return the presence show value.. * @see Show */ public Show getShow() { String show = element.elementText("show"); if (show == null) { return null; } else { return Show.valueOf(show); } } /** * Sets the presence "show" value, which specifies a particular availability * status. The show value can only be set if the presence type is "available". * A <tt>null</tt> show value is used to represent "available", which is the * default. * * @param show the presence show value. * @throws IllegalArgumentException if the presence type is not available. * @see Show */ public void setShow(Show show) { Element showElement = element.element("show"); // If show is null, clear the subject. if (show == null) { if (showElement != null) { element.remove(showElement); } return; } if (showElement == null) { if (!isAvailable()) { throw new IllegalArgumentException("Cannot set 'show' if 'type' attribute is set."); } showElement = element.addElement("show"); } showElement.setText(show.toString()); } /** * Returns the status of this presence packet, a natural-language description * of availability status. * * @return the status. */ public String getStatus() { return element.elementText("status"); } /** * Sets the status of this presence packet, a natural-language description * of availability status. * * @param status the status. */ public void setStatus(String status) { Element statusElement = element.element("status"); // If subject is null, clear the subject. if (status == null) { if (statusElement != null) { element.remove(statusElement); } return; } if (statusElement == null) { statusElement = element.addElement("status"); } statusElement.setText(status); } /** * Returns the priority. The valid priority range is -128 through 128. * If no priority element exists in the packet, this method will return * the default value of 0. * * @return the priority. */ public int getPriority() { String priority = element.elementText("priority"); if (priority == null) { return 0; } else { try { return Integer.parseInt(priority); } catch (Exception e) { return 0; } } } /** * Sets the priority. The valid priority range is -128 through 128. * * @param priority the priority. * @throws IllegalArgumentException if the priority is less than -128 or greater * than 128. */ public void setPriority(int priority) { if (priority < -128 || priority > 128) { throw new IllegalArgumentException("Priority value of " + priority + " is outside the valid range of -128 through 128"); } Element priorityElement = element.element("priority"); if (priorityElement == null) { priorityElement = element.addElement("priority"); } priorityElement.setText(Integer.toString(priority)); } /** * Returns the first child element of this packet that matches the * given name and namespace. If no matching element is found, * <tt>null</tt> will be returned. This is a convenience method to avoid * manipulating this underlying packet's Element instance directly.<p> * * Child elements in extended namespaces are used to extend the features * of XMPP. Examples include a "user is typing" indicator and invitations to * group chat rooms. Although any valid XML can be included in a child element * in an extended namespace, many common features have been standardized * as <a href="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a> * (JEPs). * * @param name the element name. * @param namespace the element namespace. * @return the first matching child element, or <tt>null</tt> if there * is no matching child element. */ public Element getChildElement(String name, String namespace) { for (Iterator i=element.elementIterator(name); i.hasNext(); ) { Element element = (Element)i.next(); if (element.getNamespaceURI().equals(namespace)) { return element; } } return null; } /** * Adds a new child element to this packet with the given name and * namespace. The newly created Element is returned. This is a * convenience method to avoid manipulating this underlying packet's * Element instance directly.<p> * * Child elements in extended namespaces are used to extend the features * of XMPP. Examples include a "user is typing" indicator and invitations to * group chat rooms. Although any valid XML can be included in a child element * in an extended namespace, many common features have been standardized * as <a href="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a> * (JEPs). * * @param name the element name. * @param namespace the element namespace. * @return the newly created child element. */ public Element addChildElement(String name, String namespace) { return element.addElement(name, namespace); } /** * Returns a deep copy of this Presence. * * @return a deep copy of this Presence. */ public Presence createCopy() { return new Presence(this); } /** * Represents the type of a presence packet. Note: the presence is assumed * to be "available" when the type attribute of the packet is <tt>null</tt>. * The valid types are: * * <ul> * <li>{@link #unavailable Presence.Type.unavailable} -- signals that the * entity is no longer available for communication. * <li>{@link #subscribe Presence.Type.subscribe} -- the sender wishes to * subscribe to the recipient's presence. * <li>{@link #subscribed Presence.Type.subscribed} -- the sender has allowed * the recipient to receive their presence. * <li>{@link #unsubscribe Presence.Type.unsubscribe} -- the sender is * unsubscribing from another entity's presence. * <li>{@link #unsubscribed Presence.Type.unsubcribed} -- the subscription * request has been denied or a previously-granted subscription has been cancelled. * <li>{@link #probe Presence.Type.probe} -- a request for an entity's current * presence; SHOULD be generated only by a server on behalf of a user. * <li>{@link #error Presence.Type.error} -- an error has occurred regarding * processing or delivery of a previously-sent presence stanza. * </ul> */ public enum Type { /** * Typically short text message used in line-by-line chat interfaces. */ unavailable, /** * The sender wishes to subscribe to the recipient's presence. */ subscribe, /** * The sender has allowed the recipient to receive their presence. */ subscribed, /** * The sender is unsubscribing from another entity's presence. */ unsubscribe, /** * The subscription request has been denied or a previously-granted * subscription has been cancelled. */ unsubscribed, /** * A request for an entity's current presence; SHOULD be * generated only by a server on behalf of a user. */ probe, /** * An error has occurred regarding processing or delivery * of a previously-sent presence stanza. */ error; } /** * Represents the presence "show" value. Note: a <tt>null</tt> "show" value is the * default, which means "available". Valid values are: * * <ul> * <li>{@link #chat Presence.Show.chat} -- the entity or resource is actively * interested in chatting. * <li>{@link #away Presence.Show.away} -- the entity or resource is * temporarily away. * <li>{@link #dnd Presence.Show.dnd} -- the entity or resource is busy * (dnd = "Do Not Disturb"). * <li>{@link #xa Presence.Show.xa} -- the entity or resource is away for an * extended period (xa = "eXtended Away"). * </ul> */ public enum Show { /** * The entity or resource is actively interested in chatting. */ chat, /** * The entity or resource is temporarily away. */ away, /** * The entity or resource is away for an extended period (xa = "eXtended Away"). */ xa, /** * The entity or resource is busy (dnd = "Do Not Disturb"). */ dnd; } }