Spark 2.7.4 duplicates only Pending contacts in roster after reconnect

Openfire 3.10.3 (CentOS 6 x86_64)

Spark 2.7.4 (Windows 7,8,10 32bit/64bit)

Hi all. Newbie to the forums. I’ve seen several tickets over time related to Spark duplicating contacts in rosters for various reasons, but I did not see anything specific to the case that was reported to me today. Regardless of:

  • reconnect is displayed as panel, in roster, or as icon
  • offline users are shown in a group or in assigned groups (or hidden entirely)
    …Pending contacts appear duplicated clientside each time the client returns from disconnected for some reason. The user is then forced to log off and back on to obtain a clean roster from Openfire as far as I can tell.

In my own testing, I’ve observed the following log occuring during such reconnection events.

Exception in thread “AWT-EventQueue-0” java.lang.ArrayIndexOutOfBoundsException: 8 >= 8

at java.util.Vector.elementAt(Unknown Source)

at javax.swing.DefaultListModel.getElementAt(Unknown Source)

at javax.swing.plaf.basic.BasicListUI.updateLayoutState(Unknown Source)

at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(Unknown Source)

at javax.swing.plaf.basic.BasicListUI.getPreferredSize(Unknown Source)

at javax.swing.JComponent.getPreferredSize(Unknown Source)

at org.jivesoftware.spark.component.VerticalFlowLayout.preferredLayoutSize(Vertica lFlowLayout.java:131)

at java.awt.Container.preferredSize(Unknown Source)

at java.awt.Container.getPreferredSize(Unknown Source)

at javax.swing.JComponent.getPreferredSize(Unknown Source)

at java.awt.BorderLayout.preferredLayoutSize(Unknown Source)

at java.awt.Container.preferredSize(Unknown Source)

at java.awt.Container.getPreferredSize(Unknown Source)

at javax.swing.JComponent.getPreferredSize(Unknown Source)

at java.awt.BorderLayout.preferredLayoutSize(Unknown Source)

at java.awt.Container.preferredSize(Unknown Source)

at java.awt.Container.getPreferredSize(Unknown Source)

at javax.swing.JComponent.getPreferredSize(Unknown Source)

at org.jivesoftware.spark.ui.ContactGroup.getPreferredSize(ContactGroup.java:899)

at org.jivesoftware.spark.component.VerticalFlowLayout.preferredLayoutSize(Vertica lFlowLayout.java:131)

at java.awt.Container.preferredSize(Unknown Source)

at java.awt.Container.getPreferredSize(Unknown Source)

at javax.swing.JComponent.getPreferredSize(Unknown Source)

at javax.swing.ScrollPaneLayout.layoutContainer(Unknown Source)

at java.awt.Container.layout(Unknown Source)

at java.awt.Container.doLayout(Unknown Source)

at java.awt.Container.validateTree(Unknown Source)

at java.awt.Container.validate(Unknown Source)

at javax.swing.RepaintManager$3.run(Unknown Source)

at javax.swing.RepaintManager$3.run(Unknown Source)

at java.security.AccessController.doPrivileged(Native Method)

at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(U nknown Source)

at javax.swing.RepaintManager.validateInvalidComponents(Unknown Source)

at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)

at java.awt.event.InvocationEvent.dispatch(Unknown Source)

at java.awt.EventQueue.dispatchEventImpl(Unknown Source)

at java.awt.EventQueue.access$500(Unknown Source)

at java.awt.EventQueue$3.run(Unknown Source)

at java.awt.EventQueue$3.run(Unknown Source)

at java.security.AccessController.doPrivileged(Native Method)

at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(U nknown Source)

at java.awt.EventQueue.dispatchEvent(Unknown Source)

at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)

at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)

at java.awt.EventDispatchThread.pumpEvents(Unknown Source)

at java.awt.EventDispatchThread.pumpEvents(Unknown Source)

at java.awt.EventDispatchThread.run(Unknown Source)

Eventually zeroing in on ContactList.class in spark.jar, I’ve made a couple tweaks and recompiled for a workaround for the time being that seems to address the situation. Basically I just skip adding any Pending users to the roster entirely, but during the addUser process I do pop a JOptionPane that calmly lets the user know the contact did actually get added and may not appear until the user accepts the request. Movement from Pending to Offline to Online appears to flow just fine after the change, with assigned group membership maintained.

I’m no programmer, so I can only offer conjecture and my kludgy workaround. What I gather is the enumeration of the Offline group during reconnection events isn’t properly accounting for Pending contact objects.

Has this condition been observed and possibly fixed in 2.7.5 / trunk? I simply haven’t had time to test any other builds or scan through the issue queue to know. Thanks, so much, for your hard work on Openfire, Smack, and Spark. Take care.
ContactList.patch.zip (815 Bytes)

No, such issue hasn’t been reported before (at least i don’t recall), so it hasn’t been addressed. We don’t have real java programmers working on Spark here either. So nobody can review your fix and check if it’s not braking anything. We can only test if Spark behaves ok after applying it. You can share your fix here (actual code changes, preferably in diff format). If it looks ok, it might be included in the next version.

I have reproduced and filed this as https://igniterealtime.org/issues/browse/SPARK-1678 (also linked to the ticket about duplicating offline users). I have also tested your patch. But i can’t accept it for the official source. It works as a workaround. Thanks for sharing the patch. Those who are affected by this issue a lot might want to apply it and build their own version of Spark. But i would prefer a proper fix for this and related issues with duplicating contacts.

Btw, i think that message is not necessary (it would involve also adding translation entry for that message). As i can see pending contact in the roster (just without an icon) and it is not duplicated during a reconnect.