Presence.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smack.packet;

  18. import java.util.Locale;

  19. import org.jivesoftware.smack.util.Objects;
  20. import org.jivesoftware.smack.util.TypedCloneable;
  21. import org.jivesoftware.smack.util.XmlStringBuilder;

  22. /**
  23.  * Represents XMPP presence packets. Every presence packet has a type, which is one of
  24.  * the following values:
  25.  * <ul>
  26.  *      <li>{@link Presence.Type#available available} -- (Default) indicates the user is available to
  27.  *          receive messages.
  28.  *      <li>{@link Presence.Type#unavailable unavailable} -- the user is unavailable to receive messages.
  29.  *      <li>{@link Presence.Type#subscribe subscribe} -- request subscription to recipient's presence.
  30.  *      <li>{@link Presence.Type#subscribed subscribed} -- grant subscription to sender's presence.
  31.  *      <li>{@link Presence.Type#unsubscribe unsubscribe} -- request removal of subscription to
  32.  *          sender's presence.
  33.  *      <li>{@link Presence.Type#unsubscribed unsubscribed} -- grant removal of subscription to
  34.  *          sender's presence.
  35.  *      <li>{@link Presence.Type#error error} -- the presence packet contains an error message.
  36.  * </ul><p>
  37.  *
  38.  * A number of attributes are optional:
  39.  * <ul>
  40.  *      <li>Status -- free-form text describing a user's presence (i.e., gone to lunch).
  41.  *      <li>Priority -- non-negative numerical priority of a sender's resource. The
  42.  *          highest resource priority is the default recipient of packets not addressed
  43.  *          to a particular resource.
  44.  *      <li>Mode -- one of five presence modes: {@link Mode#available available} (the default),
  45.  *          {@link Mode#chat chat}, {@link Mode#away away}, {@link Mode#xa xa} (extended away), and
  46.  *          {@link Mode#dnd dnd} (do not disturb).
  47.  * </ul><p>
  48.  *
  49.  * Presence packets are used for two purposes. First, to notify the server of
  50.  * the user's current presence status. Second, they are used to subscribe and
  51.  * unsubscribe users from the roster.
  52.  *
  53.  * @author Matt Tucker
  54.  */
  55. public final class Presence extends Stanza implements TypedCloneable<Presence> {

  56.     public static final String ELEMENT = "presence";

  57.     private Type type = Type.available;
  58.     private String status = null;
  59.     private int priority = Integer.MIN_VALUE;
  60.     private Mode mode = null;

  61.     /**
  62.      * Creates a new presence update. Status, priority, and mode are left un-set.
  63.      *
  64.      * @param type the type.
  65.      */
  66.     public Presence(Type type) {
  67.         setType(type);
  68.     }

  69.     /**
  70.      * Creates a new presence update with a specified status, priority, and mode.
  71.      *
  72.      * @param type the type.
  73.      * @param status a text message describing the presence update.
  74.      * @param priority the priority of this presence update.
  75.      * @param mode the mode type for this presence update.
  76.      */
  77.     public Presence(Type type, String status, int priority, Mode mode) {
  78.         setType(type);
  79.         setStatus(status);
  80.         setPriority(priority);
  81.         setMode(mode);
  82.     }

  83.     /**
  84.      * Copy constructor.
  85.      * <p>
  86.      * This does not perform a deep clone, as extension elements are shared between the new and old
  87.      * instance.
  88.      * </p>
  89.      *
  90.      * @param other
  91.      */
  92.     public Presence(Presence other) {
  93.         super(other);
  94.         this.type = other.type;
  95.         this.status = other.status;
  96.         this.priority = other.priority;
  97.         this.mode = other.mode;
  98.     }

  99.     /**
  100.      * Returns true if the {@link Type presence type} is available (online) and
  101.      * false if the user is unavailable (offline), or if this is a presence packet
  102.      * involved in a subscription operation. This is a convenience method
  103.      * equivalent to <tt>getType() == Presence.Type.available</tt>. Note that even
  104.      * when the user is available, their presence mode may be {@link Mode#away away},
  105.      * {@link Mode#xa extended away} or {@link Mode#dnd do not disturb}. Use
  106.      * {@link #isAway()} to determine if the user is away.
  107.      *
  108.      * @return true if the presence type is available.
  109.      */
  110.     public boolean isAvailable() {
  111.         return type == Type.available;    
  112.     }

  113.     /**
  114.      * Returns true if the presence type is {@link Type#available available} and the presence
  115.      * mode is {@link Mode#away away}, {@link Mode#xa extended away}, or
  116.      * {@link Mode#dnd do not disturb}. False will be returned when the type or mode
  117.      * is any other value, including when the presence type is unavailable (offline).
  118.      * This is a convenience method equivalent to
  119.      * <tt>type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd)</tt>.
  120.      *
  121.      * @return true if the presence type is available and the presence mode is away, xa, or dnd.
  122.      */
  123.     public boolean isAway() {
  124.         return type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd);
  125.     }

  126.     /**
  127.      * Returns the type of this presence packet.
  128.      *
  129.      * @return the type of the presence packet.
  130.      */
  131.     public Type getType() {
  132.         return type;
  133.     }

  134.     /**
  135.      * Sets the type of the presence packet.
  136.      *
  137.      * @param type the type of the presence packet.
  138.      */
  139.     public void setType(Type type) {
  140.         this.type = Objects.requireNonNull(type, "Type cannot be null");
  141.     }

  142.     /**
  143.      * Returns the status message of the presence update, or <tt>null</tt> if there
  144.      * is not a status. The status is free-form text describing a user's presence
  145.      * (i.e., "gone to lunch").
  146.      *
  147.      * @return the status message.
  148.      */
  149.     public String getStatus() {
  150.         return status;
  151.     }

  152.     /**
  153.      * Sets the status message of the presence update. The status is free-form text
  154.      * describing a user's presence (i.e., "gone to lunch").
  155.      *
  156.      * @param status the status message.
  157.      */
  158.     public void setStatus(String status) {
  159.         this.status = status;
  160.     }

  161.     /**
  162.      * Returns the priority of the presence, or Integer.MIN_VALUE if no priority has been set.
  163.      *
  164.      * @return the priority.
  165.      */
  166.     public int getPriority() {
  167.         return priority;
  168.     }

  169.     /**
  170.      * Sets the priority of the presence. The valid range is -128 through 128.
  171.      *
  172.      * @param priority the priority of the presence.
  173.      * @throws IllegalArgumentException if the priority is outside the valid range.
  174.      */
  175.     public void setPriority(int priority) {
  176.         if (priority < -128 || priority > 128) {
  177.             throw new IllegalArgumentException("Priority value " + priority +
  178.                     " is not valid. Valid range is -128 through 128.");
  179.         }
  180.         this.priority = priority;
  181.     }

  182.     /**
  183.      * Returns the mode of the presence update.
  184.      *
  185.      * @return the mode.
  186.      */
  187.     public Mode getMode() {
  188.         if (mode == null) {
  189.             return Mode.available;
  190.         }
  191.         return mode;
  192.     }

  193.     /**
  194.      * Sets the mode of the presence update. A null presence mode value is interpreted
  195.      * to be the same thing as {@link Presence.Mode#available}.
  196.      *
  197.      * @param mode the mode.
  198.      */
  199.     public void setMode(Mode mode) {
  200.         this.mode = mode;
  201.     }

  202.     @Override
  203.     public XmlStringBuilder toXML() {
  204.         XmlStringBuilder buf = new XmlStringBuilder();
  205.         buf.halfOpenElement(ELEMENT);
  206.         addCommonAttributes(buf);
  207.         if (type != Type.available) {
  208.             buf.attribute("type", type);
  209.         }
  210.         buf.rightAngleBracket();

  211.         buf.optElement("status", status);
  212.         if (priority != Integer.MIN_VALUE) {
  213.             buf.element("priority", Integer.toString(priority));
  214.         }
  215.         if (mode != null && mode != Mode.available) {
  216.             buf.element("show", mode);
  217.         }
  218.         buf.append(getExtensionsXML());

  219.         // Add the error sub-packet, if there is one.
  220.         appendErrorIfExists(buf);

  221.         buf.closeElement(ELEMENT);

  222.         return buf;
  223.     }

  224.     /**
  225.      * Creates and returns a copy of this presence stanza.
  226.      * <p>
  227.      * This does not perform a deep clone, as extension elements are shared between the new and old
  228.      * instance.
  229.      * </p>
  230.      * @return a clone of this presence.
  231.      */
  232.     @Override
  233.     public Presence clone() {
  234.         return new Presence(this);
  235.     }

  236.     /**
  237.      * An enum to represent the presence type. Note that presence type is often confused
  238.      * with presence mode. Generally, if a user is signed in to a server, they have a presence
  239.      * type of {@link #available available}, even if the mode is {@link Mode#away away},
  240.      * {@link Mode#dnd dnd}, etc. The presence type is only {@link #unavailable unavailable} when
  241.      * the user is signing out of the server.
  242.      */
  243.     public enum Type {

  244.        /**
  245.         * The user is available to receive messages (default).
  246.         */
  247.         available,

  248.         /**
  249.          * The user is unavailable to receive messages.
  250.          */
  251.         unavailable,

  252.         /**
  253.          * Request subscription to recipient's presence.
  254.          */
  255.         subscribe,

  256.         /**
  257.          * Grant subscription to sender's presence.
  258.          */
  259.         subscribed,

  260.         /**
  261.          * Request removal of subscription to sender's presence.
  262.          */
  263.         unsubscribe,

  264.         /**
  265.          * Grant removal of subscription to sender's presence.
  266.          */
  267.         unsubscribed,

  268.         /**
  269.          * The presence packet contains an error message.
  270.          */
  271.         error,

  272.         /**
  273.          * A presence probe as defined in section 4.3 of RFC 6121
  274.          */
  275.         probe,
  276.         ;

  277.         /**
  278.          * Converts a String into the corresponding types. Valid String values that can be converted
  279.          * to types are: "available", "unavailable", "subscribe", "subscribed", "unsubscribe",
  280.          * "unsubscribed" and "error".
  281.          *
  282.          * @param string the String value to covert.
  283.          * @return the corresponding Type.
  284.          * @throws IllegalArgumentException when not able to parse the string parameter
  285.          * @throws NullPointerException if the string is null
  286.          */
  287.         public static Type fromString(String string) {
  288.             return Type.valueOf(string.toLowerCase(Locale.US));
  289.         }
  290.     }

  291.     /**
  292.      * An enum to represent the presence mode.
  293.      */
  294.     public enum Mode {

  295.         /**
  296.          * Free to chat.
  297.          */
  298.         chat,

  299.         /**
  300.          * Available (the default).
  301.          */
  302.         available,

  303.         /**
  304.          * Away.
  305.          */
  306.         away,

  307.         /**
  308.          * Away for an extended period of time.
  309.          */
  310.         xa,

  311.         /**
  312.          * Do not disturb.
  313.          */
  314.         dnd;

  315.         /**
  316.          * Converts a String into the corresponding types. Valid String values that can be converted
  317.          * to types are: "chat", "available", "away", "xa", and "dnd".
  318.          *
  319.          * @param string the String value to covert.
  320.          * @return the corresponding Type.
  321.          * @throws IllegalArgumentException when not able to parse the string parameter
  322.          * @throws NullPointerException if the string is null
  323.          */
  324.         public static Mode fromString(String string) {
  325.             return Mode.valueOf(string.toLowerCase(Locale.US));
  326.         }
  327.     }
  328. }