Tuesday, October 24, 2006

Part 3: Jabbering with Google Talk over XMPP

This is part 3 of a series of blogs on getting IM working with a Google Talk client using XMPP. Parts 1 and 2 are here -
Jabbering with Google Talk over XMPP
Part2: Jabbering with Google Talk over XMPP

This one is going to be short one because I managed the last part of the Google Talk basic IM interaction which was presence and messaging without too much effort.

Presence
Presence is how you announce that you are available/unavailable/busy/whatever. It is through presence that people tell you that they have stepped away for a quick cuppa mocha - the part where you can have witty remarks show up against your name - basically your network availability.

The basic presence part is easy - requiring sending only a stanza. If you are already on the "roster" (XMPP's name for a buddy list) then your presence will be indicated by your id going "online" in Google Talk. You would have to be invited and on the users' roster for that.

Doing the presence part itself is optional - you can still send messages even if you have not announed your presence. The only difference is that messages directed to you are not sent by Google Talk because it is not aware of your avaiability and your friends won't know if you are online.

Presence has a bunch of interesting details which I won't go into mostly because I skipped most of them :-) but here's a quick list of what it can do -

  • announce availability/unavailability plus a bunch of sub-states
  • provide comments along with status
  • allow for subscription (notification of presence of others on the server)
  • change subscription
  • etc
Instant Messaging
The whole IM bit is where I was leading through and here it is. I did cover in Part 2 the messaging part which was basically

<message from=\"XXXXXXXX@gmail.com/D922F673\" to=\"YYYY@gmail.com\" type='chat' xml:lang=\"en\"><body>TESTING!!!</body></message>

and this is pretty much it actually. You can have the following in the message though - subject(s), body and a thread.

So once you have set up a Thread reading from your response stream you get message stanzas from all your friends and you can send them your messages on the request stream - thats it. Google Talk behaves just fine identifying the program as a non-Google Talk client.

Here's a silly picture of the two clients talking to each other.

Saturday, October 07, 2006

Answers to some seemingly common Java questions

Whenever I go through the Keyword Analysis page of Statcounter, which manages my blog web usage statistics for me, I see a bunch of Java questions which I can answer. However the page that people land on to never has the relevant answer to the query. With my recent Repetitive Stress Injury I am pretty much staying away from doing any more work than is required to help my hands heal faster. This is keeping me from working on my Google Talk programs. So, having nothing better to do I am going to try and answer some of the questions or searches that I saw coming to my blog.

Search Keywords: Java printStackTrace does not show line number
Happens if the classes that are part of the stack trace have not been compiled with the debugging option (-g) on. Here's the link for details on javac's options. The solution is to re-compile the classes with this option on and then recreate the exception. If it is not code you can build then there is not much you can do here unfortunately - you will have to analyze the code to figure out where it went wrong. Not having debug information while compiling usually also means that you won't get any local variable information while debugging in a JPDA debugger (to be complete precise that would mean that the -g:vars option has not been specified).

Search Keywords: how can i tell what caused a concurrentmodificationexception?
A ConcurrentModificationException happens if a java.util.Collection is modified while an Iterator is iterating over it. There are many ways you can end up doing this - I am going to try and list the situations that I believe are most common.

Disclaimer: Code snippets do not use generics which won't make any difference anyway.
1.] Listeners
Consider this listener interface -


XYZListener.java
1 public interface XYZListener {
2 void eventOccurred(Event evt);
3 }



and this implementation -

XYZListenerImpl.java
4 public class XYZListenerImpl.java {
5 public void eventOccurred(Event evt) {
6 evt.getEventSource().removeXYZListener*this);
7 // do something useful
8 }
9 }

where Event.getEventSource() returns the object against whict XYZListenerImpl's instance was registed as a listener.

Now, you will get a ConcurrentModificationException if the EventSource is implemented this way -

EventSource.java
10 public class EventSource {
11 private List listeners = Collections.synchronizedList(new LinkedList());
12 public void addXYZListener(XYZListener l) {
13 if (!listeners.contains(l))
14 listeners.add(l)
15 }
16
17 public void removeXYZListener(XYZListener l) {
18 listeners.remove(l);
19 }
20
21 protected void fireEvent(Event evt) {
22 for (Iterator iter = listeners.iterator(); iter.hasNext();) {
23 XYZListener listener = (XYZListener)iter.next();
24 listener.eventOccurred(evt);
25 }
26 }
27 }

This is going to cause a ConcurrentModificationException at line 24 (assuming that there are more than one listeners registered and XYZListenerImpl is not the last one ;-)) because in line 6 the listeners List is modified while it is being iterated over in EventSource.fireEvent's Iterator.
The solution in this case is to use the right pattern for firing events -

protected void fireEvent(Event evt) {
List clonedList = new ArrayList(listeners);
for (Iterator iter = clonedList.iterator(); iter.hasNext();) { // [19 Dec] edited - thanks to Anon comment
XYZListener listener = (XYZListener)iter.next();
try {
listener.eventOccurred(evt);
} catch(Exception ex) {
// this prevents one bad listener from preventing the event from going to others
// log the exception
ex.printStackTrace();
}
}
}

2.] Incorrect coding
This will cause a ConcurrentModificationException -

public void someMethod(List l) {
for (Iterator iter = l.iterator(); iter.hasNext();) {
Object o = iter.next();
if (someCondition()) {
l.remove(o);
}
}



Fix this by using Iterator.remove() instead of doing a list.remove()

3.] Concurrency
The trickiest one is when the Collection gets modified by another thread while it is being iterated upon. One solution is to clone the collection (e.g. new ArrayList(list)) and then iterate upon it. To find out where the List got modified -
  1. Create a wrapper List similar to Collections.SynchronizedList which delegates all methods to the enclosed List.
  2. In the add/remove and any other method that modifies the List dump the current Thread's stacks using Thread.dumpStack. Refer to this. I suggest printing the current timestamp and the Thread's id for easy collating and the List's hashCode() to identify operations against each List instance.
  3. When you get the ConcurrentModificationException print the List's hashCode and look for the last print from the List modification logs for a list of this hashCode and you should know which two threads are the "culprits".

Search Keywords: how do you add a print statement ever 5 minutes in java
This is quite easy. Create a java.util.Timer class and add a TimerTask and set it to fire every 5 minutes and write the print statements in the TimerTask.

Search Keywords: using ethereal to capture google talk
This is not really possible after TLS is set up as I discussed in the comments here. Google Talk mandates TLS and once the stream gets encrypted the whole point of that is to not be able to sniff out the contents using something pretty much like Ethereal.

There are a couple of other interesting queries that I have not taken up
what are some things that made java so popular?
java 5 why
(I would say - Generics)
why isn't java used for games
(I really don't know if it is or it is not used for games and what kind of games?)