📄 chatbot.java
字号:
/**
* $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 + -