ProviderManager.java issue

I started using the pluggable IQ mechanism in the 5/10 daily build. Very nice addition the Smack API.

I added the smack.providers file in the WEB-INF directory.

<?xml version="1.0"?>

query

jabber:iq:time

org.jivesoftware.smack.packet.Time

I had trouble getting the ProviderManager class with the XmlPullParser to read the child elements of the iqProvider. I had to add an extra parser.next() to get the child element text like:

if (eventType == XmlPullParser.START_TAG) {

if (parser.getName().equals(“iqProvider”)) {

parser.next();

parser.next();

System.out.println(parser.getName());

String elementName = parser.nextText();

System.out.println(elementName);

parser.next();

parser.next();

System.out.println(parser.getName());

String namespace = parser.nextText();

System.out.println(namespace);

parser.next();

parser.next();

System.out.println(parser.getName());

String className = parser.nextText();

System.out.println(className);

Doesn’'t make sense but seems to work. Something strange with the XmlPullParser or am I doing something wrong in the smack.providers file?

Thanks for the bug fix. It looks like I hadn’‘t properly tested the very latest version of the code. I’'ve put the fix in CVS, so it will be out with the next daily build.

Also, I’‘d love to hear any more thoughts you have about the new providers functionality. It’'s a tricky thing to get right, so feedback is appreciated before the official 1.1 release.

Regards,

Matt

Thank you Matt, this fix works in the 5/11 daily build.

The pluggable IQ mechanism is working great for me and is very easy and flexible to implement. I built a Time class that extends the IQ class which uses the bean introspection as noted in your Smack docs.

I can send a quick time request:

Packet pck = new Packet() {

public String toXML() {

return “<iq id=“jcl_007” to=“jabber.org” type=“get”><query xmlns=“jabber:iq:time”/>”;

}

};

connection.sendPacket(pck);

And get the interpreted response:

20030511T13:13:36CSTSun May 11 08:13:36 2003

Also, I’'d love to hear any more thoughts you have

about the new providers functionality. It’'s a tricky

thing to get right, so feedback is appreciated before

the official 1.1 release.

The only worry that I have about the provider functionality thus far is the limitation of having a single provider for a give namespace. While it’‘s fine for something like jabber:iq:last and other small namespaces, it might be a problem for something like jabber:iq:agents, jabber:iq: private or any other “large” namespace, or “multiple-function” namespace. i.e. the “private” namespace may contain sticky notes, prefs, anything else plus it may contain stuff from other programs that I may want to interpret (JAJC notes, etc). While it’‘s possible for the single class to be written to handle and dispatch as appropriate, if I get a jar from someone else that handles a certain type of private data, I won’'t be able to handle my own private data because only one handler for the namespace is allowed.

The solution that comes to my mind would be either a pluggable filter strategy where each “filter” registered for the namespace gets a shot at the packet, or a “chain of responsibility” approach (yea, I’'ve been reading some pattern books recently ).

Still don’‘t have enough of that OO mindset nor knowledge of all the jabber stuff to tell what would be the best approach but though I’'d toss this out as food for though.

Take care,

John

John,

Hmm… I’‘m really not convinced this is a problem. Trying to “solve” it would only make the whole system quite a bit more complex for very little gain in my opinion. I’‘d recommend that we wait until the current system doesn’'t work for a particular real-world use case before looking at making changes.

Thanks,

Matt

I agree with Matt. The core API is nice and clean right now. If the scenario you (insurgent) describe becomes a problem, I think the best solution is to create a generic, reusable provider that takes the single event, and implements either a filter/chain of responsibility/command pattern for sub-plug-ins. That way the core remains clean but the functionality is added in a way that minimizes rework.

-iain

glickster can you please send me your code where you send the packet and get the response?

Thank you.

Nick

You will need a \WEB-INF subdirectory off the directory you are running your client and/or smack api code. (Package names removed for this example)

Create a file call smack.providers with the following xml text:

<?xml version="1.0"?>

query

jabber:iq:time

Time <!Add your package name to the Time class if needed>

Add a Time class:

import org.jivesoftware.smack.packet.*;

/**

*/

public class Time extends IQ {

private String utc = null;

private String display = null;

private String tz = null;

public Time() {

setType(IQ.Type.GET);

}

public String getUtc() {

return utc;

}

public void setUtc(String utc) {

this.utc = utc;

}

public String getTz() {

return tz;

}

public void setTz(String tz) {

this.tz = tz;

}

public String getDisplay() {

return display;

}

public void setDisplay(String display) {

this.display = display;

}

public String getQueryXML() {

StringBuffer buf = new StringBuffer();

buf.append("<query xmlns=“jabber:iq:time”>");

if (utc != null) {

if (utc.equals("")) {

buf.append("");

}

else {

buf.append("").append(utc).append("");

}

}

if (tz != null) {

if (tz.equals("")) {

buf.append("");

}

else {

buf.append("").append(tz).append("");

}

}

if (display != null) {

if (display.equals("")) {

buf.append("");

}

else {

buf.append("").append(display).append("") ;

}

}

buf.append("");

return buf.toString();

}

}

Client code to login:

//Create a connection to the XMPP server.

XMPPConnection.DEBUG_ENABLED = true;

XMPPConnection con = new XMPPConnection(“jabber.org”);

con.login(“xxxxx”, “xxxxx”, “xxxxx”);

//Add filter to see everything basically

OrFilter or1 = new OrFilter(new PacketTypeFilter(IQ.class),

new PacketTypeFilter(Message.class));

OrFilter or2 = new OrFilter(new PacketTypeFilter(Presence.class), or1);

con.addPacketListener(this, or2);

Packet pck = new Packet() {

public String toXML() {

return “<iq id=“id1_001” to=“jabber.org” type=“get”><query xmlns=“jabber:iq:time”/>”;

}

};

con.sendPacket(pck);

Listener code to verify Time class is working:

public void processPacket(Packet packet) {

if (packet instanceof Message) {

Message message = (Message) packet;

System.out.println(“Message XML:” + message.toXML());

}

else if (packet instanceof IQ) {

IQ message = (IQ) packet;

System.out.println(“IQ XML:” + message.toXML());

if (message instanceof Time) {

System.out.println(“IQ XML from Time Class:” + message.toXML());

}

}

else if (packet instanceof Presence) {

Presence message = (Presence) packet;

System.out.println(“Presence XML:” + message.toXML());

}

}

Message was edited by: glickster