Could not see any search results using Smack

Hello All,

I am having problems with searching using Smack. I am trying to search using a certain gateway (“tlen”) and, while it does work using Psi, it fails completely when I’'m doing it with Smack.

Here’'s the troubling little piece of code:

final XMPPConnection connection = messenger.getConnection();

final UserSearchManager search = new UserSearchManager(connection);

final String service = “tlen.” + connection.getServiceName();

try

{

final Form queryForm = search.getSearchForm(service);

final Form searchForm = queryForm.createAnswerForm();

//

// setting the form fields…

// I’'ve cut that out to make this shorter

//

SmackConfiguration.setPacketReplyTimeout(60000);

final ReportedData reportedData = search.getSearchResults(searchForm, service);

//

// reportedData is null !!

// WHY?

//

}

catch (XMPPException e)

{

e.printStackTrace();

}

So… reportedData is null.

On the debugger it looks like this:

This is what I’'m sending:

BUT on the Raw Received Packets there are some answers:

So… the basic question is, if I am doing anything wrong?

So… I think the IQ packet is not parsed correctly enough…

Could it be some issue in DataFormProvider? What do you think? I got down to this PacketReader fragment (parseIQ method):

else {

Object provider = ProviderManager.getIQProvider(elementName, namespace);

if (provider != null) {

if (provider instanceof IQProvider) {

iqPacket = ((IQProvider)provider).parseIQ(parser);

}

else if (provider instanceof Class) {

iqPacket = (IQ)PacketParserUtils.parseWithIntrospection(elementName,

(Class)provider, parser);

}

}

}

and DataFormProvider is picked according to the default search.providers file.

I’‘ve tried to test if I could succeed using a nightly build but, unfortunately, the build of 26 Sep wouldn’'t quite work for me.

Well, I know my problem is hard to recreate so I shouldn’‘t really count for any assistance, I’'ll be trying to debug the code and see what it gives.

Just one thing… Should anyone know of any recent and reliable nightly build, please let me know, ok?

Hi,

I couldn’‘t test all your example, but I’'ve tested the provider and there could be same issue but it seems to be working OK.

I’'ve tried to parse your XML response using this code:

XmlPullParser parser = new MXParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new StringReader(sample1)); UserSearch.Provider provider = new UserSearch.Provider();
SimpleUserSearch simpleUserSearch = (SimpleUserSearch) provider.parseIQ(parser);
            ReportedData reportedData = simpleUserSearch.getReportedData();
...

Where “sample1” is the string that post as a response.

I found that there could be a bug, but also the reportedData has the right information.

The problem is when the response has Items and Data Forms. The UserSearch.Provider answers to kinds of objects, UserSearch and SimpleUserSearch depending on the content of the packet.

If the packet is a query result and have Data Form then it fills a UserSearch and return it, but if the packet has some Items it just fill a SimpleUserSearch with that items and return it.

In this case the provider returns a SimpleUserSearch with this item:

<item jid="jarmoni@tlen.xxxxxxxxxxxxx"> <first>Andrzej</first> <last>Jarmoniuk</last> <nick>jarmoni</nick> <email></email>
</item>

And omit the Data Form information (actually it parses that part but the object containing it is discarded).

In your case both the Item and Data Form seems to have the same data, so maybe this is enough for you.

There’'s also a small issue that may confuse, the simpleUserSearch.toXML() answers the empty message that you post, but it have the Item, so if you are using the Smack Debug Window this could be the difference between the packet and the raw packet output.

I couldn’'t test this by invoking the UserSearch.sendSearchForm method, but it should be returning the same ReportedData as the code above with the result.

Let me know if this help you.

Thank you.

So I’'ve got around the problem by sending the iq:search packet myself instead of using UserSearch or UserSearchManager… this way I have the result as an IQ packet.

final Presence presence = new Presence(Presence.Type.AVAILABLE);
presence.setMode(Presence.Mode.AVAILABLE);
presence.setTo("tlen.aster.pl");
connection.sendPacket(presence);
                              
final UserSearch search = new UserSearch();
final Form form = search.getSearchForm(connection, "tlen.aster.pl").createAnswerForm();
               
form.setAnswer("maxgroups", "1");
form.setAnswer("tid", "jarmoni"); final DataForm dataForm = form.getDataFormToSend();
               
final PacketCollector collector = connection.createPacketCollector(new PacketTypeFilter(IQ.class));
               
search.addExtension(dataForm);
search.setType(IQ.Type.SET);
search.setTo("tlen.aster.pl");
connection.sendPacket(search);
               
final IQ response = (IQ) collector.nextResult();

Also, SimpleUserSearch class has package visibility in 2.2.1, so in order to get hold of a ReportedData object from it, one has to do some tricks with package names…

I think it’'s a somewhat coarse way but it seems to work.

Message was edited by: ajarmoniuk

I see.

I think I’'ve found the problem.

This is the Smack code

public ReportedData sendSearchForm(XMPPConnection con, Form searchForm, String searchService) throws XMPPException {
        UserSearch search = new UserSearch();
        search.setType(IQ.Type.SET);
        search.setTo(searchService);
        search.addExtension(searchForm.getDataFormToSend());         PacketCollector collector = con.createPacketCollector(new PacketIDFilter(search.getPacketID()));         con.sendPacket(search);         IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());         // Cancel the collector.
        collector.cancel();
        if (response == null) {
            throw new XMPPException("No response from server on status set.");
        }
        if (response.getError() != null) {
            return sendSimpleSearchForm(con, searchForm, searchService);
        }         return ReportedData.getReportedDataFrom(response);
    }

Witch is almost the same as yours, the only difference is the last part

return ReportedData.getReportedDataFrom(response);

We can assume that the “response” has the right data, two reasons, your code works and the provider works.

Now, the reported data expect a packet with a Data Form

public static ReportedData getReportedDataFrom(Packet packet) {
        // Check if the packet includes the DataForm extension
        PacketExtension packetExtension = packet.getExtension("x","jabber:x:data");
        if (packetExtension != null) {
            // Check if the existing DataForm is a result of a search
            DataForm dataForm = (DataForm) packetExtension;
            if (dataForm.getReportedData() != null)
                return new ReportedData(dataForm);
        }
        // Otherwise return null
        return null;
    }

But the IQ packet is a SimpleUserSearch, because of the provider test, and it doesn’'t contains a Data Form extension, it just has the items.

So the getReportedDataFrom returns null, and sendSearchForm returns null.

That seems to be the problem.

To sum up, if the packet result contains both Data Forms and Items the provider translate it to a SimpleUserSearch discarding the Data Form, and if you invoke the sendSearchForm method, it will try to return the Data Form part of the packet, witch was previously discarded. So the response of a SearchForm must only contains the result in the Data Form.

This seems to be a bug.