Commit 87e7616f authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Initial version. JM-1147

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@9292 b35dd754-fafc-0310-a699-88a17e54d16e
parent ec9e49e4
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.
*/
package org.jivesoftware.openfire.muc.spi;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.openfire.forms.DataForm;
import org.jivesoftware.openfire.forms.FormField;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.openfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.openfire.resultsetmanager.ResultSet;
import org.jivesoftware.openfire.resultsetmanager.ResultSetImpl;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.PacketError.Condition;
import java.util.*;
/**
* This class adds jabber:iq:search combined with 'result set management'
* functionality to the MUC service of Openfire.
*
* @author Guus der Kinderen - Nimbuzz B.V. <guus@nimbuzz.com>
* @author Giancarlo Frison - Nimbuzz B.V. <giancarlo@nimbuzz.com>
*/
public class IQMUCSearchHandler
{
/**
* The MUC-server to extend with jabber:iq:search functionality.
*/
private final MultiUserChatServer mucServer;
/**
* Creates a new instance of the search provider.
*
* @param mucServer
* The server for which to return search results.
*/
public IQMUCSearchHandler(MultiUserChatServer mucServer)
{
this.mucServer = mucServer;
}
/**
* Utility method that returns a 'jabber:iq:search' child element filled
* with a blank dataform.
*
* @return Element, named 'query', escaped by the 'jabber:iq:search'
* namespace, filled with a blank dataform.
*/
private static Element getDataElement()
{
final XDataFormImpl searchForm = new XDataFormImpl(DataForm.TYPE_FORM);
searchForm.setTitle("Chat Rooms Search");
searchForm.addInstruction("instrunctions");
final FormField typeFF = new XFormFieldImpl("FORM_TYPE");
typeFF.setType(FormField.TYPE_HIDDEN);
typeFF.addValue("jabber:iq:search");
searchForm.addField(typeFF);
final FormField nameFF = new XFormFieldImpl("name");
nameFF.setType(FormField.TYPE_TEXT_SINGLE);
nameFF.setLabel("Name");
nameFF.setRequired(false);
searchForm.addField(nameFF);
final FormField matchFF = new XFormFieldImpl("name_is_exact_match");
matchFF.setType(FormField.TYPE_BOOLEAN);
matchFF.setLabel("Name must match exactly");
matchFF.setRequired(false);
searchForm.addField(matchFF);
final FormField subjectFF = new XFormFieldImpl("subject");
subjectFF.setType(FormField.TYPE_TEXT_SINGLE);
subjectFF.setLabel("Subject");
subjectFF.setRequired(false);
searchForm.addField(subjectFF);
final FormField userAmountFF = new XFormFieldImpl("num_users");
userAmountFF.setType(FormField.TYPE_TEXT_SINGLE);
userAmountFF.setLabel("Number of users");
userAmountFF.setRequired(false);
searchForm.addField(userAmountFF);
final FormField maxUsersFF = new XFormFieldImpl("num_max_users");
maxUsersFF.setType(FormField.TYPE_TEXT_SINGLE);
maxUsersFF.setLabel("Max number allowed of users");
maxUsersFF.setRequired(false);
searchForm.addField(maxUsersFF);
final FormField includePasswordProtectedFF = new XFormFieldImpl(
"include_password_protected");
includePasswordProtectedFF.setType(FormField.TYPE_BOOLEAN);
includePasswordProtectedFF.setLabel("Include password protected rooms");
includePasswordProtectedFF.setRequired(false);
searchForm.addField(includePasswordProtectedFF);
final Element probeResult = DocumentHelper.createElement(QName.get(
"query", "jabber:iq:search"));
probeResult.add(searchForm.asXMLElement());
return probeResult;
}
/**
* Constructs an answer on a IQ stanza that contains a search request. The
* answer will be an IQ stanza of type 'result' or 'error'.
*
* @param iq
* The IQ stanza that is the search request.
* @return An answer to the provided request.
*/
public IQ handleIQ(IQ iq)
{
final IQ reply = IQ.createResultIQ(iq);
final Element formElement = iq.getChildElement().element(
QName.get("x", "jabber:x:data"));
if (formElement == null)
{
reply.setChildElement(getDataElement());
return reply;
}
// parse params from request.
final XDataFormImpl df = new XDataFormImpl();
df.parse(formElement);
boolean name_is_exact_match = false;
String subject = null;
int numusers = -1;
int numaxusers = -1;
boolean includePasswordProtectedRooms = true;
final Set<String> names = new HashSet<String>();
final Iterator<FormField> formFields = df.getFields();
while (formFields.hasNext())
{
final FormField field = formFields.next();
if (field.getVariable().equals("name"))
{
names.add(getFirstValue(field));
}
}
final FormField matchFF = df.getField("name_is_exact_match");
if (matchFF != null)
{
final String b = getFirstValue(matchFF);
if (b != null)
{
name_is_exact_match = b.equals("1")
|| b.equalsIgnoreCase("true")
|| b.equalsIgnoreCase("yes");
}
}
final FormField subjectFF = df.getField("subject");
if (subjectFF != null)
{
subject = getFirstValue(subjectFF);
}
try
{
final FormField userAmountFF = df.getField("num_users");
if (userAmountFF != null)
{
numusers = Integer.parseInt(getFirstValue(userAmountFF));
}
final FormField maxUsersFF = df.getField("num_max_users");
if (maxUsersFF != null)
{
numaxusers = Integer.parseInt(getFirstValue(maxUsersFF));
}
}
catch (NumberFormatException e)
{
reply.setError(PacketError.Condition.bad_request);
return reply;
}
final FormField includePasswordProtectedRoomsFF = df.getField("include_password_protected");
if (includePasswordProtectedRoomsFF != null)
{
final String b = getFirstValue(includePasswordProtectedRoomsFF);
if (b != null)
{
if (b.equals("0") || b.equalsIgnoreCase("false")
|| b.equalsIgnoreCase("no"))
{
includePasswordProtectedRooms = false;
}
}
}
// search for chatrooms matching the request params.
final List<MUCRoom> mucs = new ArrayList<MUCRoom>();
for (MUCRoom room : mucServer.getChatRooms())
{
boolean find = false;
if (names.size() > 0)
{
for (final String name : names)
{
if (name_is_exact_match)
{
if (name.equalsIgnoreCase(room.getNaturalLanguageName()))
{
find = true;
break;
}
}
else
{
if (room.getNaturalLanguageName().toLowerCase().indexOf(
name.toLowerCase()) != -1)
{
find = true;
break;
}
}
}
}
if (subject != null
&& room.getSubject().toLowerCase().indexOf(
subject.toLowerCase()) != -1)
{
find = true;
}
if (numusers > -1 && room.getParticipants().size() < numusers)
{
find = false;
}
if (numaxusers > -1 && room.getMaxUsers() < numaxusers)
{
find = false;
}
if (!includePasswordProtectedRooms && room.isPasswordProtected())
{
find = false;
}
if (find && canBeIncludedInResult(room))
{
mucs.add(room);
}
}
final ResultSet<MUCRoom> searchResults = new ResultSetImpl<MUCRoom>(
sortByUserAmount(mucs));
// See if the requesting entity would like to apply 'result set
// management'
final Element set = iq.getChildElement().element(
QName.get("set", ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT));
final List<MUCRoom> mucrsm;
// apply RSM only if the element exists, and the (total) results
// set is not empty.
final boolean applyRSM = set != null && !mucs.isEmpty();
if (applyRSM)
{
if (!ResultSet.isValidRSMRequest(set))
{
reply.setError(Condition.bad_request);
return reply;
}
try
{
mucrsm = searchResults.applyRSMDirectives(set);
}
catch (NullPointerException e)
{
final IQ itemNotFound = IQ.createResultIQ(iq);
itemNotFound.setError(Condition.item_not_found);
return itemNotFound;
}
}
else
{
// if no rsm, all found rooms are part of the result.
mucrsm = new ArrayList<MUCRoom>(searchResults);
}
ArrayList<XFormFieldImpl> fields = null;
final Element res = DocumentHelper.createElement(QName.get("query",
"jabber:iq:search"));
final XDataFormImpl resultform = new XDataFormImpl(DataForm.TYPE_RESULT);
boolean atLeastoneResult = false;
for (MUCRoom room : mucrsm)
{
fields = new ArrayList<XFormFieldImpl>();
XFormFieldImpl innerfield = new XFormFieldImpl("name");
innerfield.setType(FormField.TYPE_TEXT_SINGLE);
innerfield.addValue(room.getNaturalLanguageName());
fields.add(innerfield);
innerfield = new XFormFieldImpl("subject");
innerfield.setType(FormField.TYPE_TEXT_SINGLE);
innerfield.addValue(room.getSubject());
fields.add(innerfield);
innerfield = new XFormFieldImpl("num_users");
innerfield.setType(FormField.TYPE_TEXT_SINGLE);
innerfield.addValue(String.valueOf(room.getOccupantsCount()));
fields.add(innerfield);
innerfield = new XFormFieldImpl("num_max_users");
innerfield.setType(FormField.TYPE_TEXT_SINGLE);
innerfield.addValue(String.valueOf(room.getMaxUsers()));
fields.add(innerfield);
innerfield = new XFormFieldImpl("is_password_protected");
innerfield.setType(FormField.TYPE_BOOLEAN);
innerfield.addValue(Boolean.toString(room.isPasswordProtected()));
fields.add(innerfield);
innerfield = new XFormFieldImpl("is_member_only");
innerfield.setType(FormField.TYPE_BOOLEAN);
innerfield.addValue(Boolean.toString(room.isMembersOnly()));
fields.add(innerfield);
resultform.addItemFields(fields);
atLeastoneResult = true;
}
if (atLeastoneResult)
{
final FormField rffName = new XFormFieldImpl("name");
rffName.setLabel("Name");
resultform.addReportedField(rffName);
final FormField rffSubject = new XFormFieldImpl("subject");
rffSubject.setLabel("Subject");
resultform.addReportedField(rffSubject);
final FormField rffNumUsers = new XFormFieldImpl("num_users");
rffNumUsers.setLabel("Number of users");
resultform.addReportedField(rffNumUsers);
final FormField rffNumMaxUsers = new XFormFieldImpl("num_max_users");
rffNumMaxUsers.setLabel("Max number allowed of users");
resultform.addReportedField(rffNumMaxUsers);
final FormField rffPasswordProtected = new XFormFieldImpl(
"is_password_protected");
rffPasswordProtected.setLabel("Is a password protected room.");
resultform.addReportedField(rffPasswordProtected);
FormField innerfield = new XFormFieldImpl("is_member_only");
innerfield.setType(FormField.TYPE_TEXT_SINGLE);
innerfield.setLabel("Is a member only room.");
resultform.addReportedField(innerfield);
res.add(resultform.asXMLElement());
}
if (applyRSM)
{
res.add(searchResults.generateSetElementFromResults(mucrsm));
}
reply.setChildElement(res);
return reply;
}
/**
* Sorts the provided list in such a way that the MUC with the most users
* will be the first one in the list.
*
* @param mucs
* The unordered list that will be sorted.
*/
private static List<MUCRoom> sortByUserAmount(List<MUCRoom> mucs)
{
Collections.sort(mucs, new Comparator<MUCRoom>()
{
public int compare(MUCRoom o1, MUCRoom o2)
{
return o2.getOccupantsCount() - o1.getOccupantsCount();
}
});
return mucs;
}
/**
* Checks if the room may be included in search results. This is almost
* identical to {@link MultiUserChatServerImpl#canDiscoverRoom(MUCRoom room)},
* but that method is private and cannot be re-used here.
*
* @param room
* The room to check
* @return ''true'' if the room may be included in search results, ''false''
* otherwise.
*/
private static boolean canBeIncludedInResult(MUCRoom room)
{
// Check if locked rooms may be discovered
final boolean discoverLocked = JiveGlobals.getBooleanProperty("xmpp.muc.discover.locked", true);
if (!discoverLocked && room.isLocked())
{
return false;
}
return room.isPublicRoom();
}
/**
* Returns the first value from the FormField, or 'null' if no value has
* been set.
*
* @param formField
* The field from which to return the first value.
* @return String based value, or 'null' if the FormField has no values.
*/
public static String getFirstValue(FormField formField)
{
if (formField == null)
{
throw new IllegalArgumentException(
"The argument 'formField' cannot be null.");
}
Iterator<String> it = formField.getValues();
if (!it.hasNext())
{
return null;
}
return it.next();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment