Home | History | Annotate | Download | only in user
      1 /**
      2  * Copyright 2003-2007 Jive Software.
      3  *
      4  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.jivesoftware.smackx.workgroup.user;
     18 
     19 import org.jivesoftware.smackx.workgroup.MetaData;
     20 import org.jivesoftware.smackx.workgroup.WorkgroupInvitation;
     21 import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener;
     22 import org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm;
     23 import org.jivesoftware.smackx.workgroup.packet.DepartQueuePacket;
     24 import org.jivesoftware.smackx.workgroup.packet.QueueUpdate;
     25 import org.jivesoftware.smackx.workgroup.packet.SessionID;
     26 import org.jivesoftware.smackx.workgroup.packet.UserID;
     27 import org.jivesoftware.smackx.workgroup.settings.*;
     28 import org.jivesoftware.smack.*;
     29 import org.jivesoftware.smack.filter.*;
     30 import org.jivesoftware.smack.packet.*;
     31 import org.jivesoftware.smack.util.StringUtils;
     32 import org.jivesoftware.smackx.Form;
     33 import org.jivesoftware.smackx.FormField;
     34 import org.jivesoftware.smackx.ServiceDiscoveryManager;
     35 import org.jivesoftware.smackx.muc.MultiUserChat;
     36 import org.jivesoftware.smackx.packet.DataForm;
     37 import org.jivesoftware.smackx.packet.DiscoverInfo;
     38 import org.jivesoftware.smackx.packet.MUCUser;
     39 
     40 import java.util.ArrayList;
     41 import java.util.Iterator;
     42 import java.util.List;
     43 import java.util.Map;
     44 
     45 /**
     46  * Provides workgroup services for users. Users can join the workgroup queue, depart the
     47  * queue, find status information about their placement in the queue, and register to
     48  * be notified when they are routed to an agent.<p>
     49  * <p/>
     50  * This class only provides a users perspective into a workgroup and is not intended
     51  * for use by agents.
     52  *
     53  * @author Matt Tucker
     54  * @author Derek DeMoro
     55  */
     56 public class Workgroup {
     57 
     58     private String workgroupJID;
     59     private Connection connection;
     60     private boolean inQueue;
     61     private List<WorkgroupInvitationListener> invitationListeners;
     62     private List<QueueListener> queueListeners;
     63 
     64     private int queuePosition = -1;
     65     private int queueRemainingTime = -1;
     66 
     67     /**
     68      * Creates a new workgroup instance using the specified workgroup JID
     69      * (eg support (at) workgroup.example.com) and XMPP connection. The connection must have
     70      * undergone a successful login before being used to construct an instance of
     71      * this class.
     72      *
     73      * @param workgroupJID the JID of the workgroup.
     74      * @param connection   an XMPP connection which must have already undergone a
     75      *                     successful login.
     76      */
     77     public Workgroup(String workgroupJID, Connection connection) {
     78         // Login must have been done before passing in connection.
     79         if (!connection.isAuthenticated()) {
     80             throw new IllegalStateException("Must login to server before creating workgroup.");
     81         }
     82 
     83         this.workgroupJID = workgroupJID;
     84         this.connection = connection;
     85         inQueue = false;
     86         invitationListeners = new ArrayList<WorkgroupInvitationListener>();
     87         queueListeners = new ArrayList<QueueListener>();
     88 
     89         // Register as a queue listener for internal usage by this instance.
     90         addQueueListener(new QueueListener() {
     91             public void joinedQueue() {
     92                 inQueue = true;
     93             }
     94 
     95             public void departedQueue() {
     96                 inQueue = false;
     97                 queuePosition = -1;
     98                 queueRemainingTime = -1;
     99             }
    100 
    101             public void queuePositionUpdated(int currentPosition) {
    102                 queuePosition = currentPosition;
    103             }
    104 
    105             public void queueWaitTimeUpdated(int secondsRemaining) {
    106                 queueRemainingTime = secondsRemaining;
    107             }
    108         });
    109 
    110         /**
    111          * Internal handling of an invitation.Recieving an invitation removes the user from the queue.
    112          */
    113         MultiUserChat.addInvitationListener(connection,
    114                 new org.jivesoftware.smackx.muc.InvitationListener() {
    115                     public void invitationReceived(Connection conn, String room, String inviter,
    116                                                    String reason, String password, Message message) {
    117                         inQueue = false;
    118                         queuePosition = -1;
    119                         queueRemainingTime = -1;
    120                     }
    121                 });
    122 
    123         // Register a packet listener for all the messages sent to this client.
    124         PacketFilter typeFilter = new PacketTypeFilter(Message.class);
    125 
    126         connection.addPacketListener(new PacketListener() {
    127             public void processPacket(Packet packet) {
    128                 handlePacket(packet);
    129             }
    130         }, typeFilter);
    131     }
    132 
    133     /**
    134      * Returns the name of this workgroup (eg support (at) example.com).
    135      *
    136      * @return the name of the workgroup.
    137      */
    138     public String getWorkgroupJID() {
    139         return workgroupJID;
    140     }
    141 
    142     /**
    143      * Returns true if the user is currently waiting in the workgroup queue.
    144      *
    145      * @return true if currently waiting in the queue.
    146      */
    147     public boolean isInQueue() {
    148         return inQueue;
    149     }
    150 
    151     /**
    152      * Returns true if the workgroup is available for receiving new requests. The workgroup will be
    153      * available only when agents are available for this workgroup.
    154      *
    155      * @return true if the workgroup is available for receiving new requests.
    156      */
    157     public boolean isAvailable() {
    158         Presence directedPresence = new Presence(Presence.Type.available);
    159         directedPresence.setTo(workgroupJID);
    160         PacketFilter typeFilter = new PacketTypeFilter(Presence.class);
    161         PacketFilter fromFilter = new FromContainsFilter(workgroupJID);
    162         PacketCollector collector = connection.createPacketCollector(new AndFilter(fromFilter,
    163                 typeFilter));
    164 
    165         connection.sendPacket(directedPresence);
    166 
    167         Presence response = (Presence)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    168 
    169         // Cancel the collector.
    170         collector.cancel();
    171         if (response == null) {
    172             return false;
    173         }
    174         else if (response.getError() != null) {
    175             return false;
    176         }
    177         else {
    178             return Presence.Type.available == response.getType();
    179         }
    180     }
    181 
    182     /**
    183      * Returns the users current position in the workgroup queue. A value of 0 means
    184      * the user is next in line to be routed; therefore, if the queue position
    185      * is being displayed to the end user it is usually a good idea to add 1 to
    186      * the value this method returns before display. If the user is not currently
    187      * waiting in the workgroup, or no queue position information is available, -1
    188      * will be returned.
    189      *
    190      * @return the user's current position in the workgroup queue, or -1 if the
    191      *         position isn't available or if the user isn't in the queue.
    192      */
    193     public int getQueuePosition() {
    194         return queuePosition;
    195     }
    196 
    197     /**
    198      * Returns the estimated time (in seconds) that the user has to left wait in
    199      * the workgroup queue before being routed. If the user is not currently waiting
    200      * int he workgroup, or no queue time information is available, -1 will be
    201      * returned.
    202      *
    203      * @return the estimated time remaining (in seconds) that the user has to
    204      *         wait inthe workgroupu queue, or -1 if time information isn't available
    205      *         or if the user isn't int the queue.
    206      */
    207     public int getQueueRemainingTime() {
    208         return queueRemainingTime;
    209     }
    210 
    211     /**
    212      * Joins the workgroup queue to wait to be routed to an agent. After joining
    213      * the queue, queue status events will be sent to indicate the user's position and
    214      * estimated time left in the queue. Once joining the queue, there are three ways
    215      * the user can leave the queue: <ul>
    216      * <p/>
    217      * <li>The user is routed to an agent, which triggers a GroupChat invitation.
    218      * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
    219      * <li>A server error occurs, or an administrator explicitly removes the user
    220      * from the queue.
    221      * </ul>
    222      * <p/>
    223      * A user cannot request to join the queue again if already in the queue. Therefore,
    224      * this method will throw an IllegalStateException if the user is already in the queue.<p>
    225      * <p/>
    226      * Some servers may be configured to require certain meta-data in order to
    227      * join the queue. In that case, the {@link #joinQueue(Form)} method should be
    228      * used instead of this method so that meta-data may be passed in.<p>
    229      * <p/>
    230      * The server tracks the conversations that a user has with agents over time. By
    231      * default, that tracking is done using the user's JID. However, this is not always
    232      * possible. For example, when the user is logged in anonymously using a web client.
    233      * In that case the user ID might be a randomly generated value put into a persistent
    234      * cookie or a username obtained via the session. A userID can be explicitly
    235      * passed in by using the {@link #joinQueue(Form, String)} method. When specified,
    236      * that userID will be used instead of the user's JID to track conversations. The
    237      * server will ignore a manually specified userID if the user's connection to the server
    238      * is not anonymous.
    239      *
    240      * @throws XMPPException if an error occured joining the queue. An error may indicate
    241      *                       that a connection failure occured or that the server explicitly rejected the
    242      *                       request to join the queue.
    243      */
    244     public void joinQueue() throws XMPPException {
    245         joinQueue(null);
    246     }
    247 
    248     /**
    249      * Joins the workgroup queue to wait to be routed to an agent. After joining
    250      * the queue, queue status events will be sent to indicate the user's position and
    251      * estimated time left in the queue. Once joining the queue, there are three ways
    252      * the user can leave the queue: <ul>
    253      * <p/>
    254      * <li>The user is routed to an agent, which triggers a GroupChat invitation.
    255      * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
    256      * <li>A server error occurs, or an administrator explicitly removes the user
    257      * from the queue.
    258      * </ul>
    259      * <p/>
    260      * A user cannot request to join the queue again if already in the queue. Therefore,
    261      * this method will throw an IllegalStateException if the user is already in the queue.<p>
    262      * <p/>
    263      * Some servers may be configured to require certain meta-data in order to
    264      * join the queue.<p>
    265      * <p/>
    266      * The server tracks the conversations that a user has with agents over time. By
    267      * default, that tracking is done using the user's JID. However, this is not always
    268      * possible. For example, when the user is logged in anonymously using a web client.
    269      * In that case the user ID might be a randomly generated value put into a persistent
    270      * cookie or a username obtained via the session. A userID can be explicitly
    271      * passed in by using the {@link #joinQueue(Form, String)} method. When specified,
    272      * that userID will be used instead of the user's JID to track conversations. The
    273      * server will ignore a manually specified userID if the user's connection to the server
    274      * is not anonymous.
    275      *
    276      * @param answerForm the completed form the send for the join request.
    277      * @throws XMPPException if an error occured joining the queue. An error may indicate
    278      *                       that a connection failure occured or that the server explicitly rejected the
    279      *                       request to join the queue.
    280      */
    281     public void joinQueue(Form answerForm) throws XMPPException {
    282         joinQueue(answerForm, null);
    283     }
    284 
    285     /**
    286      * <p>Joins the workgroup queue to wait to be routed to an agent. After joining
    287      * the queue, queue status events will be sent to indicate the user's position and
    288      * estimated time left in the queue. Once joining the queue, there are three ways
    289      * the user can leave the queue: <ul>
    290      * <p/>
    291      * <li>The user is routed to an agent, which triggers a GroupChat invitation.
    292      * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
    293      * <li>A server error occurs, or an administrator explicitly removes the user
    294      * from the queue.
    295      * </ul>
    296      * <p/>
    297      * A user cannot request to join the queue again if already in the queue. Therefore,
    298      * this method will throw an IllegalStateException if the user is already in the queue.<p>
    299      * <p/>
    300      * Some servers may be configured to require certain meta-data in order to
    301      * join the queue.<p>
    302      * <p/>
    303      * The server tracks the conversations that a user has with agents over time. By
    304      * default, that tracking is done using the user's JID. However, this is not always
    305      * possible. For example, when the user is logged in anonymously using a web client.
    306      * In that case the user ID might be a randomly generated value put into a persistent
    307      * cookie or a username obtained via the session. When specified, that userID will
    308      * be used instead of the user's JID to track conversations. The server will ignore a
    309      * manually specified userID if the user's connection to the server is not anonymous.
    310      *
    311      * @param answerForm the completed form associated with the join reqest.
    312      * @param userID     String that represents the ID of the user when using anonymous sessions
    313      *                   or <tt>null</tt> if a userID should not be used.
    314      * @throws XMPPException if an error occured joining the queue. An error may indicate
    315      *                       that a connection failure occured or that the server explicitly rejected the
    316      *                       request to join the queue.
    317      */
    318     public void joinQueue(Form answerForm, String userID) throws XMPPException {
    319         // If already in the queue ignore the join request.
    320         if (inQueue) {
    321             throw new IllegalStateException("Already in queue " + workgroupJID);
    322         }
    323 
    324         JoinQueuePacket joinPacket = new JoinQueuePacket(workgroupJID, answerForm, userID);
    325 
    326 
    327         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(joinPacket.getPacketID()));
    328 
    329         this.connection.sendPacket(joinPacket);
    330 
    331         IQ response = (IQ)collector.nextResult(10000);
    332 
    333         // Cancel the collector.
    334         collector.cancel();
    335         if (response == null) {
    336             throw new XMPPException("No response from the server.");
    337         }
    338         if (response.getError() != null) {
    339             throw new XMPPException(response.getError());
    340         }
    341 
    342         // Notify listeners that we've joined the queue.
    343         fireQueueJoinedEvent();
    344     }
    345 
    346     /**
    347      * <p>Joins the workgroup queue to wait to be routed to an agent. After joining
    348      * the queue, queue status events will be sent to indicate the user's position and
    349      * estimated time left in the queue. Once joining the queue, there are three ways
    350      * the user can leave the queue: <ul>
    351      * <p/>
    352      * <li>The user is routed to an agent, which triggers a GroupChat invitation.
    353      * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
    354      * <li>A server error occurs, or an administrator explicitly removes the user
    355      * from the queue.
    356      * </ul>
    357      * <p/>
    358      * A user cannot request to join the queue again if already in the queue. Therefore,
    359      * this method will throw an IllegalStateException if the user is already in the queue.<p>
    360      * <p/>
    361      * Some servers may be configured to require certain meta-data in order to
    362      * join the queue.<p>
    363      * <p/>
    364      * The server tracks the conversations that a user has with agents over time. By
    365      * default, that tracking is done using the user's JID. However, this is not always
    366      * possible. For example, when the user is logged in anonymously using a web client.
    367      * In that case the user ID might be a randomly generated value put into a persistent
    368      * cookie or a username obtained via the session. When specified, that userID will
    369      * be used instead of the user's JID to track conversations. The server will ignore a
    370      * manually specified userID if the user's connection to the server is not anonymous.
    371      *
    372      * @param metadata metadata to create a dataform from.
    373      * @param userID   String that represents the ID of the user when using anonymous sessions
    374      *                 or <tt>null</tt> if a userID should not be used.
    375      * @throws XMPPException if an error occured joining the queue. An error may indicate
    376      *                       that a connection failure occured or that the server explicitly rejected the
    377      *                       request to join the queue.
    378      */
    379     public void joinQueue(Map<String,Object> metadata, String userID) throws XMPPException {
    380         // If already in the queue ignore the join request.
    381         if (inQueue) {
    382             throw new IllegalStateException("Already in queue " + workgroupJID);
    383         }
    384 
    385         // Build dataform from metadata
    386         Form form = new Form(Form.TYPE_SUBMIT);
    387         Iterator<String> iter = metadata.keySet().iterator();
    388         while (iter.hasNext()) {
    389             String name = iter.next();
    390             String value = metadata.get(name).toString();
    391 
    392             String escapedName = StringUtils.escapeForXML(name);
    393             String escapedValue = StringUtils.escapeForXML(value);
    394 
    395             FormField field = new FormField(escapedName);
    396             field.setType(FormField.TYPE_TEXT_SINGLE);
    397             form.addField(field);
    398             form.setAnswer(escapedName, escapedValue);
    399         }
    400         joinQueue(form, userID);
    401     }
    402 
    403     /**
    404      * Departs the workgroup queue. If the user is not currently in the queue, this
    405      * method will do nothing.<p>
    406      * <p/>
    407      * Normally, the user would not manually leave the queue. However, they may wish to
    408      * under certain circumstances -- for example, if they no longer wish to be routed
    409      * to an agent because they've been waiting too long.
    410      *
    411      * @throws XMPPException if an error occured trying to send the depart queue
    412      *                       request to the server.
    413      */
    414     public void departQueue() throws XMPPException {
    415         // If not in the queue ignore the depart request.
    416         if (!inQueue) {
    417             return;
    418         }
    419 
    420         DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID);
    421         PacketCollector collector = this.connection.createPacketCollector(new PacketIDFilter(departPacket.getPacketID()));
    422 
    423         connection.sendPacket(departPacket);
    424 
    425         IQ response = (IQ)collector.nextResult(5000);
    426         collector.cancel();
    427         if (response == null) {
    428             throw new XMPPException("No response from the server.");
    429         }
    430         if (response.getError() != null) {
    431             throw new XMPPException(response.getError());
    432         }
    433 
    434         // Notify listeners that we're no longer in the queue.
    435         fireQueueDepartedEvent();
    436     }
    437 
    438     /**
    439      * Adds a queue listener that will be notified of queue events for the user
    440      * that created this Workgroup instance.
    441      *
    442      * @param queueListener the queue listener.
    443      */
    444     public void addQueueListener(QueueListener queueListener) {
    445         synchronized (queueListeners) {
    446             if (!queueListeners.contains(queueListener)) {
    447                 queueListeners.add(queueListener);
    448             }
    449         }
    450     }
    451 
    452     /**
    453      * Removes a queue listener.
    454      *
    455      * @param queueListener the queue listener.
    456      */
    457     public void removeQueueListener(QueueListener queueListener) {
    458         synchronized (queueListeners) {
    459             queueListeners.remove(queueListener);
    460         }
    461     }
    462 
    463     /**
    464      * Adds an invitation listener that will be notified of groupchat invitations
    465      * from the workgroup for the the user that created this Workgroup instance.
    466      *
    467      * @param invitationListener the invitation listener.
    468      */
    469     public void addInvitationListener(WorkgroupInvitationListener invitationListener) {
    470         synchronized (invitationListeners) {
    471             if (!invitationListeners.contains(invitationListener)) {
    472                 invitationListeners.add(invitationListener);
    473             }
    474         }
    475     }
    476 
    477     /**
    478      * Removes an invitation listener.
    479      *
    480      * @param invitationListener the invitation listener.
    481      */
    482     public void removeQueueListener(WorkgroupInvitationListener invitationListener) {
    483         synchronized (invitationListeners) {
    484             invitationListeners.remove(invitationListener);
    485         }
    486     }
    487 
    488     private void fireInvitationEvent(WorkgroupInvitation invitation) {
    489         synchronized (invitationListeners) {
    490             for (Iterator<WorkgroupInvitationListener> i = invitationListeners.iterator(); i.hasNext();) {
    491                 WorkgroupInvitationListener listener = i.next();
    492                 listener.invitationReceived(invitation);
    493             }
    494         }
    495     }
    496 
    497     private void fireQueueJoinedEvent() {
    498         synchronized (queueListeners) {
    499             for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
    500                 QueueListener listener = i.next();
    501                 listener.joinedQueue();
    502             }
    503         }
    504     }
    505 
    506     private void fireQueueDepartedEvent() {
    507         synchronized (queueListeners) {
    508             for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
    509                 QueueListener listener = i.next();
    510                 listener.departedQueue();
    511             }
    512         }
    513     }
    514 
    515     private void fireQueuePositionEvent(int currentPosition) {
    516         synchronized (queueListeners) {
    517             for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
    518                 QueueListener listener = i.next();
    519                 listener.queuePositionUpdated(currentPosition);
    520             }
    521         }
    522     }
    523 
    524     private void fireQueueTimeEvent(int secondsRemaining) {
    525         synchronized (queueListeners) {
    526             for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
    527                 QueueListener listener = i.next();
    528                 listener.queueWaitTimeUpdated(secondsRemaining);
    529             }
    530         }
    531     }
    532 
    533     // PacketListener Implementation.
    534 
    535     private void handlePacket(Packet packet) {
    536         if (packet instanceof Message) {
    537             Message msg = (Message)packet;
    538             // Check to see if the user left the queue.
    539             PacketExtension pe = msg.getExtension("depart-queue", "http://jabber.org/protocol/workgroup");
    540             PacketExtension queueStatus = msg.getExtension("queue-status", "http://jabber.org/protocol/workgroup");
    541 
    542             if (pe != null) {
    543                 fireQueueDepartedEvent();
    544             }
    545             else if (queueStatus != null) {
    546                 QueueUpdate queueUpdate = (QueueUpdate)queueStatus;
    547                 if (queueUpdate.getPosition() != -1) {
    548                     fireQueuePositionEvent(queueUpdate.getPosition());
    549                 }
    550                 if (queueUpdate.getRemaingTime() != -1) {
    551                     fireQueueTimeEvent(queueUpdate.getRemaingTime());
    552                 }
    553             }
    554 
    555             else {
    556                 // Check if a room invitation was sent and if the sender is the workgroup
    557                 MUCUser mucUser = (MUCUser)msg.getExtension("x", "http://jabber.org/protocol/muc#user");
    558                 MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null;
    559                 if (invite != null && workgroupJID.equals(invite.getFrom())) {
    560                     String sessionID = null;
    561                     Map<String, List<String>> metaData = null;
    562 
    563                     pe = msg.getExtension(SessionID.ELEMENT_NAME,
    564                             SessionID.NAMESPACE);
    565                     if (pe != null) {
    566                         sessionID = ((SessionID)pe).getSessionID();
    567                     }
    568 
    569                     pe = msg.getExtension(MetaData.ELEMENT_NAME,
    570                             MetaData.NAMESPACE);
    571                     if (pe != null) {
    572                         metaData = ((MetaData)pe).getMetaData();
    573                     }
    574 
    575                     WorkgroupInvitation inv = new WorkgroupInvitation(connection.getUser(), msg.getFrom(),
    576                             workgroupJID, sessionID, msg.getBody(),
    577                             msg.getFrom(), metaData);
    578 
    579                     fireInvitationEvent(inv);
    580                 }
    581             }
    582         }
    583     }
    584 
    585     /**
    586      * IQ packet to request joining the workgroup queue.
    587      */
    588     private class JoinQueuePacket extends IQ {
    589 
    590         private String userID = null;
    591         private DataForm form;
    592 
    593         public JoinQueuePacket(String workgroup, Form answerForm, String userID) {
    594             this.userID = userID;
    595 
    596             setTo(workgroup);
    597             setType(IQ.Type.SET);
    598 
    599             form = answerForm.getDataFormToSend();
    600             addExtension(form);
    601         }
    602 
    603         public String getChildElementXML() {
    604             StringBuilder buf = new StringBuilder();
    605 
    606             buf.append("<join-queue xmlns=\"http://jabber.org/protocol/workgroup\">");
    607             buf.append("<queue-notifications/>");
    608             // Add the user unique identification if the session is anonymous
    609             if (connection.isAnonymous()) {
    610                 buf.append(new UserID(userID).toXML());
    611             }
    612 
    613             // Append data form text
    614             buf.append(form.toXML());
    615 
    616             buf.append("</join-queue>");
    617 
    618             return buf.toString();
    619         }
    620     }
    621 
    622     /**
    623      * Returns a single chat setting based on it's identified key.
    624      *
    625      * @param key the key to find.
    626      * @return the ChatSetting if found, otherwise false.
    627      * @throws XMPPException if an error occurs while getting information from the server.
    628      */
    629     public ChatSetting getChatSetting(String key) throws XMPPException {
    630         ChatSettings chatSettings = getChatSettings(key, -1);
    631         return chatSettings.getFirstEntry();
    632     }
    633 
    634     /**
    635      * Returns ChatSettings based on type.
    636      *
    637      * @param type the type of ChatSettings to return.
    638      * @return the ChatSettings of given type, otherwise null.
    639      * @throws XMPPException if an error occurs while getting information from the server.
    640      */
    641     public ChatSettings getChatSettings(int type) throws XMPPException {
    642         return getChatSettings(null, type);
    643     }
    644 
    645     /**
    646      * Returns all ChatSettings.
    647      *
    648      * @return all ChatSettings of a given workgroup.
    649      * @throws XMPPException if an error occurs while getting information from the server.
    650      */
    651     public ChatSettings getChatSettings() throws XMPPException {
    652         return getChatSettings(null, -1);
    653     }
    654 
    655 
    656     /**
    657      * Asks the workgroup for it's Chat Settings.
    658      *
    659      * @return key specify a key to retrieve only that settings. Otherwise for all settings, key should be null.
    660      * @throws XMPPException if an error occurs while getting information from the server.
    661      */
    662     private ChatSettings getChatSettings(String key, int type) throws XMPPException {
    663         ChatSettings request = new ChatSettings();
    664         if (key != null) {
    665             request.setKey(key);
    666         }
    667         if (type != -1) {
    668             request.setType(type);
    669         }
    670         request.setType(IQ.Type.GET);
    671         request.setTo(workgroupJID);
    672 
    673         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
    674         connection.sendPacket(request);
    675 
    676 
    677         ChatSettings response = (ChatSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    678 
    679         // Cancel the collector.
    680         collector.cancel();
    681         if (response == null) {
    682             throw new XMPPException("No response from server.");
    683         }
    684         if (response.getError() != null) {
    685             throw new XMPPException(response.getError());
    686         }
    687         return response;
    688     }
    689 
    690     /**
    691      * The workgroup service may be configured to send email. This queries the Workgroup Service
    692      * to see if the email service has been configured and is available.
    693      *
    694      * @return true if the email service is available, otherwise return false.
    695      */
    696     public boolean isEmailAvailable() {
    697         ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
    698 
    699         try {
    700             String workgroupService = StringUtils.parseServer(workgroupJID);
    701             DiscoverInfo infoResult = discoManager.discoverInfo(workgroupService);
    702             return infoResult.containsFeature("jive:email:provider");
    703         }
    704         catch (XMPPException e) {
    705             return false;
    706         }
    707     }
    708 
    709     /**
    710      * Asks the workgroup for it's Offline Settings.
    711      *
    712      * @return offlineSettings the offline settings for this workgroup.
    713      * @throws XMPPException if an error occurs while getting information from the server.
    714      */
    715     public OfflineSettings getOfflineSettings() throws XMPPException {
    716         OfflineSettings request = new OfflineSettings();
    717         request.setType(IQ.Type.GET);
    718         request.setTo(workgroupJID);
    719 
    720         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
    721         connection.sendPacket(request);
    722 
    723 
    724         OfflineSettings response = (OfflineSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    725 
    726         // Cancel the collector.
    727         collector.cancel();
    728         if (response == null) {
    729             throw new XMPPException("No response from server.");
    730         }
    731         if (response.getError() != null) {
    732             throw new XMPPException(response.getError());
    733         }
    734         return response;
    735     }
    736 
    737     /**
    738      * Asks the workgroup for it's Sound Settings.
    739      *
    740      * @return soundSettings the sound settings for the specified workgroup.
    741      * @throws XMPPException if an error occurs while getting information from the server.
    742      */
    743     public SoundSettings getSoundSettings() throws XMPPException {
    744         SoundSettings request = new SoundSettings();
    745         request.setType(IQ.Type.GET);
    746         request.setTo(workgroupJID);
    747 
    748         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
    749         connection.sendPacket(request);
    750 
    751 
    752         SoundSettings response = (SoundSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    753 
    754         // Cancel the collector.
    755         collector.cancel();
    756         if (response == null) {
    757             throw new XMPPException("No response from server.");
    758         }
    759         if (response.getError() != null) {
    760             throw new XMPPException(response.getError());
    761         }
    762         return response;
    763     }
    764 
    765     /**
    766      * Asks the workgroup for it's Properties
    767      *
    768      * @return the WorkgroupProperties for the specified workgroup.
    769      * @throws XMPPException if an error occurs while getting information from the server.
    770      */
    771     public WorkgroupProperties getWorkgroupProperties() throws XMPPException {
    772         WorkgroupProperties request = new WorkgroupProperties();
    773         request.setType(IQ.Type.GET);
    774         request.setTo(workgroupJID);
    775 
    776         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
    777         connection.sendPacket(request);
    778 
    779 
    780         WorkgroupProperties response = (WorkgroupProperties)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    781 
    782         // Cancel the collector.
    783         collector.cancel();
    784         if (response == null) {
    785             throw new XMPPException("No response from server.");
    786         }
    787         if (response.getError() != null) {
    788             throw new XMPPException(response.getError());
    789         }
    790         return response;
    791     }
    792 
    793     /**
    794      * Asks the workgroup for it's Properties
    795      *
    796      * @param jid the jid of the user who's information you would like the workgroup to retreive.
    797      * @return the WorkgroupProperties for the specified workgroup.
    798      * @throws XMPPException if an error occurs while getting information from the server.
    799      */
    800     public WorkgroupProperties getWorkgroupProperties(String jid) throws XMPPException {
    801         WorkgroupProperties request = new WorkgroupProperties();
    802         request.setJid(jid);
    803         request.setType(IQ.Type.GET);
    804         request.setTo(workgroupJID);
    805 
    806         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
    807         connection.sendPacket(request);
    808 
    809 
    810         WorkgroupProperties response = (WorkgroupProperties)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    811 
    812         // Cancel the collector.
    813         collector.cancel();
    814         if (response == null) {
    815             throw new XMPPException("No response from server.");
    816         }
    817         if (response.getError() != null) {
    818             throw new XMPPException(response.getError());
    819         }
    820         return response;
    821     }
    822 
    823 
    824     /**
    825      * Returns the Form to use for all clients of a workgroup. It is unlikely that the server
    826      * will change the form (without a restart) so it is safe to keep the returned form
    827      * for future submissions.
    828      *
    829      * @return the Form to use for searching transcripts.
    830      * @throws XMPPException if an error occurs while sending the request to the server.
    831      */
    832     public Form getWorkgroupForm() throws XMPPException {
    833         WorkgroupForm workgroupForm = new WorkgroupForm();
    834         workgroupForm.setType(IQ.Type.GET);
    835         workgroupForm.setTo(workgroupJID);
    836 
    837         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(workgroupForm.getPacketID()));
    838         connection.sendPacket(workgroupForm);
    839 
    840         WorkgroupForm response = (WorkgroupForm)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    841 
    842         // Cancel the collector.
    843         collector.cancel();
    844         if (response == null) {
    845             throw new XMPPException("No response from server on status set.");
    846         }
    847         if (response.getError() != null) {
    848             throw new XMPPException(response.getError());
    849         }
    850         return Form.getFormFrom(response);
    851     }
    852 
    853     /*
    854     public static void main(String args[]) throws Exception {
    855         Connection con = new XMPPConnection("anteros");
    856         con.connect();
    857         con.loginAnonymously();
    858 
    859         Workgroup workgroup = new Workgroup("demo (at) workgroup.anteros", con);
    860         WorkgroupProperties props = workgroup.getWorkgroupProperties("derek (at) anteros.com");
    861 
    862         System.out.print(props);
    863         con.disconnect();
    864     }
    865     */
    866 
    867 
    868 }