/**
*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.xmpp.workgroup.search;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.dom4j.Element;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.xmpp.workgroup.AgentNotFoundException;
import org.jivesoftware.xmpp.workgroup.Workgroup;
import org.jivesoftware.xmpp.workgroup.WorkgroupManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.forms.DataForm;
import org.xmpp.forms.FormField;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
/**
* This class is responsible for handling all the packets sent to the workgroup service whose
* element name is transcript-search. If no data form is present inside the child element then
* the a search data form will be returned. Otherwise, the result of the search will be returned
* to the sender of the search request.
*
* @author Gaston Dombiak
*/
public class IQChatSearchHandler {
private static final Logger Log = LoggerFactory.getLogger(IQChatSearchHandler.class);
private static final String LOAD_META_DATA =
"SELECT metadataName, metadataValue FROM fpSessionMetadata WHERE sessionID=?";
private WorkgroupManager workgroupManager;
private DataForm searchForm;
private DataForm resultForm;
public IQChatSearchHandler(WorkgroupManager workgroupManager) {
this.workgroupManager = workgroupManager;
init();
}
public void handleIQ(IQ packet) {
try {
// Check that the sender of this IQ is an agent
workgroupManager.getAgentManager().getAgent(packet.getFrom());
Element iq = packet.getChildElement();
IQ reply = IQ.createResultIQ(packet);
if (iq.elements().isEmpty()) {
reply.setChildElement(iq.createCopy());
// Send the search form to the agent
reply.addExtension(searchForm.createCopy());
workgroupManager.send(reply);
}
else {
// Send the result of the search to the agent
Date startDate = null;
Date endDate = null;
Collection<Workgroup> workgroups = WorkgroupManager.getInstance().getWorkgroups();
JID agentJID = null;
String queryString = null;
// Get the search parameters from the completed form
DataForm submitedForm = (DataForm)packet.getExtension(DataForm.ELEMENT_NAME,
DataForm.NAMESPACE);
for (FormField field : submitedForm.getFields()) {
if ("date/start".equals(field.getVariable())) {
try {
startDate = DataForm.parseDate(field.getValues().get(0));
}
catch (ParseException e) {
Log.debug("Invalid startDate " +
field.getValues().get(0), e);
}
}
else if ("date/end".equals(field.getVariable())) {
try {
endDate = DataForm.parseDate(field.getValues().get(0));
}
catch (ParseException e) {
Log.debug("Invalid endDate " +
field.getValues().get(0), e);
}
}
else if ("workgroups".equals(field.getVariable())) {
if (!field.getValues().isEmpty()) {
workgroups = new ArrayList<Workgroup>();
for (String value : field.getValues()) {
try {
workgroups.add(
WorkgroupManager.getInstance().getWorkgroup(
new JID(value)));
}
catch (UserNotFoundException e) {
Log.debug("Invalid workgroup JID " +
value, e);
}
}
}
else {
// Search in all the workgroups since no one was specified
workgroups = WorkgroupManager.getInstance().getWorkgroups();
}
}
else if ("agent".equals(field.getVariable())) {
agentJID = new JID(field.getValues().get(0));
}
else if ("queryString".equals(field.getVariable())) {
queryString = field.getValues().get(0);
}
}
// Build the response
DataForm searchResults = resultForm.createCopy();
// Perform the search
for (Workgroup workgroup : workgroups) {
ChatSearch search = new ChatSearch(workgroup, startDate, endDate, agentJID,
queryString);
for (QueryResult result : search.getResults()) {
Map<String, Object> fields = new LinkedHashMap<String, Object>();
fields.put("workgroup", result.getWorkgroup().getJID().toBareJID());
fields.put("sessionID", result.getSessionID());
fields.put("startDate", result.getStartDate());
fields.put("agentJIDs", result.getAgentJIDs());
fields.put("relevance", result.getRelevance());
// Add Metadata
Map<String, String> metadata = getMetadataMap(result.getSessionID());
if (metadata.containsKey("question")) {
fields.put("question", metadata.get("question"));
}
if (metadata.containsKey("email")) {
fields.put("email", metadata.get("email"));
}
if (metadata.containsKey("username")) {
fields.put("username", metadata.get("username"));
}
searchResults.addItemFields(fields);
}
}
reply.setChildElement(iq.getName(), iq.getNamespaceURI());
reply.addExtension(searchResults);
workgroupManager.send(reply);
}
}
catch (AgentNotFoundException e) {
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(new PacketError(PacketError.Condition.not_authorized));
workgroupManager.send(reply);
}
}
private void init() {
// Configure the search form that will be sent to the agents
this.searchForm = new DataForm(DataForm.Type.form);
this.searchForm.setTitle("Chat search");
this.searchForm.addInstruction("Fill out this form to search for chats");
// Add starting date
FormField field = this.searchForm.addField();
field.setType(FormField.Type.text_single);
field.setLabel("Starting Date");
field.setVariable("date/start");
// Add ending date
field = this.searchForm.addField();
field.setType(FormField.Type.text_single);
field.setLabel("Ending Date");
field.setVariable("date/end");
// Add workgroup JID
field = this.searchForm.addField();
field.setType(FormField.Type.jid_multi);
field.setLabel("Workgroup");
field.setVariable("workgroups");
// Add agent JID
field = this.searchForm.addField();
field.setType(FormField.Type.jid_single);
field.setLabel("Agent");
field.setVariable("agent");
// Add query string
field = this.searchForm.addField();
field.setType(FormField.Type.text_single);
field.setLabel("Search Terms");
field.setVariable("queryString");
field.setRequired(true);
// Configure the form that will hold the search results
this.resultForm = new DataForm(DataForm.Type.result);
this.resultForm.addReportedField("workgroup", null, FormField.Type.jid_single);
this.resultForm.addReportedField("sessionID", null, FormField.Type.text_single);
this.resultForm.addReportedField("startDate", null, FormField.Type.text_single);
this.resultForm.addReportedField("agentJIDs", null, FormField.Type.jid_multi);
this.resultForm.addReportedField("relevance", null, FormField.Type.text_single);
}
private Map<String, String> getMetadataMap(String sessionID) {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
Map<String, String> map = new HashMap<String, String>();
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_META_DATA);
pstmt.setString(1, sessionID);
rs = pstmt.executeQuery();
while (rs.next()) {
String name = rs.getString(1);
String value = rs.getString(2);
map.put(name, value);
}
}
catch (Exception ex) {
Log.error(ex.getMessage(), ex);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return map;
}
}