powered by Jive Software

IQHandler not delivering packets

Trying to use an IQHandler inside messenger for custom IQ packets. Handler gets called for the packet, and we are returning a “result”, but can not get it delivered to the client. Using Messenger 2.1.1 and Smack 1.4.1.

FROM CLIENT:

Sends

private void sendAgentIQ() {

IQ iq = new AgentIQ();

iq.setType(IQ.Type.GET);

PacketCollector collector = xmppConn.createPacketCollector(new PacketIDFilter(iq.getPacketID()));

//PacketCollector collector = xmppConn.createPacketCollector(new PacketTypeFilter(IQ.class));

xmppConn.sendPacket(iq);

trace.logp(Level.FINE, thisClass, “sendAgentIQ”, “Sent agentIQ”);

IQ result = (IQ) collector.nextResult(5000);

if (result != null && result.getType() == IQ.Type.RESULT) {

trace.logp(Level.FINE, thisClass, “sendAgentIQ”, “Received IQ”);

trace.logp(Level.FINE, thisClass, “sendAgentIQ”, result.toXML());

}

}

SERVER SIDE IQ HANDLER:

// javadoc inherited IQHandler

public IQ handleIQ(IQ packet) {

trace.entering(thisClass, “handleIQ”);

IQ.Type type = packet.getType();

if ((type.equals(IQ.Type.set)) || (type.equals(IQ.Type.get))) {

trace.logp(Level.FINE, thisClass, “handleIQ”, “Processing set/get”);

IQ result;

result = IQ.createResultIQ(packet);

Element el = DocumentHelper.createElement(QName.get(AgentIQ.ROOT_EL, AgentIQ.NAMESPACE));

result.setChildElement(el);

trace.logp(Level.FINE, thisClass, “handleIQ”, result.toXML());

return result;

}

return null;

}

Traces following but client never gets the packet:

As additional information, looks like there is some sort of initialization issue with the Handler. Getting the following in the server log. Is it not possible to install a custom IQ handler as part of a plugin? Can it only be done as a module during XMPPServer bootstrap?

2005.03.10 22:38:35 org.jivesoftware.messenger.handler.IQHandler.process(IQHandler.java:70) Internal server error

java.lang.NullPointerException

at org.jivesoftware.messenger.handler.IQHandler.process(IQHandler.java:50)

at org.jivesoftware.messenger.IQRouter.handle(IQRouter.java:192)

at org.jivesoftware.messenger.IQRouter.route(IQRouter.java:74)

at org.jivesoftware.messenger.PacketRouter.route(PacketRouter.java:78)

at org.jivesoftware.messenger.net.SocketReadThread.readStream(SocketReadThread.jav a:207)

at org.jivesoftware.messenger.net.SocketReadThread.run(SocketReadThread.java:109)

There is definitely an initialization issue. It appears you must explicitly call initialize if you extend IQHandler and add the handler outside the normal server startup sequence.

public AgentIQHandler() {

super(“AgentIQ Handler”);

super.initialize(XMPPServer.getInstance());

}

Is this correct?

Hey Andrew,

From your code I guess that you are trying to add a new IQ handler to the server itself. So my first suggestion for you is that you may want to consider creating a plugin that includes a new component which will provide a new service. Your component will be responsible for handling any kind of packet whose domain matches the domain of your component.

For instance, if the server is “localhost” then your component could handle packet’'s whose domain is “myservice.localhost”. Following this approach will make your code more independent from server changes and you may also run your component with other servers.

If you want to follow your current approach you will need to make some changes to the server in order to be sure that your IQ handler will be properly initialized, found and used.

Changes to apply to the server:

  1. Modify XMPPServer#loadModules to include your new IQ handler

  2. Your IQ handler should redefine #handleIQ and #getInfo

  3. #getInfo: The idea of this method is to return an object that specifies the element and namespace that this IQ handler will handle. A common practice is to create this object once during the construction of your handler

  4. #handleIQ: This method is where the real action takes place. I think that your #sendAgentIQ should be called from this method. I don’'t see any problem why your packet is not being routed back to the client except the exception that you posted

You can look at the IQTimeHandler class which is a very simple IQ handler. Let me know if you have any problem.

Regards,

– Gato

Gato,

Thanks for the reply. I am doing steps 2-4 in your list. It was the missing step 1 that caused the problem.

I believe there is an implementation inheritance issue (creating an implied dependency) going on with IQHandler. It is not sufficient to implement the abstract methods. Success is also dependent on an implicit initialization sequence.

The plugin documentation includes an example of adding an IQHandler. However there is no mention of the initialization issue. This is what lead me astray.

It was not my intent to build Messenger to get the plugin / IQHandler to work. But this is the second time I have picked up there is an implicit assumption that any plugin should be incorporated into the general Messenger build process. This is fair, but not very clear to those new to the project. Might be helpful to more explicitly distinguish this, as it helps in making the decision between “chatbot” vs “extend server” approach to developing a custom application.

That said, think we are going to retreat to a “chatbot” approach using Smack.

Thanks again, great project!!!

Andrew,

Yep. I missed the option of adding the IQHandler as a plugin. Instead of doing step 1 you should follow the plugin idea.

I’'m not sure what initialization issue you are referring to. When your plugin is loaded you will need to send #addHandler(IQHandler) to the IQRouter as described in the plugin guide. The IQRouter will then send #getInfo() to the new IQHandler which you should answer with the element and namespace that your IQHandler is going to handle.

Let me know what clarifications we need to add to the plugin development guide.

Thanks,

– Gato

Gato -

I will try to be more to the point. There is a “bug” in 2.1.2 if you add an IQHandler as a Plugin. If the plugin is not loaded as a module, you have to explicitly call “initialize()” on your IQHandler instance before you call IQRouter::addHandler(). If you don’'t you will get a null pointer exception.

The base IQHandler implementation is relying on internal state that is set in “initialize()” when it is loaded as module. If your plugin IQHandler is not loaded as a module it will not work.

Think a note should at least be added to the plugin documentation. Fixing it might require some more thought.

Thanks again!

Andy

Hey Andy,

Good catch. I now see what you were saying. I will modify IQRouter#addHandler so that the new IQHandler will ask the new handler to be initialized.

Thanks,

– Gato

Andy,

You can get the latest code from the CVS or download the next nightly build and try again.

Thanks,

– Gato

Very Cool. Thanks!