⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 requestqueue.java

📁 openfire 服务器源码下载
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/**
 * $Revision: 32969 $
 * $Date: 2006-08-07 10:40:31 -0700 (Mon, 07 Aug 2006) $
 *
 * Copyright (C) 2004-2006 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
 */

package org.jivesoftware.xmpp.workgroup;

import org.jivesoftware.xmpp.workgroup.dispatcher.Dispatcher;
import org.jivesoftware.xmpp.workgroup.dispatcher.RoundRobinDispatcher;
import org.jivesoftware.xmpp.workgroup.request.Request;
import org.jivesoftware.xmpp.workgroup.request.UserRequest;
import org.jivesoftware.xmpp.workgroup.spi.JiveLiveProperties;
import org.jivesoftware.xmpp.workgroup.utils.ModelUtil;
import org.dom4j.Element;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupManager;
import org.jivesoftware.openfire.group.GroupNotFoundException;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.NotFoundException;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Maintains a queue of requests waiting to be routed to agents. The workgroup
 * adds and removes requests according to the protocol and the routing engine
 * will process requests in the queue.
 *
 * @author Derek DeMoro
 */
public class RequestQueue {

    private static final String LOAD_QUEUE =
            "SELECT name, description, priority, maxchats, minchats, overflow, backupQueue FROM " +
            "fpQueue WHERE queueID=?";
    private static final String UPDATE_QUEUE =
            "UPDATE fpQueue SET name=?, description=?, priority=?, maxchats=?, minchats=?, " +
            "overflow=?, backupQueue=? WHERE queueID=?";
    private static final String DELETE_QUEUE =
            "DELETE FROM fpQueueAgent WHERE objectType=? AND objectID=? AND queueID=?";
    private static final String LOAD_AGENTS =
            "SELECT objectID, administrator FROM fpQueueAgent WHERE queueID=? AND objectType=?";
    private static final String ADD_QUEUE_AGENT =
            "INSERT INTO fpQueueAgent (objectType, objectID, queueID, administrator) " +
            "VALUES (?,?,?,0)";
    private static final String LOAD_QUEUE_GROUPS =
            "SELECT groupName FROM fpQueueGroup WHERE queueID=?";
    private static final String ADD_QUEUE_GROUP =
            "INSERT INTO fpQueueGroup (queueID, groupName) VALUES (?,?)";
    private static final String DELETE_QUEUE_GROUP =
            "DELETE FROM fpQueueGroup WHERE queueID=? AND groupName=?";

    /**
     * A map of all requests in the workgroup keyed by the request's JID.
     * Lets the server route request packets to the correct request.
     */
    private LinkedList<UserRequest> requests = new LinkedList<UserRequest>();

    /**
     * A listof active agent sessions that belong to this queue.
     */
    private AgentSessionList activeAgents = new AgentSessionList();

    /**
     * The current average time a request spends in this queue.
     */
    private int averageTime;

    /**
     * The workgroup this queue belongs to.
     */
    private Workgroup workgroup;

    /**
     * The default floor for maximum number of chats that an agent
     * should have in this group.
     */
    private int minChats;
    /**
     * The default ceiling for maximum number of chats that an agent
     * should have in this group.
     */
    private int maxChats;
    /**
     * The name of the queue (and the queue's resource identifier).
     */
    private String name;
    /**
     * The description of the queue for the admin UI.
     */
    private String description;
    /**
     * The routing priority of this request queue (not currently used).
     */
    private int priority;

    /**
     * The agent groups that belong to this request queue.
     */
    private Set<String> groups = new CopyOnWriteArraySet<String>();

    /**
     * The agents that belong directly to this request queue.
     */
    private Set<Agent> agents = new CopyOnWriteArraySet<Agent>();

    /**
     * The workgoup entity properties for the queue.
     */
    private JiveLiveProperties properties;

    /**
     * Dispatcher for the queue.
     */
    private RoundRobinDispatcher dispatcher;

    /**
     * The overflow type of this queue.
     */
    private OverflowType overflowType;

    /**
     * The backup queue if overflow is OVERFLOW_BACKUP.
     */
    private long backupQueueID = 0;

    /**
     * Indicates if the queue's presence should be unavailable.
     */
    private boolean presenceAvailable = true;

