001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.workgroup.user; 018 019import java.util.Iterator; 020import java.util.List; 021import java.util.Map; 022import java.util.concurrent.CopyOnWriteArraySet; 023 024import org.jivesoftware.smack.SmackException; 025import org.jivesoftware.smack.SmackException.NoResponseException; 026import org.jivesoftware.smack.SmackException.NotConnectedException; 027import org.jivesoftware.smack.StanzaCollector; 028import org.jivesoftware.smack.StanzaListener; 029import org.jivesoftware.smack.XMPPConnection; 030import org.jivesoftware.smack.XMPPException; 031import org.jivesoftware.smack.XMPPException.XMPPErrorException; 032import org.jivesoftware.smack.filter.AndFilter; 033import org.jivesoftware.smack.filter.FromMatchesFilter; 034import org.jivesoftware.smack.filter.StanzaFilter; 035import org.jivesoftware.smack.filter.StanzaTypeFilter; 036import org.jivesoftware.smack.packet.ExtensionElement; 037import org.jivesoftware.smack.packet.IQ; 038import org.jivesoftware.smack.packet.Message; 039import org.jivesoftware.smack.packet.Presence; 040import org.jivesoftware.smack.packet.Stanza; 041 042import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 043import org.jivesoftware.smackx.disco.packet.DiscoverInfo; 044import org.jivesoftware.smackx.muc.MultiUserChatManager; 045import org.jivesoftware.smackx.muc.packet.MUCUser; 046import org.jivesoftware.smackx.workgroup.MetaData; 047import org.jivesoftware.smackx.workgroup.WorkgroupInvitation; 048import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener; 049import org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm; 050import org.jivesoftware.smackx.workgroup.packet.DepartQueuePacket; 051import org.jivesoftware.smackx.workgroup.packet.QueueUpdate; 052import org.jivesoftware.smackx.workgroup.packet.SessionID; 053import org.jivesoftware.smackx.workgroup.packet.UserID; 054import org.jivesoftware.smackx.workgroup.settings.ChatSetting; 055import org.jivesoftware.smackx.workgroup.settings.ChatSettings; 056import org.jivesoftware.smackx.workgroup.settings.OfflineSettings; 057import org.jivesoftware.smackx.workgroup.settings.SoundSettings; 058import org.jivesoftware.smackx.workgroup.settings.WorkgroupProperties; 059import org.jivesoftware.smackx.xdata.Form; 060import org.jivesoftware.smackx.xdata.FormField; 061import org.jivesoftware.smackx.xdata.packet.DataForm; 062 063import org.jxmpp.jid.DomainBareJid; 064import org.jxmpp.jid.EntityJid; 065import org.jxmpp.jid.Jid; 066 067/** 068 * Provides workgroup services for users. Users can join the workgroup queue, depart the 069 * queue, find status information about their placement in the queue, and register to 070 * be notified when they are routed to an agent.<p> 071 * 072 * This class only provides a users perspective into a workgroup and is not intended 073 * for use by agents. 074 * 075 * @author Matt Tucker 076 * @author Derek DeMoro 077 */ 078public class Workgroup { 079 080 private final Jid workgroupJID; 081 private final XMPPConnection connection; 082 private boolean inQueue; 083 private final CopyOnWriteArraySet<WorkgroupInvitationListener> invitationListeners; 084 private final CopyOnWriteArraySet<QueueListener> queueListeners; 085 086 private int queuePosition = -1; 087 private int queueRemainingTime = -1; 088 089 /** 090 * Creates a new workgroup instance using the specified workgroup JID 091 * (eg support@workgroup.example.com) and XMPP connection. The connection must have 092 * undergone a successful login before being used to construct an instance of 093 * this class. 094 * 095 * @param workgroupJID the JID of the workgroup. 096 * @param connection an XMPP connection which must have already undergone a 097 * successful login. 098 */ 099 public Workgroup(Jid workgroupJID, XMPPConnection connection) { 100 // Login must have been done before passing in connection. 101 if (!connection.isAuthenticated()) { 102 throw new IllegalStateException("Must login to server before creating workgroup."); 103 } 104 105 this.workgroupJID = workgroupJID; 106 this.connection = connection; 107 inQueue = false; 108 invitationListeners = new CopyOnWriteArraySet<>(); 109 queueListeners = new CopyOnWriteArraySet<>(); 110 111 // Register as a queue listener for internal usage by this instance. 112 addQueueListener(new QueueListener() { 113 @Override 114 public void joinedQueue() { 115 inQueue = true; 116 } 117 118 @Override 119 public void departedQueue() { 120 inQueue = false; 121 queuePosition = -1; 122 queueRemainingTime = -1; 123 } 124 125 @Override 126 public void queuePositionUpdated(int currentPosition) { 127 queuePosition = currentPosition; 128 } 129 130 @Override 131 public void queueWaitTimeUpdated(int secondsRemaining) { 132 queueRemainingTime = secondsRemaining; 133 } 134 }); 135 136 /** 137 * Internal handling of an invitation.Recieving an invitation removes the user from the queue. 138 */ 139 MultiUserChatManager.getInstanceFor(connection).addInvitationListener( 140 new org.jivesoftware.smackx.muc.InvitationListener() { 141 @Override 142 public void invitationReceived(XMPPConnection conn, org.jivesoftware.smackx.muc.MultiUserChat room, EntityJid inviter, 143 String reason, String password, Message message, MUCUser.Invite invitation) { 144 inQueue = false; 145 queuePosition = -1; 146 queueRemainingTime = -1; 147 } 148 }); 149 150 // Register a packet listener for all the messages sent to this client. 151 StanzaFilter typeFilter = new StanzaTypeFilter(Message.class); 152 153 connection.addAsyncStanzaListener(new StanzaListener() { 154 @Override 155 public void processStanza(Stanza packet) { 156 handlePacket(packet); 157 } 158 }, typeFilter); 159 } 160 161 /** 162 * Returns the name of this workgroup (eg support@example.com). 163 * 164 * @return the name of the workgroup. 165 */ 166 public Jid getWorkgroupJID() { 167 return workgroupJID; 168 } 169 170 /** 171 * Returns true if the user is currently waiting in the workgroup queue. 172 * 173 * @return true if currently waiting in the queue. 174 */ 175 public boolean isInQueue() { 176 return inQueue; 177 } 178 179 /** 180 * Returns true if the workgroup is available for receiving new requests. The workgroup will be 181 * available only when agents are available for this workgroup. 182 * 183 * @return true if the workgroup is available for receiving new requests. 184 * @throws XMPPErrorException 185 * @throws NoResponseException 186 * @throws NotConnectedException 187 * @throws InterruptedException 188 */ 189 public boolean isAvailable() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 190 Presence directedPresence = new Presence(Presence.Type.available); 191 directedPresence.setTo(workgroupJID); 192 StanzaFilter typeFilter = new StanzaTypeFilter(Presence.class); 193 StanzaFilter fromFilter = FromMatchesFilter.create(workgroupJID); 194 StanzaCollector collector = connection.createStanzaCollectorAndSend(new AndFilter(fromFilter, 195 typeFilter), directedPresence); 196 197 Presence response = collector.nextResultOrThrow(); 198 return Presence.Type.available == response.getType(); 199 } 200 201 /** 202 * Returns the users current position in the workgroup queue. A value of 0 means 203 * the user is next in line to be routed; therefore, if the queue position 204 * is being displayed to the end user it is usually a good idea to add 1 to 205 * the value this method returns before display. If the user is not currently 206 * waiting in the workgroup, or no queue position information is available, -1 207 * will be returned. 208 * 209 * @return the user's current position in the workgroup queue, or -1 if the 210 * position isn't available or if the user isn't in the queue. 211 */ 212 public int getQueuePosition() { 213 return queuePosition; 214 } 215 216 /** 217 * Returns the estimated time (in seconds) that the user has to left wait in 218 * the workgroup queue before being routed. If the user is not currently waiting 219 * int he workgroup, or no queue time information is available, -1 will be 220 * returned. 221 * 222 * @return the estimated time remaining (in seconds) that the user has to 223 * wait in the workgroup queue, or -1 if time information isn't available 224 * or if the user isn't int the queue. 225 */ 226 public int getQueueRemainingTime() { 227 return queueRemainingTime; 228 } 229 230 /** 231 * Joins the workgroup queue to wait to be routed to an agent. After joining 232 * the queue, queue status events will be sent to indicate the user's position and 233 * estimated time left in the queue. Once joining the queue, there are three ways 234 * the user can leave the queue: <ul> 235 * 236 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 237 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 238 * <li>A server error occurs, or an administrator explicitly removes the user 239 * from the queue. 240 * </ul> 241 * 242 * A user cannot request to join the queue again if already in the queue. Therefore, 243 * this method will throw an IllegalStateException if the user is already in the queue.<p> 244 * 245 * Some servers may be configured to require certain meta-data in order to 246 * join the queue. In that case, the {@link #joinQueue(Form)} method should be 247 * used instead of this method so that meta-data may be passed in.<p> 248 * 249 * The server tracks the conversations that a user has with agents over time. By 250 * default, that tracking is done using the user's JID. However, this is not always 251 * possible. For example, when the user is logged in anonymously using a web client. 252 * In that case the user ID might be a randomly generated value put into a persistent 253 * cookie or a username obtained via the session. A userID can be explicitly 254 * passed in by using the {@link #joinQueue(Form, Jid)} method. When specified, 255 * that userID will be used instead of the user's JID to track conversations. The 256 * server will ignore a manually specified userID if the user's connection to the server 257 * is not anonymous. 258 * 259 * @throws XMPPException if an error occurred joining the queue. An error may indicate 260 * that a connection failure occurred or that the server explicitly rejected the 261 * request to join the queue. 262 * @throws SmackException 263 * @throws InterruptedException 264 */ 265 public void joinQueue() throws XMPPException, SmackException, InterruptedException { 266 joinQueue(null); 267 } 268 269 /** 270 * Joins the workgroup queue to wait to be routed to an agent. After joining 271 * the queue, queue status events will be sent to indicate the user's position and 272 * estimated time left in the queue. Once joining the queue, there are three ways 273 * the user can leave the queue: <ul> 274 * 275 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 276 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 277 * <li>A server error occurs, or an administrator explicitly removes the user 278 * from the queue. 279 * </ul> 280 * 281 * A user cannot request to join the queue again if already in the queue. Therefore, 282 * this method will throw an IllegalStateException if the user is already in the queue.<p> 283 * 284 * Some servers may be configured to require certain meta-data in order to 285 * join the queue.<p> 286 * 287 * The server tracks the conversations that a user has with agents over time. By 288 * default, that tracking is done using the user's JID. However, this is not always 289 * possible. For example, when the user is logged in anonymously using a web client. 290 * In that case the user ID might be a randomly generated value put into a persistent 291 * cookie or a username obtained via the session. A userID can be explicitly 292 * passed in by using the {@link #joinQueue(Form, Jid)} method. When specified, 293 * that userID will be used instead of the user's JID to track conversations. The 294 * server will ignore a manually specified userID if the user's connection to the server 295 * is not anonymous. 296 * 297 * @param answerForm the completed form the send for the join request. 298 * @throws XMPPException if an error occurred joining the queue. An error may indicate 299 * that a connection failure occurred or that the server explicitly rejected the 300 * request to join the queue. 301 * @throws SmackException 302 * @throws InterruptedException 303 */ 304 public void joinQueue(Form answerForm) throws XMPPException, SmackException, InterruptedException { 305 joinQueue(answerForm, null); 306 } 307 308 /** 309 * <p>Joins the workgroup queue to wait to be routed to an agent. After joining 310 * the queue, queue status events will be sent to indicate the user's position and 311 * estimated time left in the queue. Once joining the queue, there are three ways 312 * the user can leave the queue: <ul> 313 * 314 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 315 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 316 * <li>A server error occurs, or an administrator explicitly removes the user 317 * from the queue. 318 * </ul> 319 * 320 * A user cannot request to join the queue again if already in the queue. Therefore, 321 * this method will throw an IllegalStateException if the user is already in the queue.<p> 322 * 323 * Some servers may be configured to require certain meta-data in order to 324 * join the queue.<p> 325 * 326 * The server tracks the conversations that a user has with agents over time. By 327 * default, that tracking is done using the user's JID. However, this is not always 328 * possible. For example, when the user is logged in anonymously using a web client. 329 * In that case the user ID might be a randomly generated value put into a persistent 330 * cookie or a username obtained via the session. When specified, that userID will 331 * be used instead of the user's JID to track conversations. The server will ignore a 332 * manually specified userID if the user's connection to the server is not anonymous. 333 * 334 * @param answerForm the completed form associated with the join request. 335 * @param userID String that represents the ID of the user when using anonymous sessions 336 * or <tt>null</tt> if a userID should not be used. 337 * @throws XMPPErrorException if an error occurred joining the queue. An error may indicate 338 * that a connection failure occurred or that the server explicitly rejected the 339 * request to join the queue. 340 * @throws NoResponseException 341 * @throws NotConnectedException 342 * @throws InterruptedException 343 */ 344 public void joinQueue(Form answerForm, Jid userID) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 345 // If already in the queue ignore the join request. 346 if (inQueue) { 347 throw new IllegalStateException("Already in queue " + workgroupJID); 348 } 349 350 JoinQueuePacket joinPacket = new JoinQueuePacket(workgroupJID, answerForm, userID); 351 352 connection.createStanzaCollectorAndSend(joinPacket).nextResultOrThrow(); 353 // Notify listeners that we've joined the queue. 354 fireQueueJoinedEvent(); 355 } 356 357 /** 358 * <p>Joins the workgroup queue to wait to be routed to an agent. After joining 359 * the queue, queue status events will be sent to indicate the user's position and 360 * estimated time left in the queue. Once joining the queue, there are three ways 361 * the user can leave the queue: <ul> 362 * 363 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 364 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 365 * <li>A server error occurs, or an administrator explicitly removes the user 366 * from the queue. 367 * </ul> 368 * 369 * A user cannot request to join the queue again if already in the queue. Therefore, 370 * this method will throw an IllegalStateException if the user is already in the queue.<p> 371 * 372 * Some servers may be configured to require certain meta-data in order to 373 * join the queue.<p> 374 * 375 * The server tracks the conversations that a user has with agents over time. By 376 * default, that tracking is done using the user's JID. However, this is not always 377 * possible. For example, when the user is logged in anonymously using a web client. 378 * In that case the user ID might be a randomly generated value put into a persistent 379 * cookie or a username obtained via the session. When specified, that userID will 380 * be used instead of the user's JID to track conversations. The server will ignore a 381 * manually specified userID if the user's connection to the server is not anonymous. 382 * 383 * @param metadata metadata to create a dataform from. 384 * @param userID String that represents the ID of the user when using anonymous sessions 385 * or <tt>null</tt> if a userID should not be used. 386 * @throws XMPPException if an error occurred joining the queue. An error may indicate 387 * that a connection failure occurred or that the server explicitly rejected the 388 * request to join the queue. 389 * @throws SmackException 390 * @throws InterruptedException 391 */ 392 public void joinQueue(Map<String,Object> metadata, Jid userID) throws XMPPException, SmackException, InterruptedException { 393 // If already in the queue ignore the join request. 394 if (inQueue) { 395 throw new IllegalStateException("Already in queue " + workgroupJID); 396 } 397 398 // Build dataform from metadata 399 Form form = new Form(DataForm.Type.submit); 400 Iterator<String> iter = metadata.keySet().iterator(); 401 while (iter.hasNext()) { 402 String name = iter.next(); 403 String value = metadata.get(name).toString(); 404 405 FormField field = new FormField(name); 406 field.setType(FormField.Type.text_single); 407 form.addField(field); 408 form.setAnswer(name, value); 409 } 410 joinQueue(form, userID); 411 } 412 413 /** 414 * Departs the workgroup queue. If the user is not currently in the queue, this 415 * method will do nothing.<p> 416 * 417 * Normally, the user would not manually leave the queue. However, they may wish to 418 * under certain circumstances -- for example, if they no longer wish to be routed 419 * to an agent because they've been waiting too long. 420 * 421 * @throws XMPPErrorException if an error occurred trying to send the depart queue 422 * request to the server. 423 * @throws NoResponseException 424 * @throws NotConnectedException 425 * @throws InterruptedException 426 */ 427 public void departQueue() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 428 // If not in the queue ignore the depart request. 429 if (!inQueue) { 430 return; 431 } 432 433 DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID); 434 connection.createStanzaCollectorAndSend(departPacket).nextResultOrThrow(); 435 436 // Notify listeners that we're no longer in the queue. 437 fireQueueDepartedEvent(); 438 } 439 440 /** 441 * Adds a queue listener that will be notified of queue events for the user 442 * that created this Workgroup instance. 443 * 444 * @param queueListener the queue listener. 445 */ 446 public void addQueueListener(QueueListener queueListener) { 447 queueListeners.add(queueListener); 448 } 449 450 /** 451 * Removes a queue listener. 452 * 453 * @param queueListener the queue listener. 454 */ 455 public void removeQueueListener(QueueListener queueListener) { 456 queueListeners.remove(queueListener); 457 } 458 459 /** 460 * Adds an invitation listener that will be notified of groupchat invitations 461 * from the workgroup for the the user that created this Workgroup instance. 462 * 463 * @param invitationListener the invitation listener. 464 */ 465 public void addInvitationListener(WorkgroupInvitationListener invitationListener) { 466 invitationListeners.add(invitationListener); 467 } 468 469 /** 470 * Removes an invitation listener. 471 * 472 * @param invitationListener the invitation listener. 473 */ 474 public void removeQueueListener(WorkgroupInvitationListener invitationListener) { 475 invitationListeners.remove(invitationListener); 476 } 477 478 private void fireInvitationEvent(WorkgroupInvitation invitation) { 479 for (WorkgroupInvitationListener listener : invitationListeners) { 480 // CHECKSTYLE:OFF 481 listener.invitationReceived(invitation); 482 // CHECKSTYLE:ON 483 } 484 } 485 486 private void fireQueueJoinedEvent() { 487 for (QueueListener listener : queueListeners) { 488 // CHECKSTYLE:OFF 489 listener.joinedQueue(); 490 // CHECKSTYLE:ON 491 } 492 } 493 494 private void fireQueueDepartedEvent() { 495 for (QueueListener listener : queueListeners) { 496 listener.departedQueue(); 497 } 498 } 499 500 private void fireQueuePositionEvent(int currentPosition) { 501 for (QueueListener listener : queueListeners) { 502 listener.queuePositionUpdated(currentPosition); 503 } 504 } 505 506 private void fireQueueTimeEvent(int secondsRemaining) { 507 for (QueueListener listener : queueListeners) { 508 listener.queueWaitTimeUpdated(secondsRemaining); 509 } 510 } 511 512 // PacketListener Implementation. 513 514 private void handlePacket(Stanza packet) { 515 if (packet instanceof Message) { 516 Message msg = (Message) packet; 517 // Check to see if the user left the queue. 518 ExtensionElement pe = msg.getExtension("depart-queue", "http://jabber.org/protocol/workgroup"); 519 ExtensionElement queueStatus = msg.getExtension("queue-status", "http://jabber.org/protocol/workgroup"); 520 521 if (pe != null) { 522 fireQueueDepartedEvent(); 523 } 524 else if (queueStatus != null) { 525 QueueUpdate queueUpdate = (QueueUpdate) queueStatus; 526 if (queueUpdate.getPosition() != -1) { 527 fireQueuePositionEvent(queueUpdate.getPosition()); 528 } 529 if (queueUpdate.getRemaingTime() != -1) { 530 fireQueueTimeEvent(queueUpdate.getRemaingTime()); 531 } 532 } 533 534 else { 535 // Check if a room invitation was sent and if the sender is the workgroup 536 MUCUser mucUser = msg.getExtension("x", "http://jabber.org/protocol/muc#user"); 537 MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null; 538 if (invite != null && workgroupJID.equals(invite.getFrom())) { 539 String sessionID = null; 540 Map<String, List<String>> metaData = null; 541 542 pe = msg.getExtension(SessionID.ELEMENT_NAME, 543 SessionID.NAMESPACE); 544 if (pe != null) { 545 sessionID = ((SessionID) pe).getSessionID(); 546 } 547 548 pe = msg.getExtension(MetaData.ELEMENT_NAME, 549 MetaData.NAMESPACE); 550 if (pe != null) { 551 metaData = ((MetaData) pe).getMetaData(); 552 } 553 554 WorkgroupInvitation inv = new WorkgroupInvitation(connection.getUser(), msg.getFrom(), 555 workgroupJID, sessionID, msg.getBody(), 556 msg.getFrom(), metaData); 557 558 fireInvitationEvent(inv); 559 } 560 } 561 } 562 } 563 564 /** 565 * IQ stanza(/packet) to request joining the workgroup queue. 566 */ 567 private class JoinQueuePacket extends IQ { 568 569 private final Jid userID; 570 private final DataForm form; 571 572 public JoinQueuePacket(Jid workgroup, Form answerForm, Jid userID) { 573 super("join-queue", "http://jabber.org/protocol/workgroup"); 574 this.userID = userID; 575 576 setTo(workgroup); 577 setType(IQ.Type.set); 578 579 form = answerForm.getDataFormToSend(); 580 addExtension(form); 581 } 582 583 @Override 584 protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder buf) { 585 buf.rightAngleBracket(); 586 buf.append("<queue-notifications/>"); 587 // Add the user unique identification if the session is anonymous 588 if (connection.isAnonymous()) { 589 buf.append(new UserID(userID).toXML()); 590 } 591 592 // Append data form text 593 buf.append(form.toXML()); 594 595 return buf; 596 } 597 } 598 599 /** 600 * Returns a single chat setting based on it's identified key. 601 * 602 * @param key the key to find. 603 * @return the ChatSetting if found, otherwise false. 604 * @throws XMPPException if an error occurs while getting information from the server. 605 * @throws SmackException 606 * @throws InterruptedException 607 */ 608 public ChatSetting getChatSetting(String key) throws XMPPException, SmackException, InterruptedException { 609 ChatSettings chatSettings = getChatSettings(key, -1); 610 return chatSettings.getFirstEntry(); 611 } 612 613 /** 614 * Returns ChatSettings based on type. 615 * 616 * @param type the type of ChatSettings to return. 617 * @return the ChatSettings of given type, otherwise null. 618 * @throws XMPPException if an error occurs while getting information from the server. 619 * @throws SmackException 620 * @throws InterruptedException 621 */ 622 public ChatSettings getChatSettings(int type) throws XMPPException, SmackException, InterruptedException { 623 return getChatSettings(null, type); 624 } 625 626 /** 627 * Returns all ChatSettings. 628 * 629 * @return all ChatSettings of a given workgroup. 630 * @throws XMPPException if an error occurs while getting information from the server. 631 * @throws SmackException 632 * @throws InterruptedException 633 */ 634 public ChatSettings getChatSettings() throws XMPPException, SmackException, InterruptedException { 635 return getChatSettings(null, -1); 636 } 637 638 639 /** 640 * Asks the workgroup for it's Chat Settings. 641 * 642 * @return key specify a key to retrieve only that settings. Otherwise for all settings, key should be null. 643 * @throws NoResponseException 644 * @throws XMPPErrorException if an error occurs while getting information from the server. 645 * @throws NotConnectedException 646 * @throws InterruptedException 647 */ 648 private ChatSettings getChatSettings(String key, int type) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 649 ChatSettings request = new ChatSettings(); 650 if (key != null) { 651 request.setKey(key); 652 } 653 if (type != -1) { 654 request.setType(type); 655 } 656 request.setType(IQ.Type.get); 657 request.setTo(workgroupJID); 658 659 ChatSettings response = connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); 660 661 return response; 662 } 663 664 /** 665 * The workgroup service may be configured to send email. This queries the Workgroup Service 666 * to see if the email service has been configured and is available. 667 * 668 * @return true if the email service is available, otherwise return false. 669 * @throws SmackException 670 * @throws InterruptedException 671 */ 672 public boolean isEmailAvailable() throws SmackException, InterruptedException { 673 ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection); 674 675 try { 676 DomainBareJid workgroupService = workgroupJID.asDomainBareJid(); 677 DiscoverInfo infoResult = discoManager.discoverInfo(workgroupService); 678 return infoResult.containsFeature("jive:email:provider"); 679 } 680 catch (XMPPException e) { 681 return false; 682 } 683 } 684 685 /** 686 * Asks the workgroup for it's Offline Settings. 687 * 688 * @return offlineSettings the offline settings for this workgroup. 689 * @throws XMPPErrorException 690 * @throws NoResponseException 691 * @throws NotConnectedException 692 * @throws InterruptedException 693 */ 694 public OfflineSettings getOfflineSettings() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 695 OfflineSettings request = new OfflineSettings(); 696 request.setType(IQ.Type.get); 697 request.setTo(workgroupJID); 698 699 return connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); 700 } 701 702 /** 703 * Asks the workgroup for it's Sound Settings. 704 * 705 * @return soundSettings the sound settings for the specified workgroup. 706 * @throws XMPPErrorException 707 * @throws NoResponseException 708 * @throws NotConnectedException 709 * @throws InterruptedException 710 */ 711 public SoundSettings getSoundSettings() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 712 SoundSettings request = new SoundSettings(); 713 request.setType(IQ.Type.get); 714 request.setTo(workgroupJID); 715 716 return connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); 717 } 718 719 /** 720 * Asks the workgroup for it's Properties. 721 * 722 * @return the WorkgroupProperties for the specified workgroup. 723 * @throws XMPPErrorException 724 * @throws NoResponseException 725 * @throws NotConnectedException 726 * @throws InterruptedException 727 */ 728 public WorkgroupProperties getWorkgroupProperties() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 729 WorkgroupProperties request = new WorkgroupProperties(); 730 request.setType(IQ.Type.get); 731 request.setTo(workgroupJID); 732 733 return connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); 734 } 735 736 /** 737 * Asks the workgroup for it's Properties. 738 * 739 * @param jid the jid of the user who's information you would like the workgroup to retreive. 740 * @return the WorkgroupProperties for the specified workgroup. 741 * @throws XMPPErrorException 742 * @throws NoResponseException 743 * @throws NotConnectedException 744 * @throws InterruptedException 745 */ 746 public WorkgroupProperties getWorkgroupProperties(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 747 WorkgroupProperties request = new WorkgroupProperties(); 748 request.setJid(jid); 749 request.setType(IQ.Type.get); 750 request.setTo(workgroupJID); 751 752 return connection.createStanzaCollectorAndSend( 753 request).nextResultOrThrow(); 754 } 755 756 757 /** 758 * Returns the Form to use for all clients of a workgroup. It is unlikely that the server 759 * will change the form (without a restart) so it is safe to keep the returned form 760 * for future submissions. 761 * 762 * @return the Form to use for searching transcripts. 763 * @throws XMPPErrorException 764 * @throws NoResponseException 765 * @throws NotConnectedException 766 * @throws InterruptedException 767 */ 768 public Form getWorkgroupForm() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 769 WorkgroupForm workgroupForm = new WorkgroupForm(); 770 workgroupForm.setType(IQ.Type.get); 771 workgroupForm.setTo(workgroupJID); 772 773 WorkgroupForm response = connection.createStanzaCollectorAndSend( 774 workgroupForm).nextResultOrThrow(); 775 return Form.getFormFrom(response); 776 } 777}