Custom presence, general extensibility

This isn’‘t actually a question. It’‘s a feature request, except that I’'m planning to do it myself – at least minimally – so it may become a feature contribution (assuming I can get it to work).

But if I’‘m missing some obvious approach, please tell me. I’‘ve been staring at this all day, and I don’'t see any alternative except to start hacking the library code.

I want to send add extra information to all presence packets that I send out. (Both regular presence and MUC presence.) This is for JEP-0115 – but there are probably other situations where people want to do stuff like that.

Smack provides no way to do this. The calls to construct Presence packets are hardwired. My most extreme idea was to subclass XMPPConnection and MultiUserChat… but I can’'t even do that, because all the fields of those classes are private.

So my current plan is to change all the “new Presence()” lines in Smack to, say, “connection.callPresenceFactory”. And then add a way to set a presence factory function. The default factory churns out ordinary Presence packets; then I can customize it to create JEP-0115 packets.

Similarly, I want to put extension forms into disco#info replies. ServiceDiscoveryManager doesn’‘t let me do this – and I can’‘t replace ServiceDiscoveryManager, because it installs itself automatically and there’'s no way to uninstall it. So, again, I need to go in and put in a factory function.

The more general request is, this would be much easier if the Smack code didn’'t mark so much stuff as private. Classes like Roster and ServiceDiscoveryManager should be easily subclassable. (And then created from factories, so that you can do something useful with the subclasses.)

As I said, I plan to do this work. At least for disco and presence. I’‘m working off of Smack 1.5.1, though. (We’'ve already got a big application running with that version.)

I think this is a valuable feature, but – well, of course I think that. It’‘s a pretty invasive change, obviously. I hate to drop in and say “Please redesign your basic architecture for me,” even if I can offer a small part of the redesign as a patch. (Which I hope I can offer in a few days.) But, it’'s what I need for this project.

Comments? Am I going about this completely the wrong way? Is this proposal repugnant to the underlying intent of Smack?

Hey:

Generally, changes to the core of XMPP like presenes aren’'t a good idea, mostly for the purpose of keeping the core simple. What were you hoping to acomplish by extending presence and maybe we can put our heads together and think up some alternative solutions?

Alex

I’‘m working on a specialized application that uses Jabber-RPC for its back-end communication. The RPC part works fine. However, we’'d like to be able to recognize other Jabber clients that use the same RPC protocol. (So that a user can, for example, select someone from his roster and send RPCs to the correct resource – the one which represents one of our applications, as opposed to a generic Jabber client.)

JEP-0115 is exactly what we need for this. We advertise extra capabilities in the presence packets, and then we know which resources are compatible apps.

(Another approach is to advertise extra capabilities in the app’'s disco#info response – put in an extension form. But that also requires me to hack the Smack source!)

I’'m working on a specialized application that uses

Jabber-RPC for its back-end communication. The RPC

part works fine. However, we’'d like to be able to

recognize other Jabber clients that use the same RPC

protocol. (So that a user can, for example, select

someone from his roster and send RPCs to the correct

resource – the one which represents one of our

applications, as opposed to a generic Jabber

client.)

JEP-0115 is exactly what we need for this. We

advertise extra capabilities in the presence packets,

and then we know which resources are compatible

apps.

The only time you would run in to this problem I think as far as smack is concerned is when the initial available presence is sent, and I guess in all of the MUC code you discussed earlier. Maybe some sort of presence packet factory, as you suggested, would work out in these case. My recommendation would be to create a patch that implements your needed changes, sticking to the jabber protocol’'s, and submit it to the developers.

(Another approach is to advertise extra capabilities

in the app’'s disco#info response – put in an

extension form. But that also requires me to hack

the Smack source!)

Why do you need to smack the smack source here, can’'t you just do a ServiceDiscoveryManager#addFeature() ? Or is there something I am not understanding?

Alex

can’'t you just do a ServiceDiscoveryManager#addFeature()

In other parts of the system, we’'re using service discovery extensions (JEP-0128) to include a bunch of information in an form. We want to do the same in the Java client.

Can you just add a DataForm with the appropriate information to your packet?

I spent several hours trying to do exactly that. No go.

The packet is created by ServiceDiscoveryManager. You can’‘t get access to it. You can’‘t subclass SDM, and if you could, you couldn’‘t install your version – the original SDM listener would remain in place, so (at best) you’'d be sending two replies to every disco query.

(I can’'t avoid having SDM hook itself up, because it does that at class loading time, and MultiUserChat loads the class.)

My best idea was to put a new PacketWriter into the XMPPConnection, which would watch for outgoing disco packets and add the form. No good. You can’'t get access to the PacketWriter, even by subclassing XMPPConnection.

I spent a couple of hours yesterday doing the private-to-protected conversion, which would allow all of the above to be possible. My in-progress source is up at http://cvs.sourceforge.net/viewcvs.py/volity/smack-dev-2.0-vol/ (if you don’'t mind wading through CVS.) I still have to finish the presence and disco code changes which will let me do what I want without a PacketWriter hack.

So, let me see if I understand this correctly then. There is extra data you want to add to the disco#info? Here is another possible solution for you: create your own namespace. If only your particular client will be able to access and use these features then it shouldn’'t be terribly burdensome to do so, in fact it may be even simpler then what you are attempting to do now. This is sort of an “in the mean time” solution, until the developers can add support for JEP-0128.

Yes, that would work as a workaround. But I figured it would be easier to actually add JEP-0128. That way I won’'t have to go back in to rewrite my app, someday in the future.

(It wasn’‘t as easy as I expected, but that’'s because I ran into the horrible thing where the XHTMLManager class loads before ServiceDiscoveryManager, and then explodes. Took me hours to figure out what was going on there.)

Anyway, I think I have done all the customization I need on Smack. My changes are visible at the CVS URL above. The step-by-step changelog is pasted below, in chronological order. (The header lines are CVS tags, in case you want to disentangle the changes.)

I offer all of this as my contribution to Smack. I think all of would be valuable to the library. Even though most Smack users will never need most of this stuff, it provides several new ways to extend the library without – well, without doing what I had to do.


  • original

Identical with the 2005-09-25 nightly build.

  • protected

Changed “private” fields and methods to “protected”. This covers most

of smack, and the disco/MUC features of smackx.

  • presence

All presence packets are now drawn from a factory API inside

XMPPConnection. The user can set a new factory, or subclass XMPPConnection

and have it set its own.

  • packethack

XMPPConnection’'s creation of its packetReader and packetWriter have

been broken out into a separate, protected method called

initPacketReaderAndWriter. (Analogous to initReaderAndWriter.)

This allows a subclass to create different ones. This is an extreme way

of making the XMPPConnection do what you want, but it’'s available if

you need it.

  • disco

Added service discovery extension forms (JEP-0128) to

ServiceDiscoveryManager.

Added a ServiceDiscoveryFactory API to ServiceDiscoveryManager, in case

you want your connections to use a subclass of SDM.