RosterExchangeManager.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.xroster;

  18. import java.lang.ref.WeakReference;
  19. import java.util.Collections;
  20. import java.util.HashSet;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import java.util.WeakHashMap;

  25. import org.jivesoftware.smack.SmackException.NotConnectedException;
  26. import org.jivesoftware.smack.StanzaListener;
  27. import org.jivesoftware.smack.XMPPConnection;
  28. import org.jivesoftware.smack.filter.StanzaExtensionFilter;
  29. import org.jivesoftware.smack.filter.StanzaFilter;
  30. import org.jivesoftware.smack.packet.Message;
  31. import org.jivesoftware.smack.packet.MessageBuilder;
  32. import org.jivesoftware.smack.packet.Stanza;
  33. import org.jivesoftware.smack.roster.Roster;
  34. import org.jivesoftware.smack.roster.RosterEntry;
  35. import org.jivesoftware.smack.roster.RosterGroup;

  36. import org.jivesoftware.smackx.xroster.packet.RosterExchange;

  37. import org.jxmpp.jid.Jid;

  38. /**
  39.  *
  40.  * Manages Roster exchanges. A RosterExchangeManager provides high level access to send
  41.  * rosters, roster groups and roster entries to XMPP clients. It also provides an easy way
  42.  * to hook up custom logic when entries are received from another XMPP client through
  43.  * RosterExchangeListeners.
  44.  *
  45.  * @author Gaston Dombiak
  46.  */
  47. public class RosterExchangeManager {

  48.     public static final String NAMESPACE = "jabber:x:roster";
  49.     public static final String ELEMENT = "x";

  50.     private static final Map<XMPPConnection, RosterExchangeManager> INSTANCES = new WeakHashMap<>();

  51.     private static final StanzaFilter PACKET_FILTER = new StanzaExtensionFilter(ELEMENT, NAMESPACE);

  52.     private final Set<RosterExchangeListener> rosterExchangeListeners = Collections.synchronizedSet(new HashSet<RosterExchangeListener>());

  53.     private final WeakReference<XMPPConnection> weakRefConnection;
  54.     private final StanzaListener packetListener;

  55.     public static synchronized RosterExchangeManager getInstanceFor(XMPPConnection connection) {
  56.         RosterExchangeManager rosterExchangeManager = INSTANCES.get(connection);
  57.         if (rosterExchangeManager == null) {
  58.             rosterExchangeManager = new RosterExchangeManager(connection);
  59.             INSTANCES.put(connection, rosterExchangeManager);
  60.         }
  61.         return rosterExchangeManager;
  62.     }

  63.     /**
  64.      * Creates a new roster exchange manager.
  65.      *
  66.      * @param connection an XMPPConnection which is used to send and receive messages.
  67.      */
  68.     public RosterExchangeManager(XMPPConnection connection) {
  69.         weakRefConnection = new WeakReference<>(connection);
  70.         // Listens for all roster exchange packets and fire the roster exchange listeners.
  71.         packetListener = new StanzaListener() {
  72.             @Override
  73.             public void processStanza(Stanza packet) {
  74.                 Message message = (Message) packet;
  75.                 RosterExchange rosterExchange = (RosterExchange) message.getExtensionElement(ELEMENT, NAMESPACE);
  76.                 // Fire event for roster exchange listeners
  77.                 fireRosterExchangeListeners(message.getFrom(), rosterExchange.getRosterEntries());
  78.             }
  79.         };
  80.         connection.addAsyncStanzaListener(packetListener, PACKET_FILTER);
  81.     }

  82.     /**
  83.      * Adds a listener to roster exchanges. The listener will be fired anytime roster entries
  84.      * are received from remote XMPP clients.
  85.      *
  86.      * @param rosterExchangeListener a roster exchange listener.
  87.      */
  88.     public void addRosterListener(RosterExchangeListener rosterExchangeListener) {
  89.         rosterExchangeListeners.add(rosterExchangeListener);
  90.     }

  91.     /**
  92.      * Removes a listener from roster exchanges. The listener will be fired anytime roster
  93.      * entries are received from remote XMPP clients.
  94.      *
  95.      * @param rosterExchangeListener a roster exchange listener.
  96.      */
  97.     public void removeRosterListener(RosterExchangeListener rosterExchangeListener) {
  98.         rosterExchangeListeners.remove(rosterExchangeListener);
  99.     }

  100.     /**
  101.      * Sends a roster to userID. All the entries of the roster will be sent to the
  102.      * target user.
  103.      *
  104.      * @param roster the roster to send
  105.      * @param targetUserID the user that will receive the roster entries
  106.      * @throws NotConnectedException if the XMPP connection is not connected.
  107.      * @throws InterruptedException if the calling thread was interrupted.
  108.      */
  109.     public void send(Roster roster, Jid targetUserID) throws NotConnectedException, InterruptedException {
  110.         XMPPConnection connection = weakRefConnection.get();

  111.         // Create a new message to send the roster
  112.         MessageBuilder messageBuilder = connection.getStanzaFactory().buildMessageStanza().to(targetUserID);
  113.         // Create a RosterExchange Package and add it to the message
  114.         RosterExchange rosterExchange = new RosterExchange(roster);
  115.         messageBuilder.addExtension(rosterExchange);

  116.         // Send the message that contains the roster
  117.         connection.sendStanza(messageBuilder.build());
  118.     }

  119.     /**
  120.      * Sends a roster entry to userID.
  121.      *
  122.      * @param rosterEntry the roster entry to send
  123.      * @param targetUserID the user that will receive the roster entries
  124.      * @throws NotConnectedException if the XMPP connection is not connected.
  125.      * @throws InterruptedException if the calling thread was interrupted.
  126.      */
  127.     public void send(RosterEntry rosterEntry, Jid targetUserID) throws NotConnectedException, InterruptedException {
  128.         XMPPConnection connection = weakRefConnection.get();

  129.         // Create a new message to send the roster
  130.         MessageBuilder messageBuilder = connection.getStanzaFactory().buildMessageStanza().to(targetUserID);
  131.         // Create a RosterExchange Package and add it to the message
  132.         RosterExchange rosterExchange = new RosterExchange();
  133.         rosterExchange.addRosterEntry(rosterEntry);
  134.         messageBuilder.addExtension(rosterExchange);

  135.         // Send the message that contains the roster
  136.         connection.sendStanza(messageBuilder.build());
  137.     }

  138.     /**
  139.      * Sends a roster group to userID. All the entries of the group will be sent to the
  140.      * target user.
  141.      *
  142.      * @param rosterGroup the roster group to send
  143.      * @param targetUserID the user that will receive the roster entries
  144.      * @throws NotConnectedException if the XMPP connection is not connected.
  145.      * @throws InterruptedException if the calling thread was interrupted.
  146.      */
  147.     public void send(RosterGroup rosterGroup, Jid targetUserID) throws NotConnectedException, InterruptedException {
  148.         XMPPConnection connection = weakRefConnection.get();

  149.         // Create a new message to send the roster
  150.         MessageBuilder msg = connection.getStanzaFactory().buildMessageStanza().to(targetUserID);
  151.         // Create a RosterExchange Package and add it to the message
  152.         RosterExchange rosterExchange = new RosterExchange();
  153.         for (RosterEntry entry : rosterGroup.getEntries()) {
  154.             rosterExchange.addRosterEntry(entry);
  155.         }
  156.         msg.addExtension(rosterExchange);

  157.         // Send the message that contains the roster
  158.         connection.sendStanza(msg.build());
  159.     }

  160.     /**
  161.      * Fires roster exchange listeners.
  162.      */
  163.     private void fireRosterExchangeListeners(Jid from, Iterator<RemoteRosterEntry> remoteRosterEntries) {
  164.         RosterExchangeListener[] listeners;
  165.         synchronized (rosterExchangeListeners) {
  166.             listeners = new RosterExchangeListener[rosterExchangeListeners.size()];
  167.             rosterExchangeListeners.toArray(listeners);
  168.         }
  169.         for (RosterExchangeListener listener : listeners) {
  170.             listener.entriesReceived(from, remoteRosterEntries);
  171.         }
  172.     }
  173. }