diff --git a/source/org/jivesoftware/smackx/ReportedData.java b/source/org/jivesoftware/smackx/ReportedData.java index 35a446afc..6c51bfc93 100644 --- a/source/org/jivesoftware/smackx/ReportedData.java +++ b/source/org/jivesoftware/smackx/ReportedData.java @@ -55,13 +55,13 @@ public class ReportedData { // Otherwise return null return null; } - - + + /** * Creates a new ReportedData based on the returned dataForm from a search - *(namespace "jabber:iq:search"). - * - * @param dataForm the dataForm returned from a search (namespace "jabber:iq:search"). + *(namespace "jabber:iq:search"). + * + * @param dataForm the dataForm returned from a search (namespace "jabber:iq:search"). */ private ReportedData(DataForm dataForm) { // Add the columns to the report based on the reported data fields @@ -90,7 +90,29 @@ public class ReportedData { // Set the report's title this.title = dataForm.getTitle(); } - + + + public ReportedData(){ + // Allow for model creation of ReportedData. + } + + /** + * Adds a new Row. + * @param row the new row to add. + */ + public void addRow(Row row){ + rows.add(row); + } + + /** + * Adds a new Column + * @param column the column to add. + */ + public void addColumn(Column column){ + columns.add(column); + } + + /** * Returns an Iterator for the rows returned from a search. * @@ -102,7 +124,7 @@ public class ReportedData { /** * Returns an Iterator for the columns returned from a search. - * + * * @return an Iterator for the columns returned from a search. */ public Iterator getColumns() { @@ -111,19 +133,19 @@ public class ReportedData { /** - * Returns the report's title. It is similar to the title on a web page or an X + * Returns the report's title. It is similar to the title on a web page or an X * window. - * + * * @return title of the report. */ public String getTitle() { return title; } - + /** - * + * * Represents the columns definition of the reported data. - * + * * @author Gaston Dombiak */ public static class Column { @@ -133,20 +155,20 @@ public class ReportedData { /** * Creates a new column with the specified definition. - * + * * @param label the columns's label. * @param variable the variable name of the column. * @param type the format for the returned data. */ - private Column(String label, String variable, String type) { + public Column(String label, String variable, String type) { this.label = label; this.variable = variable; this.type = type; } - + /** * Returns the column's label. - * + * * @return label of the column. */ public String getLabel() { @@ -156,23 +178,23 @@ public class ReportedData { /** * Returns the column's data format. Valid formats are: - * + * * - * + * * @return format for the returned data. */ public String getType() { @@ -182,7 +204,7 @@ public class ReportedData { /** * Returns the variable name that the column is showing. - * + * * @return the variable name of the column. */ public String getVariable() { @@ -191,17 +213,17 @@ public class ReportedData { } - + public static class Row { private List fields = new ArrayList(); - - private Row(List fields) { + + public Row(List fields) { this.fields = fields; } - + /** * Returns the values of the field whose variable matches the requested variable. - * + * * @param variable the variable to match. * @return the values of the field whose variable matches the requested variable. */ @@ -214,22 +236,22 @@ public class ReportedData { } return null; } - + /** * Returns the fields that define the data that goes with the item. - * + * * @return the fields that define the data that goes with the item. */ private Iterator getFields() { return Collections.unmodifiableList(new ArrayList(fields)).iterator(); } } - - private static class Field { + + public static class Field { private String variable; private List values; - private Field(String variable, List values) { + public Field(String variable, List values) { this.variable = variable; this.values = values; } diff --git a/source/org/jivesoftware/smackx/search/SimpleUserSearch.java b/source/org/jivesoftware/smackx/search/SimpleUserSearch.java index 1469bbcd4..e3497d39a 100644 --- a/source/org/jivesoftware/smackx/search/SimpleUserSearch.java +++ b/source/org/jivesoftware/smackx/search/SimpleUserSearch.java @@ -13,41 +13,57 @@ package org.jivesoftware.smackx.search; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smackx.Form; import org.jivesoftware.smackx.FormField; +import org.jivesoftware.smackx.ReportedData; +import org.xmlpull.v1.XmlPullParser; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; -public class SimpleUserSearch extends IQ { - +/** + * SimpleUserSearch is used to support the non-dataform type of JEP 55. This provides + * the mechanism for allowing always type ReportedData to be returned by any search result, + * regardless of the form of the data returned from the server. + * + * @author Derek DeMoro + */ +class SimpleUserSearch extends IQ { private Form form; - - public Form getForm() { - return form; - } + private ReportedData data; public void setForm(Form form) { this.form = form; } + public ReportedData getReportedData() { + return data; + } + + public String getChildElementXML() { StringBuffer buf = new StringBuffer(); buf.append(""); - buf.append(getConvertedPacket()); + buf.append(getItemsToSearch()); buf.append(""); - System.out.println(buf.toString()); return buf.toString(); } - public String getConvertedPacket() { + private String getItemsToSearch() { StringBuffer buf = new StringBuffer(); if (form == null) { form = Form.getFormFrom(this); } + + if(form == null){ + return ""; + } + Iterator fields = form.getFields(); while (fields.hasNext()) { FormField field = (FormField) fields.next(); String name = field.getVariable(); - String value = getValue(field); + String value = getSingleValue(field); if (value.trim().length() > 0) { buf.append("<").append(name).append(">").append(value).append(""); } @@ -56,7 +72,7 @@ public class SimpleUserSearch extends IQ { return buf.toString(); } - public String getValue(FormField formField) { + private static String getSingleValue(FormField formField) { Iterator values = formField.getValues(); while (values.hasNext()) { return (String) values.next(); @@ -64,5 +80,52 @@ public class SimpleUserSearch extends IQ { return ""; } + protected void parseItems(XmlPullParser parser) throws Exception { + ReportedData data = new ReportedData(); + + boolean done = false; + + List fields = new ArrayList(); + while (!done) { + if(parser.getAttributeCount() > 0){ + String jid = parser.getAttributeValue("", "jid"); + List valueList = new ArrayList(); + valueList.add(jid); + ReportedData.Field field = new ReportedData.Field("jid", valueList); + fields.add(field); + } + int eventType = parser.next(); + + if (eventType == XmlPullParser.START_TAG && parser.getName().equals("item")) { + fields = new ArrayList(); + } + else if (eventType == XmlPullParser.END_TAG && parser.getName().equals("item")) { + ReportedData.Row row = new ReportedData.Row(fields); + data.addRow(row); + } + else if (eventType == XmlPullParser.START_TAG) { + String name = parser.getName(); + String value = parser.nextText(); + + List valueList = new ArrayList(); + valueList.add(value); + ReportedData.Field field = new ReportedData.Field(name, valueList); + fields.add(field); + + // Column name should be the same + ReportedData.Column column = new ReportedData.Column(name, name, "text-single"); + data.addColumn(column); + } + else if (eventType == XmlPullParser.END_TAG) { + if (parser.getName().equals("query")) { + done = true; + } + } + + } + + this.data = data; + } + } diff --git a/source/org/jivesoftware/smackx/search/Test.java b/source/org/jivesoftware/smackx/search/Test.java new file mode 100644 index 000000000..f008b9040 --- /dev/null +++ b/source/org/jivesoftware/smackx/search/Test.java @@ -0,0 +1,37 @@ +/** + * $RCSfile: ,v $ + * $Revision: 1.0 $ + * $Date: 2005/05/25 04:20:03 $ + * + * Copyright (C) 1999-2005 Jive Software. All rights reserved. + * + * This software is the proprietary information of Jive Software. Use is + subject to license terms. + */ + +package org.jivesoftware.smackx.search; + +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smackx.Form; +import org.jivesoftware.smackx.ReportedData; + +public class Test { + + public static void main(String args[]) throws Exception { + XMPPConnection.DEBUG_ENABLED = true; + XMPPConnection con = new XMPPConnection("jabber.org"); + con.login("ddman", "whocares"); + + UserSearchManager search = new UserSearchManager(con, "users.jabber.org"); + Form searchForm = search.getSearchForm(); + + Form answerForm = searchForm.createAnswerForm(); + answerForm.setAnswer("last", "Lynch"); + + ReportedData data = search.getSearchResults(answerForm); + + + System.out.println(data); + + } +} diff --git a/source/org/jivesoftware/smackx/search/UserSearch.java b/source/org/jivesoftware/smackx/search/UserSearch.java index ea2aaa6fa..79c453280 100644 --- a/source/org/jivesoftware/smackx/search/UserSearch.java +++ b/source/org/jivesoftware/smackx/search/UserSearch.java @@ -36,8 +36,10 @@ import org.xmlpull.v1.XmlPullParser; */ public class UserSearch extends IQ { + /** + * Creates a new instance of UserSearch. + */ public UserSearch() { - } public String getChildElementXML() { @@ -53,8 +55,9 @@ public class UserSearch extends IQ { * * @param con the current XMPPConnection. * @param searchService the search service to use. (ex. search.jivesoftware.com) + * @return the search form received by the server. * @throws org.jivesoftware.smack.XMPPException - * thrown if a server error has occured. + * thrown if a server error has occurred. */ public Form getSearchForm(XMPPConnection con, String searchService) throws XMPPException { UserSearch search = new UserSearch(); @@ -85,7 +88,7 @@ public class UserSearch extends IQ { * @param searchService the search service to use. (ex. search.jivesoftware.com) * @return ReportedData the data found from the query. * @throws org.jivesoftware.smack.XMPPException - * thrown if a server error has occured. + * thrown if a server error has occurred. */ public ReportedData sendSearchForm(XMPPConnection con, Form searchForm, String searchService) throws XMPPException { UserSearch search = new UserSearch(); @@ -107,6 +110,8 @@ public class UserSearch extends IQ { if (response.getError() != null) { return sendSimpleSearchForm(con, searchForm, searchService); } + + return ReportedData.getReportedDataFrom(response); } @@ -118,7 +123,7 @@ public class UserSearch extends IQ { * @param searchService the search service to use. (ex. search.jivesoftware.com) * @return ReportedData the data found from the query. * @throws org.jivesoftware.smack.XMPPException - * thrown if a server error has occured. + * thrown if a server error has occurred. */ public ReportedData sendSimpleSearchForm(XMPPConnection con, Form searchForm, String searchService) throws XMPPException { SimpleUserSearch search = new SimpleUserSearch(); @@ -140,7 +145,11 @@ public class UserSearch extends IQ { if (response.getError() != null) { throw new XMPPException(response.getError()); } - return ReportedData.getReportedDataFrom(response); + + if (response instanceof SimpleUserSearch) { + return ((SimpleUserSearch) response).getReportedData(); + } + return null; } /** @@ -148,12 +157,15 @@ public class UserSearch extends IQ { */ public static class Provider implements IQProvider { + /** + * Provider Constructor. + */ public Provider() { super(); } public IQ parseIQ(XmlPullParser parser) throws Exception { - UserSearch search = new UserSearch(); + UserSearch search = null; SimpleUserSearch simpleUserSearch = new SimpleUserSearch(); boolean done = false; @@ -163,8 +175,13 @@ public class UserSearch extends IQ { buildDataForm(simpleUserSearch, parser.getText(), parser); return simpleUserSearch; } - else if (eventType == XmlPullParser.START_TAG) { + else if (eventType == XmlPullParser.START_TAG && parser.getName().equals("item")) { + simpleUserSearch.parseItems(parser); + return simpleUserSearch; + } + else if (eventType == XmlPullParser.START_TAG && parser.getNamespace().equals("jabber:x:data")) { // Otherwise, it must be a packet extension. + search = new UserSearch(); search.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser)); @@ -176,7 +193,10 @@ public class UserSearch extends IQ { } } - return search; + if (search != null) { + return search; + } + return simpleUserSearch; } } @@ -188,7 +208,7 @@ public class UserSearch extends IQ { dataForm.setTitle("User Search"); dataForm.addInstruction(instructions); - if (eventType == XmlPullParser.START_TAG) { + if (eventType == XmlPullParser.START_TAG && !parser.getNamespace().equals("jabber:x:data")) { String name = parser.getName(); FormField field = new FormField(name); field.setType(FormField.TYPE_TEXT_SINGLE); @@ -199,9 +219,15 @@ public class UserSearch extends IQ { done = true; } } + else if (eventType == XmlPullParser.START_TAG && parser.getNamespace().equals("jabber:x:data")) { + search.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(), + parser.getNamespace(), parser)); + done = true; + } + } + if (search.getExtension("x", "jabber:x:data") == null) { + search.addExtension(dataForm); } - - search.addExtension(dataForm); } diff --git a/source/org/jivesoftware/smackx/search/UserSearchManager.java b/source/org/jivesoftware/smackx/search/UserSearchManager.java index 55d51f3e1..f33567983 100644 --- a/source/org/jivesoftware/smackx/search/UserSearchManager.java +++ b/source/org/jivesoftware/smackx/search/UserSearchManager.java @@ -14,39 +14,90 @@ import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smackx.Form; import org.jivesoftware.smackx.ReportedData; +import org.jivesoftware.smackx.ServiceDiscoveryManager; +import org.jivesoftware.smackx.packet.DiscoverInfo; +import org.jivesoftware.smackx.packet.DiscoverItems; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * The UserSearchManager is a facade built upon Jabber Search Services (JEP-055) to allow for searching + * repositories on a Jabber Server. This implementation allows for transparency of implementation of + * searching (DataForms or No DataForms), but allows the user to simply use the DataForm model for both + * types of support. + *
+ * XMPPConnection con = new XMPPConnection("jabber.org");
+ * con.login("john", "doe");
+ * UserSearchManager search = new UserSearchManager(con, "users.jabber.org");
+ * Form searchForm = search.getSearchForm();
+ * Form answerForm = searchForm.createAnswerForm();
+ * answerForm.setAnswer("last", "DeMoro");
+ * ReportedData data = search.getSearchResults(answerForm);
+ * // Use Returned Data
+ * 
+ * + * @author Derek DeMoro + */ public class UserSearchManager { private XMPPConnection con; - private String serviceName; + private String searchService; private UserSearch userSearch; - public UserSearchManager(XMPPConnection con, String serviceName) { + /** + * Creates a new UserSearchManager. + * + * @param con the XMPPConnection to use. + * @param searchService the name of the search service. (ex. search.jivesoftware.com) + */ + public UserSearchManager(XMPPConnection con, String searchService) { this.con = con; - this.serviceName = serviceName; - + this.searchService = searchService; userSearch = new UserSearch(); } - public Form getSearchForm() { - try { - return userSearch.getSearchForm(con, serviceName); - } - catch (XMPPException e) { - e.printStackTrace(); - } - return null; + /** + * Returns the form to fill out to perform a search. + * + * @return the form to fill out to perform a search. + * @throws XMPPException thrown if a server error has occurred. + */ + public Form getSearchForm() throws XMPPException { + return userSearch.getSearchForm(con, searchService); } - public ReportedData sendSearchForm(Form searchForm) { - ReportedData data = null; - try { - data = userSearch.sendSearchForm(con, searchForm, serviceName); - } - catch (XMPPException e) { - e.printStackTrace(); - } + /** + * Submits a search form to the server and returns the resulting information + * in the form of ReportedData + * + * @param searchForm the Form to submit for searching. + * @return the ReportedData returned by the server. + * @throws XMPPException thrown if a server error has occurred. + */ + public ReportedData getSearchResults(Form searchForm) throws XMPPException { + return userSearch.sendSearchForm(con, searchForm, searchService); + } - return data; + /** + * Returns a collection of search services found on the server. + * + * @return a Collection of search services found on the server. + * @throws XMPPException thrown if a server error has occurred. + */ + public Collection getSearchServices() throws XMPPException { + List searchServices = new ArrayList(); + ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(con); + DiscoverItems items = discoManager.discoverItems(con.getServiceName()); + for (Iterator it = items.getItems(); it.hasNext();) { + DiscoverItems.Item item = (DiscoverItems.Item) it.next(); + DiscoverInfo info = discoManager.discoverInfo(item.getEntityID()); + if (info.containsFeature("jabber:iq:search")) { + searchServices.add(item.getEntityID()); + } + } + return searchServices; } }