fastpath在前一章有作了一些介紹,是openfire提供的一種能夠實現客服功能的插件。 java
這裏把本身查看源碼看到一些主要幾個類來講明一下這個fastpath的主要對象。 sql
這是對於的客服的實體對象,主要就是記錄一些基本的屬性,好比:agent的暱稱,jid等 編程
public class Agent { private static final Logger Log = LoggerFactory.getLogger(Agent.class); private static final String LOAD_AGENT = "SELECT name, agentJID, maxchats FROM fpAgent WHERE agentID=?"; private static final String SAVE_AGENT = "UPDATE fpAgent SET name=?, agentJID=?, maxchats=? WHERE agentID=?"; /** * The agent session created when the agent joined the service. */ private AgentSession session; /** * The ceiling on the maximumn number of chats the agent should handle. */ protected int maxChats = 0; /** * Nickname of the agent. */ private String nickname; /** * Custom properties for the agent. */ private JiveLiveProperties properties; /** * The id of the agent. */ private long id; /** * The XMPP address of the Agent. */ private JID agentJID;
這個類很好理解就是對agent這個實體類的管理類,openfire中的一些實體對象同樣整個代碼主要是用一些sql語句實現了基本的增刪改查。 session
public class AgentManager { private static final Logger Log = LoggerFactory.getLogger(AgentManager.class); private static final String LOAD_AGENTS = "SELECT agentID FROM fpAgent"; private static final String INSERT_AGENT = "INSERT INTO fpAgent (agentID, agentJID, name, maxchats, minchats) VALUES (?,?,?,?,?)"; private static final String DELETE_AGENT = "DELETE FROM fpAgent WHERE agentID=?"; private static final String DELETE_AGENT_PROPS = "DELETE FROM fpAgentProp WHERE ownerID=?";
這個對象顧名思義agent的會話實體。從類的屬性能夠看出,這個實體是對應一個agent對象,包含了這個agent在各個技能組的聊天會話的集合,加入的技能組集合,以及這個agent的最大的聊天室,出席包的狀態等都在這個類中定義。這個是在後面操做中比較經常使用的類。以及一些事件的監聽類 mvc
public class AgentSession { private static final Logger Log = LoggerFactory.getLogger(AgentSession.class); 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 WorkgroupPresence workgroupPresenceHandler; private WorkgroupIQHandler workgroupIqHandler; private MessageHandler messageHandler;
這個是技能組的實體對象,這個對象和以前的agent對象有點相同也是包含了基本的一些屬性,如:最大聊天數,這是對於技能組而言,offer超時時間等。這裏涉及到隊列的實體,一個技能組能夠包含多個隊列,根據隊列的等級來顯示路由的優先級。提供了建立隊列的方法,隊列會涉及到路由的實現。這個也是比較主要的類,在後面會常常使用。 ide
public class Workgroup { private static final Logger Log = LoggerFactory.getLogger(Workgroup.class); private String description = null; private Date creationDate; private Date modDate; private long offerTimeout = -1; private long requestTimeout = -1; private int maxChats; private int minChats; private Map<Long, RequestQueue> queues = new HashMap<Long, RequestQueue>(); /** * Custom properties for the workgroup. */ private JiveLiveProperties properties; private String workgroupName; private String displayName; private long id;
這個也是對應的技能組的管理類,這個就比較複雜,涉及的地方比較多, 測試
這個顧名思義管理髮送給技能組的出席包,好比agent加入技能組就是個對應的技能組發送出席包。 this
這個就是在前面提到的隊列,這個實體類,基本屬性主要是一些最大會話數,這裏就比較涉及多。 spa
用戶請求的鏈表集合,經過集合來添加,刪除等基本操做用戶的排隊請求,經過這個實現當前排隊人數的推送等 插件
private LinkedList<UserRequest> requests = new LinkedList<UserRequest>();agentSession的集合對象,控制在本隊列中的agent,好比agent退出等
private AgentSessionList activeAgents = new AgentSessionList();路由的實現類
/** * Dispatcher for the queue. */ private RoundRobinDispatcher dispatcher;
這個是個抽象類,就是請求的實體類。
三個實現類:
UserRequest:這個就是上面的隊列中的用戶請求的實體類,就是用戶加入排隊的時候發送的包,包括了一些路由的要求好比:agent:優先的agent,rank:排的技能組等級,timeout:隊列排隊的時間,微秒爲單位
TransferRequest:這個是後來實現轉接的時候看到,是agent端轉接給其餘agent進行請求的一個請求類,這裏的轉接是用涉及到轉接的對象,能夠轉接用戶,隊列,技能組均可以轉接。smack包也提供了對應的方法。
InvitationRequest:這個就是邀請的請求,好比fastpath在路由成功後,邀請用戶和agent加入本身建立的聊天室發送的包,就是這個類現實的。
這個也是上面一直提到的路由的實現類。整個的fastpath核心邏輯就是路由,就是這個類實現。該類是基於隊列的,從構造方法能夠看出經過定時器來掃描隊列中的用戶請求,來實現offer的分發給改隊列中的agent,以現實路由功能。
public RoundRobinDispatcher(RequestQueue queue) { this.queue = queue; agentList = new LinkedList<AgentSession>(); properties = new JiveLiveProperties("fpDispatcherProp", queue.getID()); try { info = infoProvider.getDispatcherInfo(queue.getWorkgroup(), queue.getID()); } catch (NotFoundException e) { Log.error("Queue ID " + queue.getID(), e); } // Recreate the agentSelector to use for selecting the best agent to receive the offer loadAgentSelector(); // Fill the list of AgentSessions that are active in the queue. Once the list has been // filled this dispatcher will be notified when new AgentSessions join the queue or leave // the queue fillAgentsList(); Log.error("after fillAgentsList"); TaskEngine.getInstance().scheduleAtFixedRate(new TimerTask() { @Override public void run() { checkForNewRequests(); } }, 2000, 2000); }
public void dispatch(Offer offer) { // The time when the request should timeout // long timeoutTime = System.currentTimeMillis() + info.getRequestTimeout(); //這裏修改,要是有輸入超時時間,不用默認的 final Request request = offer.getRequest(); long timeoutTime = System.currentTimeMillis() + ((request.getMetaData().containsKey("timeout"))?Long.parseLong(request.getMetaData().get("timeout").get(0)):info.getRequestTimeout()); boolean canBeInQueue = request instanceof UserRequest; Map<String,List<String>> map = request.getMetaData(); String initialAgent = map.get("agent") == null || map.get("agent").isEmpty() ? null : map.get("agent").get(0); String ignoreAgent = map.get("ignore") == null || map.get("ignore").isEmpty() ? null : map.get("ignore").get(0); // Log debug trace Log.debug("RR - Dispatching request: " + request + " in queue: " + queue.getAddress()); // Send the offer to the best agent. While the offer has not been accepted send it to the // next best agent. If there aren't any agent available then skip this section and proceed // to overflow the current request if (!agentList.isEmpty()) { for (long timeRemaining = timeoutTime - System.currentTimeMillis(); !offer.isAccepted() && timeRemaining > 0 && !offer.isCancelled(); timeRemaining = timeoutTime - System.currentTimeMillis()) { try { AgentSession session = getBestNextAgent(initialAgent, ignoreAgent, offer); Log.error("AgentSession:"); if (session == null && agentList.isEmpty()) { // Stop looking for an agent since there are no more agent available Log.error("agentList.isEmpty():"); break; } else if (session == null || offer.isRejector(session)) { Log.error("offer.isRejector(session):"); initialAgent = null; Thread.sleep(1000); } else { // Recheck for changed maxchat setting Workgroup workgroup = request.getWorkgroup(); if (session.getCurrentChats(workgroup) < session.getMaxChats(workgroup)) { // Set the timeout of the offer based on the remaining time of the // initial request and the default offer timeout timeRemaining = timeoutTime - System.currentTimeMillis(); //設置offer超時時長,是怕offer超時時長超過request時長 offer.setTimeout(timeRemaining < info.getOfferTimeout() ? timeRemaining : info.getOfferTimeout()); // Make the offer and wait for a resolution to the offer if (!request.sendOffer(session, queue)) { // Log debug trace Log.debug("RR - Offer for request: " + offer.getRequest() + " FAILED TO BE SENT to agent: " + session.getJID()); continue; } // Log debug trace Log.debug("RR - Offer for request: " + offer.getRequest() + " SENT to agent: " + session.getJID()); offer.waitForResolution(); // If the offer was accepted, we send out the invites // and reset the offer if (offer.isAccepted()) { // Get the first agent that accepted the offer AgentSession selectedAgent = offer.getAcceptedSessions().get(0); // Log debug trace Log.debug("RR - Agent: " + selectedAgent.getJID() + " ACCEPTED request: " + request); // Create the room and send the invitations offer.invite(selectedAgent); //發送監控消息 bywengwh sendUmccWorkMsg(request,selectedAgent); // Notify the agents that accepted the offer that the offer process // has finished for (AgentSession agent : offer.getAcceptedSessions()) { agent.removeOffer(offer); } if (canBeInQueue) { // Remove the user from the queue since his request has // been accepted queue.removeRequest((UserRequest) request); } } } else { // Log debug trace Log.debug("RR - Selected agent: " + session.getJID() + " has reached max number of chats"); } } } catch (Exception e) { Log.error(e.getMessage(), e); } } } if (!offer.isAccepted() && !offer.isCancelled()) { // Calculate the maximum time limit for an unattended request before cancelling it //modify by Condy 2014.03.09 //TODO 未測試 long requestTimeOut=(request.getMetaData().containsKey("timeout"))?Long.parseLong(request.getMetaData().get("timeout").get(0)):info.getRequestTimeout(); long limit = request.getCreationTime().getTime() + (requestTimeOut * (getOverflowTimes() + 1)); if (limit - System.currentTimeMillis() <= 0 || !canBeInQueue) { // Log debug trace Log.debug("RR - Cancelling request that maxed out overflow limit or cannot be queued: " + request); // Cancel the request if it has overflowed 'n' times request.cancel(Request.CancelType.AGENT_NOT_FOUND); } else { // Overflow if request timed out and was not dispatched and max number of overflows // has not been reached yet overflow(offer); // If there is no other queue to overflow then cancel the request if (!offer.isAccepted() && !offer.isCancelled()) { // Log debug trace Log.debug("RR - Cancelling request that didn't overflow: " + request); request.cancel(Request.CancelType.AGENT_NOT_FOUND); } } } }
這是幾個主要的類,對於整個fastpath插件類是不少的,功能不少,還等着你們多看源碼去挖掘。其實在看源碼的時候,能夠觀察他們的包的規劃,類的命名,fastpath主要是分紅:Provider,Handle,dispatcher,event等這幾個結尾類。從查看源碼明白他們的思路,可能不必定能作到每一個類都讀一遍,讀清楚,可是對於他們的編寫習慣有時候也能夠借鑑,對本身之後編寫也是個好處。雖然如今mvc是風靡java編程。這裏就把fastpath作個總結。後面看看會接觸到什麼新的東西或者本身學一些java的一些知識的時候在貼出來。