powered by Jive Software

Smack 4.1.0-Alpha3 and XMPPTCPConnection Stream Management problem

I am currently in the middle of an Android XMPP implementation which is working really well using Smack 4.1.0-Alpha3.

Unfortunately, I have come up against an issue with Stream Management which is giving me a hard time.

When enabled SM for a chat, I am getting NullPointerException in XMPPTCPConnection. The variable that is null is ‘unacknowledgedStanzas’ and it seems that this is never being initialised.

The only place it seems to be initialised is in the login method of XMPPTCPConnection but this only happens if, as seen on line 407, ‘isSmAvailable() && useSm’.

The useSm flag is set as I have done that on the connection already, but the ‘isSmAvailable’ method looks up the SM namespace in a ‘streamFeatures’ variable in AbstractXMPPConnection which seems to rely on the server advertising the fact that it supports SM through service discovery.

Sadly, XEP-0198 does not require a server implementation of SM to advertise the fact that it supports it. This means that the ‘unacknowledgedStanzas’ variable in XMPPTCPConnection is never initialised and therefore when accessed, throughs a NPE.

Any idea of a good way around this problem?

When enabled SM for a chat, I am getting NullPointerException in XMPPTCPConnection.
Always post the full stacktrace when reporting an Exception.

The variable that is null is ‘unacknowledgedStanzas’ and it seems that this is never being initialised.
As far as I can see, ‘unacknowledgedStanzas’ is correctly initialized.

Sadly, XEP-0198 does not require a server implementation of SM to advertise the fact that it supports it.
Of course it does require a server to announce ‘sm’ as stream feature.

Hey Flow,

You are, of course, correct. And apologies for not posting correct… it was my first post.

Anyway, the exception looks like this when I run tests against the library.

java.lang.NullPointerException
  at org.jivesoftware.smack.tcp.XMPPTCPConnection.processHandledCount(XMPPTCPConnection.java:1547)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$2300(XMPPTCPConnection.java:132)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1187)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$200(XMPPTCPConnection.java:969)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:988)

The variable ‘unacknowledgedStanzas’ does seem to be initialised correctly but in my instance it seems to not be initialised due to a missing StreamFeatureProvider for ‘urn:xmpp:sm:3’

Am I doing something wrong that is resulting in a feature provider not being added?

And yes, the server does advertise the stream feature for SM… it just doesn’t seem to come in service discovery as I expected it to.

Thanks for the help.

OK, I am getting a little further now.

If I manually call the static method on XMPPTCPConnection to turn on Stream Management:

XMPPTCPConnection.setUseStreamManagementDefault(true);

And then if I manually add a stream provider:

ProviderManager.addStreamFeatureProvider(StreamManagement.StreamManagementFeature.ELEMENT, StreamManagement.NAMESPACE, new StreamManagementStreamFeatureProvider());

Then it looks like it works.

It looks like client apps need to do this in order to enable stream management. Is this assumption correct or have I missed something?

And apologies for not posting correct… it was my first post.
No need for apologies, just wanted to share my thoughts.

And yes, the server does advertise the stream feature for SM… it just doesn’t seem to come in service discovery as I expected it to.
SM is never announced via service discovery as it’s a stream feature.

It looks like client apps need to do this in order to enable stream management. Is this assumption correct or have I missed something?
No, this should not be the case. SmackTcpSmackInitializer takes care of that.

The variable ‘unacknowledgedStanzas’ does seem to be initialised correctly but in my instance it seems to not be initialised due to a missing StreamFeatureProvider for ‘urn:xmpp:sm:3’

I don’t think the assumption that it’s caused by the StreamManagedStreamFeatureProvider not being registered is correct. Because if the Provider is not registered then isSmAvailable() will never return true, which will prevent XMPPTCPConnection from enabling StreamManagement, but then the server should/would not send a Resumed element, which causes to processHandledCount() from being invoked where the NPE happens.

But it’s conceivable that the server sends Resumed elements while SM is not active (for whatever reason). Could you verify this by enabling SmackConfiguration.DEBUG? Show us a complete XMPP trace from an example session, maybe we see how the client does not enable SM, but the server is nevertheless sending a Resumed element. Which server do you use?

Let me try to explain what I have done so far to enable stream management.

Original Approach

In my test code, I was using the SmackTcpSmackInitializer like so

SmackTcpSmackInitalizer smackTcpSmackInitalizer = new SmackTcpSmackInitalizer();
smackTcpSmackInitalizer.initialize();

I was then enabling stream management programmatically

connection.send(Enable.INSTANCE);

Thinking that this would ‘turn on’ stream management for the connection.

This was leading to my original NullPointerException…

java.lang.NullPointerException
  at org.jivesoftware.smack.tcp.XMPPTCPConnection.processHandledCount(XMPPTCPConnection.java:1547)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$2300(XMPPTCPConnection.java:132)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1187)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$200(XMPPTCPConnection.java:969)
  at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:988)

… when I tried to request acknowledgement of the messages I had sent like so

connection.requestSmAcknowledgement();

Alternative Approach

To work around this, I had to enable stream management by default on XMPPTCPConnection to ensure that the useSm flag on XMPPTCPConnection is set for new connections

XMPPTCPConnection.setUseStreamManagementDefault(true);

I also has to register the provider programmatically otherwise the call to the method ‘isSmAvailable()’ fails due to the stream feature not being registered.

ProviderManager.addStreamFeatureProvider(StreamManagement.StreamManagementFeature.ELEMENT, StreamManagement.NAMESPACE, new StreamManagementStreamFeatureProvider());

Once that was done, my test no longer fails with a NPE and I get the results I expect.

It seems that SmackTcpSmackInitializer should be doing this but I can’t seem to get it to work as expected. Are they any examples in documentation of using stream management properly?

Thanks.

In my test code, I was using the SmackTcpSmackInitializer like so
You should not do that, as Smack does that automatically

I was then enabling stream management programmatically

  1. connection.send(Enable.INSTANCE);
    You should not do that. Smack will enable SM if either SM is enabled as default or for the connection (XMPPTCPConnection.setUseStreamManagement(true)). It’s an unfortunate design that XMPPConnection.send(PlainStreamElement) is public and available to the user. This method is not meant to be used directly by the user.

XMPPTCPConnection.setUseStreamManagementDefault(true);

That’s all you need to enable SM (Which is also stated in the Smack 4.1 Readme and Upgrade Guide).

It seems that SmackTcpSmackInitializer should be doing this but I can’t seem to get it to work as expected.
If this is not done automatically by Smack, then other initializers may also not be run. I strongly recommend finding the cause why this is the case, because otherwise you will likely run in other trouble as well.