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 }