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