    /**
     * The total number of accepted requests *
     */
    private int totalChatCount;

    /**
     * The total number of requests *
     */
    private int totalRequestCount;

    /**
     * The total number of dropped requests *
     */
    private int totalDroppedRequests;

    /**
     * The creation Date *
     */
    private Date creationDate;

    /**
     * The queue id
     */
    private long id;

    /**
     * The RequestQueue XMPPAdderess
     */
    private JID address;


    private AgentManager agentManager;

    /**
     * Creates a request queue for the given workgroup given a
     * certain request queue ID.
     *
     * @param workgroup the workgroup this queue belongs to.
     * @param id  the queueID of the queue.
     */
    public RequestQueue(Workgroup workgroup, long id) {
        this.id = id;
        this.workgroup = workgroup;

        // Load up the Queue
        loadQueue();

        // Load all Groups
        loadGroups();

        // Load all Agents
        loadAgents();

        dispatcher = new RoundRobinDispatcher(this);
        creationDate = new Date();
        agentManager = workgroup.getAgentManager();
    }

    public Dispatcher getDispatcher() {
        return dispatcher;
    }

    public Workgroup getWorkgroup() {
        return workgroup;
    }

    // ############################################################################
    // The request queue
    // ############################################################################

    public int getRequestCount() {
        return requests.size();
    }

    public Collection<UserRequest> getRequests() {
        return new ArrayList<UserRequest>(requests);
    }

    public UserRequest getRequest(JID requestAddress) {
        UserRequest returnRequest = null;

        for (UserRequest request : getRequests()) {
            if (requestAddress.equals(request.getUserJID())) {
                returnRequest = request;
                break;
            }
        }

        return returnRequest;
    }

    public void clearQueue() {
        for (Request request : getRequests()) {
            request.cancel(Request.CancelType.AGENT_NOT_FOUND);
        }
        requests.clear();
    }

    public void removeRequest(UserRequest request) {
        if (request == null) {
            throw new IllegalArgumentException();
        }
        totalRequestCount++;
        if (request.getOffer() == null || !request.getOffer().isCancelled()) {
            int waitTime = (int)(System.currentTimeMillis()
                    - request.getCreationTime().getTime()) / 1000;
            if (averageTime == 0) {
                averageTime = waitTime;
            }
            averageTime = (averageTime + waitTime) / 2;
            totalChatCount++;
        }
        else {
            final int timeout = (int)request.getOffer().getTimeout() / 1000;
            int waitTime = (int)(System.currentTimeMillis()
                    - request.getCreationTime().getTime()) / 1000;

            if (waitTime > timeout) {
                // This was never left and timed-out
                totalDroppedRequests++;
            }
        }

        int index = requests.indexOf(request);
        requests.remove(request);
        if (requests.size() > 0 && index < requests.size()) {
            sendRequestStatus(getRequests());
        }
        activeAgents.broadcastQueueStatus(this);
        request.setRequestQueue(null);
    }

    public void addRequest(UserRequest request) {
        if (request == null) {
            throw new IllegalArgumentException();
        }

        request.setRequestQueue(this);
        requests.add(request);
        activeAgents.broadcastQueueStatus(this);
        request.updateQueueStatus(false);
    }


    public UserRequest getFirst() {
        return requests.getFirst();
    }

    public int getPosition(UserRequest request) {
        return requests.indexOf(request);
    }

    public void sendStatus(JID recipient) {
        try {
            Presence queueStatus = getStatusPresence();
            queueStatus.setTo(recipient);
            workgroup.send(queueStatus);
        }
        catch (Exception e) {
            ComponentManagerFactory.getComponentManager().getLog().error(e);
        }
    }

    public void sendDetailedStatus(JID recipient) {
        try {
            // queue details
            Presence queueStatus = getDetailedStatusPresence();
            queueStatus.setTo(recipient);
            workgroup.send(queueStatus);
        }
        catch (Exception e) {
            ComponentManagerFactory.getComponentManager().getLog().error(e);
        }
    }

