All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jivesoftware.smackx.workgroup.agent.AgentRoster Maven / Gradle / Ivy

Go to download

Smack is an Open Source XMPP (Jabber) client library for instant messaging and presence. This library provides the client side functionality as specified in the core XMPP specifications as related to the client side of said specifications.

The newest version!
/**
 * $Revision$
 * $Date$
 *
 * Copyright 2003-2007 Jive Software.
 *
 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jivesoftware.smackx.workgroup.agent;

import org.jivesoftware.smackx.workgroup.packet.AgentStatus;
import org.jivesoftware.smackx.workgroup.packet.AgentStatusRequest;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Manges information about the agents in a workgroup and their presence.
 *
 * @author Matt Tucker
 * @see AgentSession#getAgentRoster()
 */
public class AgentRoster {

    private static final int EVENT_AGENT_ADDED = 0;
    private static final int EVENT_AGENT_REMOVED = 1;
    private static final int EVENT_PRESENCE_CHANGED = 2;

    private Connection connection;
    private String workgroupJID;
    private List entries;
    private List listeners;
    private Map> presenceMap;
    // The roster is marked as initialized when at least a single roster packet
    // has been recieved and processed.
    boolean rosterInitialized = false;

    /**
     * Constructs a new AgentRoster.
     *
     * @param connection an XMPP connection.
     */
    AgentRoster(Connection connection, String workgroupJID) {
        this.connection = connection;
        this.workgroupJID = workgroupJID;
        entries = new ArrayList();
        listeners = new ArrayList();
        presenceMap = new HashMap>();
        // Listen for any roster packets.
        PacketFilter rosterFilter = new PacketTypeFilter(AgentStatusRequest.class);
        connection.addPacketListener(new AgentStatusListener(), rosterFilter);
        // Listen for any presence packets.
        connection.addPacketListener(new PresencePacketListener(),
                new PacketTypeFilter(Presence.class));

        // Send request for roster.
        AgentStatusRequest request = new AgentStatusRequest();
        request.setTo(workgroupJID);
        connection.sendPacket(request);
    }

    /**
     * Reloads the entire roster from the server. This is an asynchronous operation,
     * which means the method will return immediately, and the roster will be
     * reloaded at a later point when the server responds to the reload request.
     */
    public void reload() {
        AgentStatusRequest request = new AgentStatusRequest();
        request.setTo(workgroupJID);
        connection.sendPacket(request);
    }

    /**
     * Adds a listener to this roster. The listener will be fired anytime one or more
     * changes to the roster are pushed from the server.
     *
     * @param listener an agent roster listener.
     */
    public void addListener(AgentRosterListener listener) {
        synchronized (listeners) {
            if (!listeners.contains(listener)) {
                listeners.add(listener);

                // Fire events for the existing entries and presences in the roster
                for (Iterator it = getAgents().iterator(); it.hasNext();) {
                    String jid = it.next();
                    // Check again in case the agent is no longer in the roster (highly unlikely
                    // but possible)
                    if (entries.contains(jid)) {
                        // Fire the agent added event
                        listener.agentAdded(jid);
                        Map userPresences = presenceMap.get(jid);
                        if (userPresences != null) {
                            Iterator presences = userPresences.values().iterator();
                            while (presences.hasNext()) {
                                // Fire the presence changed event
                                listener.presenceChanged(presences.next());
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Removes a listener from this roster. The listener will be fired anytime one or more
     * changes to the roster are pushed from the server.
     *
     * @param listener a roster listener.
     */
    public void removeListener(AgentRosterListener listener) {
        synchronized (listeners) {
            listeners.remove(listener);
        }
    }

    /**
     * Returns a count of all agents in the workgroup.
     *
     * @return the number of agents in the workgroup.
     */
    public int getAgentCount() {
        return entries.size();
    }

    /**
     * Returns all agents (String JID values) in the workgroup.
     *
     * @return all entries in the roster.
     */
    public Set getAgents() {
        Set agents = new HashSet();
        synchronized (entries) {
            for (Iterator i = entries.iterator(); i.hasNext();) {
                agents.add(i.next());
            }
        }
        return Collections.unmodifiableSet(agents);
    }

    /**
     * Returns true if the specified XMPP address is an agent in the workgroup.
     *
     * @param jid the XMPP address of the agent (eg "[email protected]"). The
     *            address can be in any valid format (e.g. "domain/resource", "user@domain"
     *            or "user@domain/resource").
     * @return true if the XMPP address is an agent in the workgroup.
     */
    public boolean contains(String jid) {
        if (jid == null) {
            return false;
        }
        synchronized (entries) {
            for (Iterator i = entries.iterator(); i.hasNext();) {
                String entry = i.next();
                if (entry.toLowerCase().equals(jid.toLowerCase())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Returns the presence info for a particular agent, or null if the agent
     * is unavailable (offline) or if no presence information is available.

* * @param user a fully qualified xmpp JID. The address could be in any valid format (e.g. * "domain/resource", "user@domain" or "user@domain/resource"). * @return the agent's current presence, or null if the agent is unavailable * or if no presence information is available.. */ public Presence getPresence(String user) { String key = getPresenceMapKey(user); Map userPresences = presenceMap.get(key); if (userPresences == null) { Presence presence = new Presence(Presence.Type.unavailable); presence.setFrom(user); return presence; } else { // Find the resource with the highest priority // Might be changed to use the resource with the highest availability instead. Iterator it = userPresences.keySet().iterator(); Presence p; Presence presence = null; while (it.hasNext()) { p = (Presence)userPresences.get(it.next()); if (presence == null){ presence = p; } else { if (p.getPriority() > presence.getPriority()) { presence = p; } } } if (presence == null) { presence = new Presence(Presence.Type.unavailable); presence.setFrom(user); return presence; } else { return presence; } } } /** * Returns the key to use in the presenceMap for a fully qualified xmpp ID. The roster * can contain any valid address format such us "domain/resource", "user@domain" or * "user@domain/resource". If the roster contains an entry associated with the fully qualified * xmpp ID then use the fully qualified xmpp ID as the key in presenceMap, otherwise use the * bare address. Note: When the key in presenceMap is a fully qualified xmpp ID, the * userPresences is useless since it will always contain one entry for the user. * * @param user the fully qualified xmpp ID, e.g. [email protected]/Work. * @return the key to use in the presenceMap for the fully qualified xmpp ID. */ private String getPresenceMapKey(String user) { String key = user; if (!contains(user)) { key = StringUtils.parseBareAddress(user).toLowerCase(); } return key; } /** * Fires event to listeners. */ private void fireEvent(int eventType, Object eventObject) { AgentRosterListener[] listeners = null; synchronized (this.listeners) { listeners = new AgentRosterListener[this.listeners.size()]; this.listeners.toArray(listeners); } for (int i = 0; i < listeners.length; i++) { switch (eventType) { case EVENT_AGENT_ADDED: listeners[i].agentAdded((String)eventObject); break; case EVENT_AGENT_REMOVED: listeners[i].agentRemoved((String)eventObject); break; case EVENT_PRESENCE_CHANGED: listeners[i].presenceChanged((Presence)eventObject); break; } } } /** * Listens for all presence packets and processes them. */ private class PresencePacketListener implements PacketListener { public void processPacket(Packet packet) { Presence presence = (Presence)packet; String from = presence.getFrom(); if (from == null) { // TODO Check if we need to ignore these presences or this is a server bug? System.out.println("Presence with no FROM: " + presence.toXML()); return; } String key = getPresenceMapKey(from); // If an "available" packet, add it to the presence map. Each presence map will hold // for a particular user a map with the presence packets saved for each resource. if (presence.getType() == Presence.Type.available) { // Ignore the presence packet unless it has an agent status extension. AgentStatus agentStatus = (AgentStatus)presence.getExtension( AgentStatus.ELEMENT_NAME, AgentStatus.NAMESPACE); if (agentStatus == null) { return; } // Ensure that this presence is coming from an Agent of the same workgroup // of this Agent else if (!workgroupJID.equals(agentStatus.getWorkgroupJID())) { return; } Map userPresences; // Get the user presence map if (presenceMap.get(key) == null) { userPresences = new HashMap(); presenceMap.put(key, userPresences); } else { userPresences = presenceMap.get(key); } // Add the new presence, using the resources as a key. synchronized (userPresences) { userPresences.put(StringUtils.parseResource(from), presence); } // Fire an event. synchronized (entries) { for (Iterator i = entries.iterator(); i.hasNext();) { String entry = (String)i.next(); if (entry.toLowerCase().equals(StringUtils.parseBareAddress(key).toLowerCase())) { fireEvent(EVENT_PRESENCE_CHANGED, packet); } } } } // If an "unavailable" packet, remove any entries in the presence map. else if (presence.getType() == Presence.Type.unavailable) { if (presenceMap.get(key) != null) { Map userPresences = presenceMap.get(key); synchronized (userPresences) { userPresences.remove(StringUtils.parseResource(from)); } if (userPresences.isEmpty()) { presenceMap.remove(key); } } // Fire an event. synchronized (entries) { for (Iterator i = entries.iterator(); i.hasNext();) { String entry = (String)i.next(); if (entry.toLowerCase().equals(StringUtils.parseBareAddress(key).toLowerCase())) { fireEvent(EVENT_PRESENCE_CHANGED, packet); } } } } } } /** * Listens for all roster packets and processes them. */ private class AgentStatusListener implements PacketListener { public void processPacket(Packet packet) { if (packet instanceof AgentStatusRequest) { AgentStatusRequest statusRequest = (AgentStatusRequest)packet; for (Iterator i = statusRequest.getAgents().iterator(); i.hasNext();) { AgentStatusRequest.Item item = (AgentStatusRequest.Item)i.next(); String agentJID = item.getJID(); if ("remove".equals(item.getType())) { // Removing the user from the roster, so remove any presence information // about them. String key = StringUtils.parseName(StringUtils.parseName(agentJID) + "@" + StringUtils.parseServer(agentJID)); presenceMap.remove(key); // Fire event for roster listeners. fireEvent(EVENT_AGENT_REMOVED, agentJID); } else { entries.add(agentJID); // Fire event for roster listeners. fireEvent(EVENT_AGENT_ADDED, agentJID); } } // Mark the roster as initialized. rosterInitialized = true; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy