More newbie questions

Hi,

Im a 2nd year computing student from the UK and for my secound year group project, we have decided to program a simple messaging system.

We are now experimenting with getting to grips with the Smack API and have run into some problems…

I have successfully run a simple program to send a message to another user, now my problem lies in setting up a packet listener to receive messages.

Could anyone perhaps show me a simple sample code for this?

I have only tried handling IQ packets, but I guess it would work for messages and such. Create a collector, then ask the collector if it has a packet.

// create a collector
PacketCollector pc=connection.createPacketCollector(new PacketTypeFilter(IQ.class)); while (!done) {
    // Poll to see if any packets for my collector have come         Packet p=pc.pollResult();     // If not null then we have a packet
    if (p!=null) {
        // Cast to an IQ, because I know it has to be an IQ packet
        IQ iq=(IQ)p;         // Pass to my IQ handler
        myIQHandler(iq);
    }
}

I haven’'t used anything but IQ packets, but I assume you could set the filter to collect Message packets and you could recieve message packets in the same manner.

I wanted to do the same thing. This is how I did it (using a code that I found in this forum).

FirstI created a class MyPacketFilter

import org.jivesoftware.smack.*;

import org.jivesoftware.smack.packet.Message;

import org.jivesoftware.smack.packet.Packet;

import org.jivesoftware.smack.filter.*;

public class MyPacketFilter implements PacketFilter {

public MyPacketFilter() {

}

public boolean accept(Packet packet) {

return true;

}

}

I also created a class MyPacketListener

import org.jivesoftware.smack.*;

import org.jivesoftware.smack.packet.Message;

import org.jivesoftware.smack.packet.Packet;

import org.jivesoftware.smack.filter.*;

public class MyPacketListener implements PacketListener {

XMPPConnection con = null;

public MyPacketListener(XMPPConnection con) {

this.con = con;

}

import org.jivesoftware.smack.*;

import org.jivesoftware.smack.packet.Message;

import org.jivesoftware.smack.packet.Packet;

import org.jivesoftware.smack.filter.*;

public class MyPacketListener implements PacketListener {

XMPPConnection con = null;

public MyPacketListener(XMPPConnection con) {

this.con = con;

}

/**

  • Processes the packet and handles presence subscribe requests

  • @param packet

*/

public void processPacket(Packet packet){

if (packet instanceof Message)

{

System.err.println(“true”);

Message msg = (Message)packet;

String body = msg.getBody();

System.err.println("FROM: "+packet.getFrom());

System.err.println("BODY: "+msg.getBody());

}

}

}

And finally I created a class ReceiveMsg

import org.jivesoftware.smack.*;

import org.jivesoftware.smack.packet.Message;

import org.jivesoftware.smack.packet.Packet;

import org.jivesoftware.smack.filter.*;

public class ReceiveMsg {

public static void main(String args[]) {

try {

XMPPConnection connection = new XMPPConnection(“localhost”);

Message msg;

MyPacketListener myPacketListener = new MyPacketListener(connection);

MyPacketFilter myFilter = new MyPacketFilter();

connection.login(“Test”, “park”);

connection.addPacketListener(myPacketListener , myFilter);

msg = connection.createChat(“Test@localhost”).nextMessage(5000);

} catch (Exception e){System.err.println(e);}

}

}

I am only using connection.createChat(“Test@localhost”).nextMessage(5000); so that the program will not end before receiving the message (and because I thought I could do it using the method nextMessage(). I failed .

Hope that will help you.

Nick.

Hi,

I think you should change your code to follow jstrohm’‘s example of polling. It’‘s a bit simpler and doesn’'t rely on receiving messages in a timeout period. Listeners are best used when your application stays up (due to other threads running) and you want to have messages arive as ‘‘events’’.

-iain

Thanks for the comments, they’'ve really helped.

However im slightly confused as to whether I should use PacketListener or PacketCollector…

I’'ve tried the example given to me by Tnikos and setup 3 classes in my testing program PacketFilter, PacketListener and RecieveMsg.

public class MyPacketFilter implements PacketFilter

{

public MyPacketFilter()

{

}

public boolean accept(Packet packet)

{

return true;

}

}

(I am assuming that this code will make the packetfilter allow all packets to pass)

public class MyPacketListener implements PacketListener

{

XMPPConnection con = null;

public MyPacketListener(XMPPConnection con)

{

this.con = con;

}

/**

  • Processes the packet and handles presence subscribe requests

  • @param packet

**/

public void processPacket(Packet packet)

{

if (packet instanceof Message)

{

System.err.println(“true”);

Message msg = (Message)packet;

String body = msg.getBody();

System.err.println("FROM: "+packet.getFrom());

System.err.println("BODY: "+msg.getBody());

}

}

}

and finally (where I am having problems)

public class ReceiveMsg

{

public static void main(String args[])

{

try

{

MyPacketListener myPacketListener = new MyPacketListener(connection);

MyPacketFilter myFilter = new MyPacketFilter();

connection.login(“alex”, “arj899”);

connection.addPacketListener(myPacketListener , myFilter);

Message msg = connection.createChat(“jarvis@localhost”).nextMessage(5000);

}

catch (Exception e)

{

System.err.println(e);

}

}

}

I now get a ‘‘unresolved identifier’’ message on

MyPacketListener myPacketListener = new MyPacketListener(connection);

any ideas on what im doing wrong here?

Cheers

I’'m not entirely clear on what the problem is, but I see a few issues with your code:

  1. The XMPPConnection object never gets initialized anywhere.

  2. After the main method exits, your program will stop. This is probably why you’'re not seeing any output.

  3. I don’'t see any reason you should be creating your own PacketFilter. Why not use one of the standard ones?

Anyway, here’'s a very simple program that will stay open listening for any messages and printing them out until you force quite the program (ctrl-c on Windows).

import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.filter.*; public class SimpleMsgListener extends Thread implements PacketListener {     public static void main(String [] args) throws Exception {
        XMPPConnection con = new XMPPConnection("jivesoftware.com");
        con.login("test", "test");
        PacketFilter filter = new PacketTypeFilter(Message.class);
        SimpleMsgListener listener = new SimpleMsgListener();
        listener.start();
        con.addPacketListener(listener, filter);
    }     public void processPacket(Packet packet) {
        // No need to do the instanceof check since we know the filter will only
        // send us message packets.
        Message message = (Message)packet;
        System.out.println("From: " + packet.getFrom());
        System.out.println("Body: " + message.getBody());
        System.out.println("--------------------------");
    }     public void run() {
        while (true) {
            try {
                Thread.sleep(100);
            }
            catch (Exception e) { }
        }
    }
}

Regards,

Matt

BTW, here’'s a version that uses a PacketCollector instead of a listener. As you can see, the code is quite a bit simpler:

import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.filter.*; public class SimpleMsgCollector {     public static void main(String [] args) throws Exception {
        XMPPConnection con = new XMPPConnection("jivesoftware.com");
        con.login("test", "test");
        PacketFilter filter = new PacketTypeFilter(Message.class);
        PacketCollector collector = con.createPacketCollector(filter);
        while (true) {
            Message message = (Message)collector.nextResult();
            System.out.println("From: " + message.getFrom());
            System.out.println("Body: " + message.getBody());
            System.out.println("--------------------------");
        }
    }
}

Regards,

Matt

Cheers all esp. Matt

The problem is now resolved thanks to your help, now we can get on with building our messenger

Hey,

I’‘ve run into some more problems… i’'ve tried each method and both has run into problems at runtime.

The main problem with the Packetlistener code is that it seems to ‘‘timeout’’ the server (jabberd) giving the message :-

20030401T00:43:16: (io_select): 127.0.0.1(15) is being connection rate limited

matt - what was the purpose of the run() method given in your example program? I know I need to pause the thread somehow but i’'ve tried a couple of times and it still doesnt seem to make any difference

Cheers for your help,

Alex

Jabberd has a ‘‘karma’’ setting that tries to ensure everyone gets a fair share of the server’'s bandwidth by limiting how many messages over a period of time are sent by a user. The setting is usually set so that normal IM/chat traffic will never run into the limit.

If your code is generating both sides of a conversation, then the normal pauses for reading and typing are eliminated and you’'ll run into rate limits. If you have control of jabberd, you can adjust the karma settings to accommodate your usage. Alternatively, use Jive Messenger http://www.jivesoftware.com/products/messenger which does not set connection rate limits.

If you want to limit your traffic on the client, then you need to do it on the sending side of the conversation, not the receiving side of the conversation. You haven’‘t shown the code you’‘re using to generate messages, but it’‘s probably in a tight loop. If you add a sleep to the loop you should be able to slow down the packet rate to fall below jabberd’'s karma setting.

-iain

how come i always get a NullPointerException on this line

Message message = (Message)collector.nextResult();

?

i’'m sure the instance collector exists… and nextResult() is supposed to block until a packet arrives, right?

yoga,

Are you using my sample code, or something different? Can you try turning on debugging to see what’'s going on with the XML?

Thanks,

Matt

here’'s my code snippet:

public void waitForMsg(){

try{

PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter "me@yahoo.jabber.org.uk"));

PacketCollector collector = con.createPacketCollector(filter);

}

catch(Exception e){

System.out.println(e);

}

while (true) {

message = (Message)collector.nextResult();

System.out.println("From: " + message.getFrom());

System.out.println("Body: " + message.getBody());

System.out.println("----


");

}

}

it went NullPointer on the nextResult() line.

and there’'s nothing from the debugger, the last lines are just roster retrievals.

Can you post the full stack trace?

Regards,

Matt

never mind that. i put the nextMessage() inside the try, and it worked. thanks!