    public Presence getStatusPresence() {
        Presence queueStatus = new Presence();
        queueStatus.setFrom(address);

        // Add Notify Queue
        Element status = queueStatus.addChildElement("notify-queue", "http://jabber.org/protocol/workgroup");

        Element countElement = status.addElement("count");
        countElement.setText(Integer.toString(getRequestCount()));
        if (getRequestCount() > 0) {
            Element oldestElement = status.addElement("oldest");
            oldestElement.setText(UTC_FORMAT.format(getFirst().getCreationTime()));
        }

        Element timeElement = status.addElement("time");
        timeElement.setText(Integer.toString(getAverageTime()));
        Element statusElement = status.addElement("status");

        if (workgroup.getStatus() == Workgroup.Status.OPEN && presenceAvailable) {
            statusElement.setText("open");
        }
        else {
            queueStatus.setType(Presence.Type.unavailable);
            // TODO: actually active should be a full-blown workgroup state since queues
            // may be empty but still active
            if (getRequestCount() > 0) {
                statusElement.setText("active");
            }
            else {
                if (workgroup.getStatus() == Workgroup.Status.READY) {
                    statusElement.setText("ready");
                }
                else {
                    statusElement.setText("closed");
                }
            }
        }
        return queueStatus;
    }

    public Presence getDetailedStatusPresence() {
        Presence queueStatus = new Presence();
        queueStatus.setFrom(address);
        if (workgroup.getStatus() == Workgroup.Status.OPEN && presenceAvailable) {
            queueStatus.setType(null);
        }
        else {
            queueStatus.setType(Presence.Type.unavailable);
        }

        Element details = queueStatus.addChildElement("notify-queue-details", "http://jabber.org/protocol/workgroup");
        int i = 0;
        for (UserRequest request : getRequests()) {
            Element user = details.addElement("user", "http://jabber.org/protocol/workgroup");
            try {
                user.addAttribute("jid", request.getUserJID().toString());

                // Add Sub-Elements
                Element position = user.addElement("position");
                position.setText(Integer.toString(i));

                Element time = user.addElement("time");
                time.setText(Integer.toString(request.getTimeStatus()));

                Element joinTime = user.addElement("join-time");
                joinTime.setText(UTC_FORMAT.format(request.getCreationTime()));
                i++;
            }
            catch (Exception e) {
                // Since we are not locking the list of requests while doing this operation (for
                // performance reasons) it is possible that the request got accepted or cancelled
                // thus generating a NPE

                // Remove the request that generated the exception
                details.remove(user);
                // Log an error if the request still belongs to this queue
                if (this.equals(request.getRequestQueue())) {
                    ComponentManagerFactory.getComponentManager().getLog().error(e);
                }
            }
        }
        return queueStatus;
    }

    /**
     * Returns true if this queue is opened and may be eligible for receiving new requests. The
     * queue will be opened if there are agents connected to it.
     *
     * @return true if this queue is opened and may be eligible for receiving new requests.
     */
    public boolean isOpened() {
        return !activeAgents.isEmpty();
    }

    // #################################################################
    // Standard formatting according to locale and Jabber specs
    // #################################################################
    private static final FastDateFormat UTC_FORMAT = FastDateFormat.getInstance("yyyyMMdd'T'HH:mm:ss", TimeZone.getTimeZone("UTC"));

    static {
        //UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
    }

    // ###########################################################################
    // Misc queue runtime properties
    // ###########################################################################
    public AgentSessionList getAgentSessionList() {
        return activeAgents;
    }

    public int getAverageTime() {
        return averageTime;
    }

    private void sendRequestStatus(Collection<UserRequest> requests) {
        for (UserRequest request : requests) {
            request.updateQueueStatus(false);
        }
    }

    // ###########################################################################
    // Agent Groups
    // ###########################################################################
    public int getGroupCount() {
        return groups.size();
    }

    public Collection<Group> getGroups() {
        return Collections.unmodifiableCollection(getGroupObjects());
    }

    private Collection<Group> getGroupObjects() {
        final GroupManager groupManager = GroupManager.getInstance();
        Set<Group> objects = new HashSet<Group>(groups.size());
        for (String group : groups) {
            try {
                objects.add(groupManager.getGroup(group));
            } catch (GroupNotFoundException e) {
                ComponentManagerFactory.getComponentManager().getLog().error("Error retrieving group: " + group, e);
            }
        }
        return objects;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -