📄 agentsession.java
字号:
/**
* $RCSfile$
* $Revision: 28140 $
* $Date: 2006-03-06 17:18:46 -0800 (Mon, 06 Mar 2006) $
*
* Copyright (C) 2004-2008 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.openfire.fastpath.util.TaskEngine;
import org.jivesoftware.xmpp.workgroup.interceptor.InterceptorManager;
import org.jivesoftware.xmpp.workgroup.interceptor.OfferInterceptorManager;
import org.jivesoftware.xmpp.workgroup.interceptor.PacketRejectedException;
import org.jivesoftware.xmpp.workgroup.request.UserRequest;
import org.dom4j.Element;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.LocaleUtils;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* <p>A 'live' agent session.</p>
* <p>Agent sessions are only created and maintaned for available agents
* (although they may be show-dnd).</p>
*
* @author Derek DeMoro
*/
public class AgentSession {
private static final FastDateFormat UTC_FORMAT = FastDateFormat.getInstance("yyyyMMdd'T'HH:mm:ss", TimeZone.getTimeZone("GMT+0"));
private Presence presence;
private Collection<Workgroup> workgroups = new ConcurrentLinkedQueue<Workgroup>();
private Offer offer;
/**
* Flag that indicates if the agent requested to get information of agents of all the workgroups
* where the agent has joined.
*/
private boolean requestedAgentInfo = false;
private Map<Workgroup, Queue<ChatInfo>> chatInfos = new ConcurrentHashMap<Workgroup, Queue<ChatInfo>>();
/**
* By default maxChats has a value of -1 which means that #getMaxChats will return
* the max number of chats per agent defined in the workgroup. The agent may overwrite
* the default value but the new value will not be persisted for future sessions.
*/
private int maxChats;
private Agent agent;
private JID address;
private long id;
private Date lastChatTime;
/**
* @param address the XMPPAddress to create an <code>AgentSession</code>
* @param agent the <code>Agent</code>
*/
public AgentSession(JID address, Agent agent) {
this.id = -1;
this.agent = agent;
this.address = address;
maxChats = -1;
presence = new Presence();
}
public Presence getPresence() {
return presence;
}
/**
* Updates the presence of the AgentSession with the new received presence. The max number of
* chats and number of current chats will be updated if that information was included in the presence.
* If no information was provided then default values of queues, workgroups or general settings will
* be used instead.
*
* @param packet the new presence sent by the agent.
*/
public void updatePresence(Presence packet) {
// Create a copy of the received Presence to use as the presence of the AgentSession
Presence sessionPresence = packet.createCopy();
// Remove the "agent-status" element from the new AgentSession's presence
Element child = sessionPresence.getChildElement("agent-status", "http://jabber.org/protocol/workgroup");
sessionPresence.getElement().remove(child);
// Set the new presence to the AgentSession
presence = sessionPresence;
// Set the new maximum number of chats and the number of current chats to the
// AgentSession based on the values sent within the presence (if any)
Element elem = packet.getChildElement("agent-status", "http://jabber.org/protocol/workgroup");
if (elem != null) {
Iterator metaIter = elem.elementIterator();
while (metaIter.hasNext()) {
Element agentStatusElement = (Element)metaIter.next();
if ("max-chats".equals(agentStatusElement.getName())) {
String maxChats = agentStatusElement.getText();
if (maxChats == null || maxChats.trim().length() == 0) {
setMaxChats(-1);
}
else {
setMaxChats(Integer.parseInt(maxChats));
}
}
}
}
}
public void join(Workgroup workgroup) {
boolean added = false;
boolean alreadyJoined = workgroups.contains(workgroup);
if(!alreadyJoined){
added = workgroups.add(workgroup);
}
for (RequestQueue requestQueue : workgroup.getRequestQueues()) {
if (requestQueue.isMember(getAgent())) {
if (added) {
requestQueue.getAgentSessionList().addAgentSession(this);
}
requestQueue.sendStatus(getJID());
requestQueue.sendDetailedStatus(getJID());
}
}
updateStatus(workgroup);
if (added) {
workgroup.agentJoined(this);
// Initialize the list that will hold the chats in the workgroup
chatInfos.put(workgroup, new ConcurrentLinkedQueue<ChatInfo>());
}
}
public void depart(Workgroup workgroup) {
boolean removed = workgroups.remove(workgroup);
if (removed) {
for (RequestQueue requestQueue : workgroup.getRequestQueues()) {
requestQueue.getAgentSessionList().removeAgentSession(this);
}
if (workgroups.isEmpty()) {
getAgent().closeSession(getJID());
}
updateStatus(workgroup);
workgroup.agentDeparted(this);
}
}
public int getCurrentChats(Workgroup group) {
return getChats(group).size();
}
private void updateStatus(Workgroup workgroup) {
if (getMaxChats(workgroup) > getCurrentChats(workgroup) && offer != null) {
offer.removeRejector(this);
}
sendStatusToAllAgents(workgroup);
// When the agent becomes unavailable he will stop receiving presence updates from other
// agents so the agent will need to request information from agents once again and discard
// the old presences since they are outdated
if (!presence.isAvailable()) {
requestedAgentInfo = false;
}
}
/**
* Sends a packet to this agent with all the agents that belong to this agent's workgroup. This
* packet will be sent only when the agent has requested it.<p>
* <p/>
* Once the list of agents has been sent the agent will start to receive updates when new
* agents are added or removed from the workgroup as well as when agents become available
* or unavailable.
*
* @param packet request made by agent.
* @param workgroup the workgroup whose agents will be sent to the requester.
*/
public void sendAgentsInWorkgroup(IQ packet, final Workgroup workgroup) {
IQ statusPacket = IQ.createResultIQ(packet);
Element agentStatusRequest = statusPacket.setChildElement("agent-status-request",
"http://jabber.org/protocol/workgroup");
for (Agent agentInWorkgroup : workgroup.getAgents()) {
if (agentInWorkgroup == agent) {
continue;
}
// Add the information of the agent
agentStatusRequest.add(agentInWorkgroup.getAgentInfo());
}
// Send the response for this queue
WorkgroupManager.getInstance().send(statusPacket);
// Upate the flag to indicate that the agent has requested information about the other
// agents. This implies that from now on this agent will start to receive presence
// updates from the other workgroup agents when they become unavailable or new agents
// join the workgroup
requestedAgentInfo = true;
// Send the presence of the available agents to this agent
// Note: Execute this process in another thread since we want to release this thread as
// soon as possible so other requests may be read and processed
TaskEngine.getInstance().submit(new Runnable() {
public void run() {
try {
sendStatusOfAllAgents(workgroup);
}
catch (Exception e) {
ComponentManagerFactory.getComponentManager().getLog().error("Error sending status of all agents", e);
}
}
});
}
/**
* Sends information of the agent to the agent that requested it.
*
* @param packet the original packet that made the request to obtain the agent's info.
*/
public void sendAgentInfo(IQ packet) {
IQ statusPacket = IQ.createResultIQ(packet);
Element agentInfo = statusPacket.setChildElement("agent-info",
"http://jivesoftware.com/protocol/workgroup");
agentInfo.addElement("jid").setText(getAgent().getAgentJID().toBareJID());
agentInfo.addElement("name").setText(getAgent().getNickname());
// Send the response
WorkgroupManager.getInstance().send(statusPacket);
}
/**
* Sends the presence of each available agent in the workgroup to this agent.
*
* @param workgroup the workgroup whose agents' presences will be sent to this agent.
*/
private void sendStatusOfAllAgents(Workgroup workgroup) {
for (AgentSession agentSession : workgroup.getAgentSessions()) {
if (!agentSession.getJID().equals(address)) {
Presence statusPacket = agentSession.getPresence().createCopy();
statusPacket.setFrom(agentSession.getJID());
statusPacket.setTo(address);
// Add the agent-status element
agentSession.getAgentStatus(statusPacket,workgroup);
workgroup.send(statusPacket);
}
}
}
/**
* Sends this agent's status to all other agents in the Workgroup.
*
* @param workgroup the workgroup whose agent will be notified
*/
private void sendStatusToAllAgents(Workgroup workgroup) {
for (AgentSession agentSession : workgroup.getAgentSessions()) {
// Only send presences to Agents that are available and had requested to
// receive other agents' information
if (agentSession.hasRequestedAgentInfo() && !agentSession.getJID().equals(address)) {
Presence statusPacket = presence.createCopy();
statusPacket.setFrom(address);
statusPacket.setTo(agentSession.getJID());
// Add the agent-status element
getAgentStatus(statusPacket, workgroup);
workgroup.send(statusPacket);
}
}
}
private void getAgentStatus(Presence statusPacket, Workgroup workgroup) {
Element agentStatus = statusPacket.getElement().addElement("agent-status",
"http://jabber.org/protocol/workgroup");
// Add the workgroup JID as an attribute to the agent status element
agentStatus.addAttribute("jid", workgroup.getJID().toBareJID());
// Add max-chats element to the agent status element
Element maxChats = agentStatus.addElement("max-chats");
maxChats.setText(Integer.toString(getMaxChats(workgroup)));
// Add information about the current chats to the agent status element
Element currentChats = agentStatus.addElement("current-chats",
"http://jivesoftware.com/protocol/workgroup");
for (ChatInfo chatInfo : getChats(workgroup)) {
Element chatElement = currentChats.addElement("chat");
chatElement.addAttribute("sessionID", chatInfo.getSessionID());
chatElement.addAttribute("userID", chatInfo.getUserID());
chatElement.addAttribute("startTime", UTC_FORMAT.format(chatInfo.getDate()));
// Check for question
if (chatInfo.getQuestion() != null) {
chatElement.addAttribute("question", chatInfo.getQuestion());
}
// Check for username
if (chatInfo.getUsername() != null) {
chatElement.addAttribute("username", chatInfo.getUsername());
}
// Check for email
if (chatInfo.getEmail() != null) {
chatElement.addAttribute("email", chatInfo.getEmail());
}
}
}
public String toString() {
return "AI-" + Integer.toHexString(hashCode()) +
" JID " + address.toString() +
" CC " + Integer.toString(chatInfos.size()) +
" MC " + Integer.toString(maxChats);
}
/**
* Send an offer
*
* @param offer the <code>Offer</code> to send.
* @param offerPacket the packet to send to the agent with the offer.
* @return true if the packet was sent to the agent.
*/
public boolean sendOffer(Offer offer, IQ offerPacket) {
synchronized (this) {
if (this.offer != null) {
return false;
}
this.offer = offer;
}
try {
offer.addPendingSession(this);
InterceptorManager interceptorManager = OfferInterceptorManager.getInstance();
try {
Workgroup workgroup = offer.getRequest().getWorkgroup();
interceptorManager.invokeInterceptors(workgroup.getJID().toBareJID(),
offerPacket, false, false);
// Send the Offer to the agent
WorkgroupManager.getInstance().send(offerPacket);
interceptorManager.invokeInterceptors(workgroup.getJID().toBareJID(),
offerPacket, false, true);
}
catch (PacketRejectedException e) {
ComponentManagerFactory.getComponentManager().getLog().warn("Offer was not sent " +
"due to interceptor REJECTION: " + offerPacket.toXML(), e);
}
return true;
}
catch (Exception e) {
ComponentManagerFactory.getComponentManager().getLog().error(LocaleUtils.getLocalizedString("admin.error"), e);
return false;
}
}
public void sendRevoke(Offer offer, IQ agentRevoke) {
if (this.offer == null || !this.offer.equals(offer)) {
return;
}
try {
WorkgroupManager.getInstance().send(agentRevoke);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -