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

📄 chatbot.java

📁 openfire 服务器源码下载
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/**
 * $RCSfile$
 * $Revision: $
 * $Date: $
 *
 * 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.chatbot;

import org.jivesoftware.openfire.fastpath.dataforms.FormElement;
import org.jivesoftware.openfire.fastpath.dataforms.FormManager;
import org.jivesoftware.openfire.fastpath.dataforms.WorkgroupForm;
import org.jivesoftware.openfire.fastpath.history.ChatTranscriptManager;
import org.jivesoftware.openfire.fastpath.settings.chat.ChatSettings;
import org.jivesoftware.openfire.fastpath.settings.chat.ChatSettingsManager;
import org.jivesoftware.openfire.fastpath.settings.chat.KeyEnum;
import org.jivesoftware.xmpp.workgroup.UnauthorizedException;
import org.jivesoftware.xmpp.workgroup.UserCommunicationMethod;
import org.jivesoftware.xmpp.workgroup.Workgroup;
import org.jivesoftware.xmpp.workgroup.interceptor.ChatbotInterceptorManager;
import org.jivesoftware.xmpp.workgroup.interceptor.InterceptorManager;
import org.jivesoftware.xmpp.workgroup.interceptor.PacketRejectedException;
import org.jivesoftware.xmpp.workgroup.interceptor.QueueInterceptorManager;
import org.jivesoftware.xmpp.workgroup.request.Request;
import org.jivesoftware.xmpp.workgroup.request.UserRequest;
import org.jivesoftware.util.NotFoundException;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A Chatbot holds a sequence of steps where each step represents an interaction with a
 * user. The user may navigate sequentially between the defined steps in the Chatbot.<p>
 *
 * ChatBots are stateless so the information of the chat for each user is kept in a
 * {@link ChatbotSession}. Each {@link org.jivesoftware.xmpp.workgroup.Workgroup} will have
 * a different Chatbot.<p>
 *
 * Currently the bot steps are hardcoded but a future version may let them be dynamic. The
 * current step is kept in the ChatbotSession as an integer number. When filling out a data
 * form a substep is used to register the current question that the user is completing.
 * These are the current supported steps:
 * <ol>
 *  <li><b>step = -1</b> - The chat session was just created but no message was sent.</li>
 *  <li><b>step = 0</b> - The welcome message was sent to the user. Since the user will receive the
 *  join question after the welcome message then this position is changed immediatelly.</li>
 *  <li><b>step = 1</b> - The join question was sent to the user and an answer is expected.</li>
 *  <li><b>step = 2</b> - The user decided to join the workgroup so the dataform is presented to
 *  the user. Each field in the dataform will generate a new message for the user. After the
 *  question was answered then the next message is sent. The same step value will be used for all
 *  the dataform fields. For each question a substep is used to represent the current question that
 *  the user is completing. The user may go back or repeat the question by sending commands.</li>
 *  <li><b>step = 3</b> - The user completed the form and joined a queue. At this point only
 *  commands are accepted from the user.</li>
 *  <li><b>step = 4</b> - The user left the queue since a room invitation was sent to him to start
 *  a chat session with an agent. At this point the user may ask to receive the invitation
 *  again.</li>
 *  <li><b>step = 5</b> - The user accepted the invitation and is now having a chat with an agent.
 *   At this point only commands are accepted from the user.</li>
 *  <li><b>step = 6</b> - The user has finished the chat with the agent and is asked if he wants to
 *  receive the chat transcript by email.</li>
 *  <li><b>step = 7</b> - The user wants to get the transcript by email but hasn't specified an
 *  email address so ask him to enter an email address and then send the chat transcript by
 *  email.</li>
 * </ol>
 *
 * The Chatbot allows the user to execute commands. Commands may help the user go back to
 * previous questions so he can change an answer or repeat the last question in case the user
 * closed his window accidentally.
 * These are the supported commands:
 * <ol>
 *  <li><b>back</b> - User is requesting to go back one step in the dialog and repeat the
 *      previous message</li>
 *  <li><b>repeat</b> - User is requesting to repeat the last message</li>
 *  <li><b>help</b> - User is requesting the list of available commands</li>
 *  <li><b>bye</b> - User is closing the chat session no matter the if he already joined a
 *      waiting queue or not</li>
 *  <li><b>position</b> - User wants to know his position in the waiting queue</li>
 * </ol>
 *
 * <b>Future ideas</b>
 * <ul>
 * <li>Configure the chat bot with JIDs of agents or admin that are allowed to:<ol>
 *      <li>obtain workgroup and queue statistics</li>
 *      <li>obtain current workgroup configureation</li>
 *      <li>change the chatbot configuration</li>
 *      <li>change the workgroup configuration, etc. etc. etc.</li></ol></li>
 * <li>After the user ends the chat session with the agent offer the user to fill out
 * a QoS survey.</li>
 * </ul>
 *
 * @author Gaston Dombiak
 */
public class Chatbot implements UserCommunicationMethod {

    /**
     * Holds the workgroup where the chatbot is working. This is a one-to-one relation so this
     * chatbot is the only chatbot that will be answering Messages sent to the workgroup.
     */
    private Workgroup workgroup;

    /**
     * The chat settings stores all the messages that the chatbot will use. The messages can
     * be modified from the Admin Console.
     */
    private ChatSettings settings;

    /**
     * Holds the chat sessions of all the users that are trying to join this workgroup.
     */
    private Map<String, ChatbotSession> sessions = new ConcurrentHashMap<String, ChatbotSession>();

    // TODO use resource bundles for these joining answers
    /**
     * Text that assumes that a user sent a positive answer.
     */
    private String yes = "yes";

    /**
     * Text that assumes that a user sent a negative answer.
     */
    private String no = "no";

    /**
     * Creates a new chatbot responsible for answering Messages sent to the specified workgroup.
     *
     * @param workgroup Workgroup where the new chatbot will be working.
     */
    public Chatbot(Workgroup workgroup) {
        this.workgroup = workgroup;
        this.settings = ChatSettingsManager.getInstance().getChatSettings(workgroup);
    }

    /**
     * Returns the session of the specified user in a given workgroup. If no session exists then
     * a new one will be created for the user if requested. If the session of the user remains
     * inactive for some time then it may be discarded.
     *
     * @param user the user to return his session in a given workgroup.
     * @param create true if a new session should be created if it doesn't already exist.
     * @return the session of the specified user in a given workgroup.
     */
    public ChatbotSession getSession(JID user, boolean create) {
        String fullJID = user.toString();
        ChatbotSession session = sessions.get(fullJID);
        if (session == null && create) {
            synchronized (fullJID.intern()) {
                session = sessions.get(fullJID);
                if (session == null) {
                    session = new ChatbotSession(user, this);
                    sessions.put(fullJID, session);
                }
            }
        }
        return session;
    }

    /**
     * Process a message sent by the owner of the specified session.
     *
     * @param session the session whose owner (i.e. user) sent the message.
     * @param message message sent by the owner of the session to the workgroup.
     */
    public void onMessage(ChatbotSession session, Message message) {
        InterceptorManager interceptorManager = ChatbotInterceptorManager.getInstance();
        try {
            interceptorManager.invokeInterceptors(workgroup.getJID().toBareJID(), message, true,
                    false);

            // Update the Message thread that the user is using in the session
            session.setMessageThread(message.getThread());
            // Check if the workgroup is opened
            synchronized(session) {
                if (workgroup.getStatus() != Workgroup.Status.OPEN) {
                    // Send message saying that the workgroup is closed/not available
                    sendReply(message, getWorkgroupClosedMessage());
                }
                else if (handleCommand(message, session)) {
                    // The sent message executed a command so do nothing
                }
                else if (session.getCurrentStep() < 0) {
                    // Send the welcome message
                    sendWelcomeMessage(message);
                    // Send the join question
                    sendJoinQuestion(message, session);
                }
                else if (session.getCurrentStep() == 1) {
                    // User is answering join question
                    if (yes.equalsIgnoreCase(message.getBody().trim())) {
                        // User accepted to join the workgroup so send the first question of
                        // the form
                        userAcceptedJoining(message, session);
                    }
                    else if (no.equalsIgnoreCase(message.getBody().trim())) {
                        // User rejected to join the workgroup so send a goodbye message and close
                        // the chat session
                        closeSession(message);
                    }
                    else {
                        // The user sent an unknown answer so repeat the join question
                        sendJoinQuestion(message, session);
                    }
                }
                else if (session.getCurrentStep() == 2) {
                    // User is filling out the form
                    if (userAnsweredField(message, session)) {
                        // User answered correctly the question so send the next question or if the
                        // form has been filled out then join the queue
                        if (session.getCurrentSubstep() < getForm().getFormElements().size()-1) {
                            sendNextQuestion(message, session);
                        }
                        else {
                            userJoinQueue(message, session);
                        }
                    }
                    else {
                        // The user sent an unknown answer so repeat the last question
                        repeatQuestion(message, session);
                    }
                }
                else if (session.getCurrentStep() == 4) {
                    // User is answering if he wants to get another room invitation
                    if (yes.equalsIgnoreCase(message.getBody().trim())) {
                        // User accepted to receive another room invitation so send another
                        // room invitation
                        sendRoomInvitation(message, session);
                    }
                    else if (no.equalsIgnoreCase(message.getBody().trim())) {
                        // User declined to receive another room invitation so do nothing
                    }
                    else {
                        // The user sent an unknown answer so repeat the invitation question
                        sendInvitationQuestion(message.getFrom(), session);
                    }
                }
                else if (session.getCurrentStep() == 6) {
                    // User is answering email question
                    if (yes.equalsIgnoreCase(message.getBody().trim())) {
                        // User accepted to receive the transcript by email
                        List<String> emailValue = session.getAttributes().get("email");
                        if (emailValue == null || emailValue.isEmpty()) {
                            // The user wants to get the transcript by email but he hasn't provided
                            // an email yet so ask for one
                            sendGetEmailQuestion(message, session);
                        }
                        else {
                            // Send the transcript by email
                            sendTranscriptByMail(emailValue.get(0), message, session);
                            // Send a goodbye message and close the chat session
                            closeSession(message);
                        }
                    }
                    else if (no.equalsIgnoreCase(message.getBody().trim())) {
                        // User rejected to receive the transcript by email so send a goodbye
                        // message and close the chat session

⌨️ 快捷键说明

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