Errata

All errata for Instant Messaging in Java are be posted here.

If you discover any mistakes in the book, you may post them in the Author Online Forum.


Chapter 2, Listing 2.2 Page 40:

The equality tests contain a NullPointerException problem. In tests where XOR (^) is used, a combination of AND (&&) and OR (||) tests should be used. This affects equalsDomain, equalsUser, and equalsResource. For example, equalsDomain() should read:

public boolean equalsDomain(String domain){
  if (this.domain == null && domain == null){
    return true;
  }

  if (this.domain == null || domain == null){
    return false;
 }

  return this.domain.equalsIgnoreCase(domain);
}

Even better, production code should not allow null values for the domain field (or any other field) of the JabberID class. In addition, there is a mismatch between the value "" (an empty string) and a null value for the domain or the other fields. Should they be equivalent? In equality tests, both indicate a default value for the field and should test as equivalent even though the book's JabberID class does behave this way.

You should also be aware that the JabberID class presented in the book is lacking code to enforce proper Jabber ID formats. For example, illegal characters such as '@', '/', etc. can be added to parts of the Jabber ID using the setter methods (Listing 2.1) and the toString() method (Listing 2.4) will generate invalid Jabber IDs.

In this Errata entry, I want to emphasize that the class is far from robust and probably requires 5x the amount of code present to be production worthy. ;) You should treat the book code as compilable, runnable pseudo-code and expect to invest some effort to turn it into production ready code.


Chapter 2, Page 54, First Paragraph:

The second and third occurrences of "unavailable" should be "available". The paragraph should read:

Check your "smirk" client telnet session. Notice that nothing has changed there. Its presence is still _unavailable_ so the server won't send messages to it. Let's update its presence to _available_ and see what happens. The process follows what we just did on the "iain" client session. However, let's use a shortcut. The <presence> packet default type is _available_ so we can omit it to save bandwidth (and typing). These actions are shown in steps 11 and 12.


Chapter 3, Pages 72-73:

The last two lines of page 72 and the following XML fragment on page 73 are repeated on page 73.


Chapter 4, Page 111:

The first paragraph of the page is repeated in the paragraph that follows. Skip the first paragraph and start reading in the second.

Page 112:

In the last full paragraph before section 4.2.3, the last sentence of that paragraph should read:

"By reading the reference section... it should be easy to determine what X extensions are important for your project."

Page 124:

Second to last sentence of the last paragraph should read:

"In addition, we can't be authenticated without having established a Jabber XML stream with the server and having an account on the server."

Page 129, Listing 4.7:

The for loop expression should use a NOT (!) in the conditional test. The loop will continue to consume messages until it finds one sent from "buffy".

for ( Packet packet = waitFor("message", null);
      ! packet.getFrom().startsWith("buffy");
      packet = waitFor("message",null) ){
    // do nothing while message is not from buffy
}
// message from buffy received.

Notice that the online source code has eliminated the loop entirely. The only message the test client should receive is one from "buffy".


Chapter 5, Listing 5.12, Page 160:

There are three errors in the code listing:

1) The for loop should have the opposite test (we want to loop while the packet sender nickname does not end in "smirk".

2) The for loop is missing an ending curly-brace to indicate no for loop body.

All together the for loop should look like this:

for (Packet packet = waitFor("message",null);
     !packet.getFrom().endsWith("smirk");
    packet = waitFor("message",null)){
}

3) The first instance of sleep(1000) is missing a semi-colon.


Chapter 6, Footnote 7, Page 171:

The word "packet" is misspelled. It should read:

"In this case, we are talking about a groupchat message packet that is written..."


Chapter 7, Listing 7.3, Page 201:

Third comment should read:

// Increment (sequence) times to get hash(sequence)


Chapter 7, Listing 7.5 Page 204:

In the digest authentication code, the password from the packet rather than the user's password is sent to the auth.isDigestAuthenticated() method. If you ever execute the code as written, it will throw NullPointerExceptions (password from the packet must be null to have passed the first test).

The correct code should read:

  void handleSetPacket(Packet query){

    String password = query.getChildValue("password");
    String digest = query.getChildValue("digest");
    String hash = query.getChildValue("hash");

    if (password != null){
      if (user.getPassword().equals(password)){
        authenticated();
        return;
      }
    } else if (digest != null){
      if (auth.isDigestAuthenticated(session.getStreamID(),
                                     user.getPassword(),
                                     digest)){
        authenticated();
        return;
      }
    } else if (hash != null){
      if (auth.isHashAuthenticated(user.getHash(),hash)){
        user.setHash(hash);
        int sequence = Integer.parseInt(user.getSequence()) - 1;
        user.setSequence(Integer.toString(sequence));
        authenticated();
        return;
      }
    }
    sendErrorPacket(401,"Bad user name or password");
  }

Chapter 8, Page 223:

The last <group> tag in the roster update XML snippet should be indented two more spaces.


Chapter 10, Page 279, Subsection 10.1.3:

The subsection title should read:

"Creating system administration tools and techniques"

The error also exists in the table of contents


Chapter 10:

The Kerberos security protocol is misspelled as Kerebos.


Appendix A, Page 302-3:

The Info/Query Extension table heading for the third column should read:

"Namespace"