Home | History | Annotate | Download | only in packet
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * Copyright 2003-2007 Jive Software.
      7  *
      8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 package org.jivesoftware.smackx.packet;
     22 
     23 import org.jivesoftware.smack.packet.PacketExtension;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Iterator;
     27 
     28 /**
     29  * Represents message events relating to the delivery, display, composition and cancellation of
     30  * messages.<p>
     31  *
     32  * There are four message events currently defined in this namespace:
     33  * <ol>
     34  * <li>Offline<br>
     35  * Indicates that the message has been stored offline by the intended recipient's server. This
     36  * event is triggered only if the intended recipient's server supports offline storage, has that
     37  * support enabled, and the recipient is offline when the server receives the message for delivery.</li>
     38  *
     39  * <li>Delivered<br>
     40  * Indicates that the message has been delivered to the recipient. This signifies that the message
     41  * has reached the recipient's XMPP client, but does not necessarily mean that the message has
     42  * been displayed. This event is to be raised by the XMPP client.</li>
     43  *
     44  * <li>Displayed<br>
     45  * Once the message has been received by the recipient's XMPP client, it may be displayed to the
     46  * user. This event indicates that the message has been displayed, and is to be raised by the
     47  * XMPP client. Even if a message is displayed multiple times, this event should be raised only
     48  * once.</li>
     49  *
     50  * <li>Composing<br>
     51  * In threaded chat conversations, this indicates that the recipient is composing a reply to a
     52  * message. The event is to be raised by the recipient's XMPP client. A XMPP client is allowed
     53  * to raise this event multiple times in response to the same request, providing the original
     54  * event is cancelled first.</li>
     55  * </ol>
     56  *
     57  * @author Gaston Dombiak
     58  */
     59 public class MessageEvent implements PacketExtension {
     60 
     61     public static final String OFFLINE = "offline";
     62     public static final String COMPOSING = "composing";
     63     public static final String DISPLAYED = "displayed";
     64     public static final String DELIVERED = "delivered";
     65     public static final String CANCELLED = "cancelled";
     66 
     67     private boolean offline = false;
     68     private boolean delivered = false;
     69     private boolean displayed = false;
     70     private boolean composing = false;
     71     private boolean cancelled = true;
     72 
     73     private String packetID = null;
     74 
     75     /**
     76     * Returns the XML element name of the extension sub-packet root element.
     77     * Always returns "x"
     78     *
     79     * @return the XML element name of the packet extension.
     80     */
     81     public String getElementName() {
     82         return "x";
     83     }
     84 
     85     /**
     86      * Returns the XML namespace of the extension sub-packet root element.
     87      * According the specification the namespace is always "jabber:x:event"
     88      *
     89      * @return the XML namespace of the packet extension.
     90      */
     91     public String getNamespace() {
     92         return "jabber:x:event";
     93     }
     94 
     95     /**
     96      * When the message is a request returns if the sender of the message requests to be notified
     97      * when the receiver is composing a reply.
     98      * When the message is a notification returns if the receiver of the message is composing a
     99      * reply.
    100      *
    101      * @return true if the sender is requesting to be notified when composing or when notifying
    102      * that the receiver of the message is composing a reply
    103      */
    104     public boolean isComposing() {
    105         return composing;
    106     }
    107 
    108     /**
    109      * When the message is a request returns if the sender of the message requests to be notified
    110      * when the message is delivered.
    111      * When the message is a notification returns if the message was delivered or not.
    112      *
    113      * @return true if the sender is requesting to be notified when delivered or when notifying
    114      * that the message was delivered
    115      */
    116     public boolean isDelivered() {
    117         return delivered;
    118     }
    119 
    120     /**
    121      * When the message is a request returns if the sender of the message requests to be notified
    122      * when the message is displayed.
    123      * When the message is a notification returns if the message was displayed or not.
    124      *
    125      * @return true if the sender is requesting to be notified when displayed or when notifying
    126      * that the message was displayed
    127      */
    128     public boolean isDisplayed() {
    129         return displayed;
    130     }
    131 
    132     /**
    133      * When the message is a request returns if the sender of the message requests to be notified
    134      * when the receiver of the message is offline.
    135      * When the message is a notification returns if the receiver of the message was offline.
    136      *
    137      * @return true if the sender is requesting to be notified when offline or when notifying
    138      * that the receiver of the message is offline
    139      */
    140     public boolean isOffline() {
    141         return offline;
    142     }
    143 
    144     /**
    145      * When the message is a notification returns if the receiver of the message cancelled
    146      * composing a reply.
    147      *
    148      * @return true if the receiver of the message cancelled composing a reply
    149      */
    150     public boolean isCancelled() {
    151         return cancelled;
    152     }
    153 
    154     /**
    155      * Returns the unique ID of the message that requested to be notified of the event.
    156      * The packet id is not used when the message is a request for notifications
    157      *
    158      * @return the message id that requested to be notified of the event.
    159      */
    160     public String getPacketID() {
    161         return packetID;
    162     }
    163 
    164     /**
    165      * Returns the types of events. The type of event could be:
    166      * "offline", "composing","delivered","displayed", "offline"
    167      *
    168      * @return an iterator over all the types of events of the MessageEvent.
    169      */
    170     public Iterator<String> getEventTypes() {
    171         ArrayList<String> allEvents = new ArrayList<String>();
    172         if (isDelivered()) {
    173             allEvents.add(MessageEvent.DELIVERED);
    174         }
    175         if (!isMessageEventRequest() && isCancelled()) {
    176             allEvents.add(MessageEvent.CANCELLED);
    177         }
    178         if (isComposing()) {
    179             allEvents.add(MessageEvent.COMPOSING);
    180         }
    181         if (isDisplayed()) {
    182             allEvents.add(MessageEvent.DISPLAYED);
    183         }
    184         if (isOffline()) {
    185             allEvents.add(MessageEvent.OFFLINE);
    186         }
    187         return allEvents.iterator();
    188     }
    189 
    190     /**
    191      * When the message is a request sets if the sender of the message requests to be notified
    192      * when the receiver is composing a reply.
    193      * When the message is a notification sets if the receiver of the message is composing a
    194      * reply.
    195      *
    196      * @param composing sets if the sender is requesting to be notified when composing or when
    197      * notifying that the receiver of the message is composing a reply
    198      */
    199     public void setComposing(boolean composing) {
    200         this.composing = composing;
    201         setCancelled(false);
    202     }
    203 
    204     /**
    205      * When the message is a request sets if the sender of the message requests to be notified
    206      * when the message is delivered.
    207      * When the message is a notification sets if the message was delivered or not.
    208      *
    209      * @param delivered sets if the sender is requesting to be notified when delivered or when
    210      * notifying that the message was delivered
    211      */
    212     public void setDelivered(boolean delivered) {
    213         this.delivered = delivered;
    214         setCancelled(false);
    215     }
    216 
    217     /**
    218      * When the message is a request sets if the sender of the message requests to be notified
    219      * when the message is displayed.
    220      * When the message is a notification sets if the message was displayed or not.
    221      *
    222      * @param displayed sets if the sender is requesting to be notified when displayed or when
    223      * notifying that the message was displayed
    224      */
    225     public void setDisplayed(boolean displayed) {
    226         this.displayed = displayed;
    227         setCancelled(false);
    228     }
    229 
    230     /**
    231      * When the message is a request sets if the sender of the message requests to be notified
    232      * when the receiver of the message is offline.
    233      * When the message is a notification sets if the receiver of the message was offline.
    234      *
    235      * @param offline sets if the sender is requesting to be notified when offline or when
    236      * notifying that the receiver of the message is offline
    237      */
    238     public void setOffline(boolean offline) {
    239         this.offline = offline;
    240         setCancelled(false);
    241     }
    242 
    243     /**
    244      * When the message is a notification sets if the receiver of the message cancelled
    245      * composing a reply.
    246      * The Cancelled event is never requested explicitly. It is requested implicitly when
    247      * requesting to be notified of the Composing event.
    248      *
    249      * @param cancelled sets if the receiver of the message cancelled composing a reply
    250      */
    251     public void setCancelled(boolean cancelled) {
    252         this.cancelled = cancelled;
    253     }
    254 
    255     /**
    256      * Sets the unique ID of the message that requested to be notified of the event.
    257      * The packet id is not used when the message is a request for notifications
    258      *
    259      * @param packetID the message id that requested to be notified of the event.
    260      */
    261     public void setPacketID(String packetID) {
    262         this.packetID = packetID;
    263     }
    264 
    265     /**
    266      * Returns true if this MessageEvent is a request for notifications.
    267      * Returns false if this MessageEvent is a notification of an event.
    268      *
    269     * @return true if this message is a request for notifications.
    270      */
    271     public boolean isMessageEventRequest() {
    272         return this.packetID == null;
    273     }
    274 
    275     /**
    276      * Returns the XML representation of a Message Event according the specification.
    277      *
    278      * Usually the XML representation will be inside of a Message XML representation like
    279      * in the following examples:<p>
    280      *
    281      * Request to be notified when displayed:
    282      * <pre>
    283      * &lt;message
    284      *    to='romeo (at) montague.net/orchard'
    285      *    from='juliet (at) capulet.com/balcony'
    286      *    id='message22'&gt;
    287      * &lt;x xmlns='jabber:x:event'&gt;
    288      *   &lt;displayed/&gt;
    289      * &lt;/x&gt;
    290      * &lt;/message&gt;
    291      * </pre>
    292      *
    293      * Notification of displayed:
    294      * <pre>
    295      * &lt;message
    296      *    from='romeo (at) montague.net/orchard'
    297      *    to='juliet (at) capulet.com/balcony'&gt;
    298      * &lt;x xmlns='jabber:x:event'&gt;
    299      *   &lt;displayed/&gt;
    300      *   &lt;id&gt;message22&lt;/id&gt;
    301      * &lt;/x&gt;
    302      * &lt;/message&gt;
    303      * </pre>
    304      *
    305      */
    306     public String toXML() {
    307         StringBuilder buf = new StringBuilder();
    308         buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
    309             "\">");
    310         // Note: Cancellation events don't specify any tag. They just send the packetID
    311 
    312         // Add the offline tag if the sender requests to be notified of offline events or if
    313         // the target is offline
    314         if (isOffline())
    315             buf.append("<").append(MessageEvent.OFFLINE).append("/>");
    316         // Add the delivered tag if the sender requests to be notified when the message is
    317         // delivered or if the target notifies that the message has been delivered
    318         if (isDelivered())
    319             buf.append("<").append(MessageEvent.DELIVERED).append("/>");
    320         // Add the displayed tag if the sender requests to be notified when the message is
    321         // displayed or if the target notifies that the message has been displayed
    322         if (isDisplayed())
    323             buf.append("<").append(MessageEvent.DISPLAYED).append("/>");
    324         // Add the composing tag if the sender requests to be notified when the target is
    325         // composing a reply or if the target notifies that he/she is composing a reply
    326         if (isComposing())
    327             buf.append("<").append(MessageEvent.COMPOSING).append("/>");
    328         // Add the id tag only if the MessageEvent is a notification message (not a request)
    329         if (getPacketID() != null)
    330             buf.append("<id>").append(getPacketID()).append("</id>");
    331         buf.append("</").append(getElementName()).append(">");
    332         return buf.toString();
    333     }
    334 
    335 }
    336