powered by Jive Software

Tracing an exception (with patch)

In the Roster class:

public RosterItem createRosterItem(JID user) {

return createRosterItem(user, /nickname/ null, null);

}

// nickname is null

public RosterItem createRosterItem(JID user, String nickname, List groups) {

org.xmpp.packet.Roster roster = new org.xmpp.packet.Roster();

roster.setType(IQ.Type.set);

// creating an item with null nickname

Roster.Item item = roster.addItem(user, nickname, null, Roster.Subscription.none, groups);

// trying to create a roster item with null nickname

RosterItem rosterItem = rosterItemProvider.createItem(username, new RosterItem(item));

broadcast(roster);

return rosterItem;

}

/code

RosterItemProvider:

private static final String CREATE_ROSTER_ITEM =

"INSERT INTO jiveRoster (username, rosterID, jid, sub, ask, recv, nick) " +

“VALUES (?, ?, ?, ?, ?, ?, ?)”;

public RosterItem createItem(String username, RosterItem item) {

Connection con = null;

PreparedStatement pstmt = null;

try {

con = DbConnectionManager.getConnection();

long rosterID = SequenceManager.nextID(JiveConstants.ROSTER);

pstmt = con.prepareStatement(CREATE_ROSTER_ITEM);

pstmt.setString(1, username);

pstmt.setLong(2, rosterID);

pstmt.setString(3, item.getJid().toBareJID());

pstmt.setInt(4, item.getSubStatus().getValue());

pstmt.setInt(5, item.getAskStatus().getValue());

pstmt.setInt(6, item.getRecvStatus().getValue());

pstmt.setString(7, item.getNickname());

pstmt.executeUpdate();

item.setID(rosterID);

insertGroups(rosterID, item.getGroups().iterator(), con);

}

catch (SQLException e) {

// swallowing is BAD, BAD, BAD! (well, not always)

// please log the original SQL message as well…

throw new UserAlreadyExistsException(item.getJid().toBareJID());

}

return item;

}

/code

wildfire_sybase.sql

CREATE TABLE jiveRoster (

rosterID INTEGER NOT NULL,

username NVARCHAR(32) NOT NULL, /* violated constraint */

jid TEXT NOT NULL,

sub INTEGER NOT NULL,

ask INTEGER NOT NULL,

recv INTEGER NOT NULL,

nick NVARCHAR(255),

CONSTRAINT jiveRoster_pk PRIMARY KEY (rosterID)

);

/code

To fix this issue, it’'s enough to change the Roster.createRoster(JID) to:

public RosterItem createRosterItem(JID user) {

return createRosterItem(user, user.getNode(), null);

}

/code

Hi Dimitar,

is this really a bug? IMHO “username” is set as a global var while creating the Roster and has nothing to do with “nickname”. If you experience exceptions there then the stacktrace should point to the method which instantiated Roster(null).

LG

Roster.java

public class Roster implements Cacheable {

private String username;

public Roster(String username) {

presenceManager = XMPPServer.getInstance().getPresenceManager();

rosterManager = XMPPServer.getInstance().getRosterManager();

sessionManager = SessionManager.getInstance();

this.username = username;

protected RosterItem provideRosterItem(JID user, String nickname, List groups) {

// trying to create a roster item with null nickname

RosterItem rosterItem = rosterItemProvider.createItem(username, new RosterItem(item));

/code

I cannot agree that this behaviour is by design. What I say is that any call to Roster.createRosterItem(JID) would end up in new UserAlreadyExistsException(jid.toBareJID()).

This exception might mislead the developer that the user is already in the roster, while in fact it has nothing to do with this. The exception will be caused by the NOT NULL constraint on the nickname column. Since the nickname (not username) is hardcoded to null, there is no way to call the said method of the Roster class and not get that exception no matter what the rest of the system state is.

I’'d be glad to be proven wrong. Please feel free to post a snippet of code to do it.

Hi Dimitar,

as far as I understand the code nickname is hardcoded to null, but username is used here:

RosterItem rosterItem = rosterItemProvider.createItem(username, new RosterItem(item));

/code

The nick column may be null so pstmt.setString(7, item.getNickname());[/code] should do no harm.

LG

oops…blush

I’‘ll check again tomorrow when I’'m back in the office. There was a violated null constraint, but it seems that my explanation was wrong.

It happens when you add to your roster some user who has never logged into the server. E.g. imagine that you have 2 users coming from LDAP - user A logs in first and adds user B before user B logs in for the first time.

The problem was traced to our database. I apologise for the wasted time.