Starting with tomorrow’‘s daily build, you’‘ll see a new smackx.jar file. This JAR contains Smack standard extensions, which will generally implement various JEP’'s found at:
So far, support for private data (JEP 49) is included (although it’'s not tested yet and may not work for another day or two). Gato will soon check-in support for sharing roster items (JEP 93) and is also working on message events (JEP 22).
The reason we’'re building a lot of this functionality into a seperate JAR is:
Not all users will need the functionality.
We want to keep the core JAR file as small as possible.
The main JAR file will eventually represent the core XMPP standard (once it is finalized) but nothing else. The smackx.jar will contain extended functionality the community has implemented but that other servers and clients may not support.
I gave the Private data extension a try (Aug 6 build) using the DefaultPrivateData feature. I added a PrivateDataManager to a connection and it saves PD using DefaultPrivateData ok. When trying to retrieve PD, I would get a ClassCastException when calling getPrivateData on the manager. I determined that I wasn’'t registering an IQProvider for the element and namespace. I used
(noob question: “PrivateDataManager.PrivateDataIQProvider()” is static, yet the compiler forces me to use “new”. I assume it’'s because the one method “ParseIQ” is not declared static?)
After that, the PrivateDataIQProvider.parseIQ wasn’‘t parsing correctly. Here’‘s patch that works for DefaultPrivateData, no guarantee it doesn’‘t break a custom pd handler (but it shouldn’'t):
public IQ parseIQ(XmlPullParser parser) throws Exception {
PrivateData privateData = null;
boolean done = false;
String elementName = parser.getName();
String namespace = parser.getNamespace();
// See if any objects are registered to handle this private data type.
Object provider = getPrivateDataProvider(elementName, namespace);
// If there is a registered provider, use it.
if (provider != null) {
if (provider instanceof PrivateDataProvider) {
privateData = ((PrivateDataProvider)provider).parsePrivateData(parser);
}
// Otherwise it''s a JavaBean, so use introspection.
else {
privateData = parseWithIntrospection(elementName, (Class)provider,
parser);
}
}
else {
DefaultPrivateData data = new DefaultPrivateData(elementName, namespace);
boolean finished = false;
while (!finished) {
int event = parser.next();
if (event == XmlPullParser.START_TAG) {
String name = parser.getName();
// If an empty element, set the value with the empty string.
if (parser.isEmptyElementTag()) {
data.setValue(name,"");
}
// Otherwise, get the the element text.
else {
event = parser.next();
if (event == XmlPullParser.TEXT) {
String value = parser.getText();
data.setValue(name, value);
}
}
}
else if (event == XmlPullParser.END_TAG) {
if (parser.getName().equals(elementName)) {
finished = true;
}
}
}
privateData = data;
}
IQ result = new PrivateDataResult(privateData);
return result;
}
Urg, the method name should be addPrivateDataProvider and not addIQProvider. I’'ll fix that. But, you have the right idea – just pass in a new instance of the provider class and that will be used for the parsing.
The private data using DefaultPrivateData is still broken in the Aug13 build. When the method is called, the parser is already on the first element so the parser.next() at the beginning of the while loop is throwing it off.
public IQ parseIQ(XmlPullParser parser) throws Exception {
PrivateData privateData = null;
boolean done = false;
while (!done) {
*int eventType = parser.next();*
if (eventType == XmlPullParser.START_TAG) {
Is there a reason that that outer while loop needs to stay? I had eliminated it from that previous patch I posted but maybe I’'ve missed something?
Also, you added a presenceChanged to the RosterListener interface (thanks!) but it never gets fired. In Roster.PresencePacketListener.processPacket the check is: entries.contains(key) where entries is an ArrayList of RosterEntries but “key” is a string.
I can’'t see anything wrong with the private data – can you paste in some example code that shows the issue? I just tested with the following and everything worked:
When I referenced the externally built jars, everything worked but when I referenced the project in Eclipse, I couldn’'t even get you example to work. It got that ClassCastException which clued me in that it was something about the IQ provider.
The reason it wouldn’‘t work through Eclipse is that you didn’‘t have the smack.providers file in the classpath. Most IDE’'s will let you add items to the classpath of the project which would let you compile from inside the IDE.
The PrivateDataIQProvider shouldn’‘t be registered by external classes since it’‘s already registered to handle private data IQ’‘s in the smack.providers file that is inside smackx.jar. Plus, I just don’‘t understand your code – it doesn’‘t make sense since private data uses an established element name and namespace according to its JEP. I’‘m not quite sure what you’'re trying to do…
Yea, I had my own smack.providers in the project so it wasn’'t picking up anything from the one you provided. Adding the appropriate entries to my smack.providers also lets it work.
The reason I was doing what I’'m doing is that I was confusing the function of PrivateDataIQProvider with addPrivateDataProvider. The reason for this confusion was that if you go back to the Aug06 build where I started playing with the PD stuff, the only way that it would work was to call ProviderManager.addIQProvider(“notes”,“http://us.insurgent.javeren/notes”,new PrivateDataManager.PrivateDataIQProvider()); and then loadPrivateData(“notes”,“http://us.insurgent.javeren/notes”);
Then when I saw addIQProvider having to be called with query/jabber:iq:private I thought we were going to be limited to a single handler for all private data. Now I see that’'s not the case
Though I bet there are some more gems like this in my code