Saturday, January 22, 2011

stackoverflow - 10k rep

I've finally crossed the 10k reputation milestone on stackoverflow! I thought I'd take this opportunity to reflect back on my time as a member of this famous programming Q & A site.

Even though I was one of the first people to join stackoverflow when the beta version came out two years ago, I did not become an active participant until much more recently. I have found this site to be a great way of helping people with programming difficulties and also as a great learning resource. During my time here, I have:

  • answered 546 questions
  • asked 46 questions
  • participated across 609 tags (mainly java, unix, bash and xml)
  • received 35 badges - 2 gold, 10 silver and 23 bronze
I have really enjoyed being a member of stackoverflow. For me, it has not simply been a quest for a high reputation, but more about learning new technologies and picking up advice from other experts on the site. I like to take on challenging questions, rather than the easy ones, because it pushes me to do research into areas I have never looked at before, and I learn so much during the process. As a result, I have dabbled with certain libraries that I haven't used before, such as Apache Lucene.

It's hard juggling work and stackoverflow. The only times I get to use it are during the weekends and in the evenings after work. Most of the questions have already been answered by then! However, I still like browsing the questions and checking out the answers.

Anyway, I need to get back to it now. Let's see how fast I can make it to 20k!

Saturday, January 08, 2011

A Paginated JList

If you have a large JList and don't want to scroll through it, it might be a better idea to "paginate" it i.e. display the list in "pages" of a few rows at a time and allow users to flip back and forth between them. To do this, I have written a Java Swing component called PaginatedList, which looks like this:

You pass in a JList and specify a page size (the page size is 10 in this example) and it returns a PaginatedList which you can add onto another JComponent as normal. The code is shown below:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListModel;


/**
 * A paginated JList. Only displays a specific number of rows
 * and allows you to page back and forth through the list.
 * with the help of a toolbar.
 */
public class PaginatedList extends JPanel {

  private final int pageSize;
  private final JList list;
  private final ListModel model;
  private final int lastPageNum;
  private int currPageNum;
  private JLabel countLabel ;
  private JButton first, prev, next, last;

  /**
   * @param list the source list
   * @param pageSize the number of rows visible
   */
  public PaginatedList(JList list, int pageSize) {
      super();
      this.pageSize = pageSize;
      this.list = list;
      this.model = list.getModel();

      //work out how many pages there are
      this.lastPageNum = model.getSize() / pageSize +
                        (model.getSize() % pageSize != 0 ? 1 : 0);
      this.currPageNum = lastPageNum > 0 ? 1 : 0;

      setLayout(new BorderLayout());
      countLabel = new JLabel() ;
      add(countLabel, BorderLayout.NORTH);
      add(list, BorderLayout.CENTER);
      add(createControls(), BorderLayout.SOUTH);
      updatePage();
  }

  private JPanel createControls() {
      first = new JButton(new AbstractAction("<<") {
          public void actionPerformed(ActionEvent e) {
              currPageNum = 1;
              updatePage();
          }
      });

      prev = new JButton(new AbstractAction("<") {
          public void actionPerformed(ActionEvent e) {
              if (--currPageNum <= 0)
                  currPageNum = 1;
              updatePage();
          }
      });

      next = new JButton(new AbstractAction(">") {
          public void actionPerformed(ActionEvent e) {
              if (++currPageNum > lastPageNum)
                  currPageNum = lastPageNum;
              updatePage();

          }
      });

      last = new JButton(new AbstractAction(">>") {
          public void actionPerformed(ActionEvent e) {
              currPageNum = lastPageNum;
              updatePage();
          }
      });

      JPanel bar = new JPanel(new GridLayout(1, 4));
      bar.add(first);
      bar.add(prev);
      bar.add(next);
      bar.add(last);
      return bar;
  }

  private void updatePage() {

      //replace the list's model with a new model containing
      //only the entries in the current page.
      if(model.getSize() != 0){
          final DefaultListModel page = new DefaultListModel();
          final int start = (currPageNum - 1) * pageSize;
          int end = start + pageSize;
          if (end >= model.getSize()) {
              end = model.getSize();
          }
          for (int i = start; i < end; i++) {
              page.addElement(model.getElementAt(i));
          }
          list.setModel(page);
      }

      //update the label
      countLabel.setText("Page " + currPageNum + "/" + lastPageNum);

      // update buttons
      final boolean canGoBack = currPageNum > 1;
      final boolean canGoFwd = currPageNum != lastPageNum;
      first.setEnabled(canGoBack);
      prev.setEnabled(canGoBack);
      next.setEnabled(canGoFwd);
      last.setEnabled(canGoFwd);
  }

  public static void main(String args[]) throws Exception {

      // create 100 elements of dummy data.
      String[] data = new String[101];
      for (int i = 0; i < data.length; i++) {
          data[i] = "Item "+ (i + 1);
      }

      // create a paginated list with page size 20
      PaginatedList list = new PaginatedList(new JList(data), 10);

      // add it to a frame
      JFrame f = new JFrame("Paginated List Demo");
      f.add(list);
      f.setSize(100, 100);
      f.pack();
      f.setVisible(true);
  }
}

Saturday, January 01, 2011

fahd.blog in 2010

Happy 2011!
I'd like to wish everyone a great start to an even greater new year!

During 2010, I posted 47 new entries on fahd.blog, which is 23% more than in 2009. In addition to more posts, I am thrilled that I have more readers from all over the world too! Thanks for reading!

Top 5 posts of 2010:

I'm going to be writing a lot more this year, so stay tuned for more great techie tips, tricks and hacks! :)

Saturday, December 18, 2010

Automatically Retry Failed Jobs in Quartz

How do you handle job failures in Quartz? There are a few things you can do:
  • Do nothing. Let the job fail and log the error.
  • Retry continuously until the job succeeds.
  • Retry n times and then disable the job.
In this post, I will describe how you can configure your jobs to be retried on failure.

Retrying continuously until success:
If you want to keep trying over and over again until the job succeeds, all you have to do is throw a JobExecutionException with a flag to tell the scheduler to fire it again when it fails. The following code shows how:

class MyJob implements Job {

  public MyJob() {
  }

  public void execute(JobExecutionContext context)
                  throws JobExecutionException {
    try{
        //do something
    }
    catch(Exception e){

        Thread.sleep(10000); //sleep for 10 secs

        JobExecutionException e2 = new JobExecutionException(e);
        //fire it again
        e2.refireImmediately();
        throw e2;
    }
  }
}
Retrying n times:
It gets a bit more complicated if you want to retry a certain number of times only. You have to use a StatefulJob and hold a retryCounter in its JobDataMap, which you increment if the job fails. If the counter exceeds the maximum number of retries, then you can disable the job if you wish.
class MyJob implements StatefulJob {

  public MyJob() {
  }

  public void execute(JobExecutionContext context)
                                 throws JobExecutionException {
    JobDataMap dataMap = context.getJobDetail().getJobDataMap();
    int count = dataMap.getIntValue("count");

    // allow 5 retries
    if(count >= 5){
        JobExecutionException e = new JobExecutionException("Retries exceeded");
        //unschedule it so that it doesn't run again
        e.setUnscheduleAllTriggers(true);
        throw e;
    }


    try{
        //do something

        //reset counter back to 0
        dataMap.putAsString("count", 0);
    }
    catch(Exception e){
        count++;
        dataMap.putAsString("count", count);
        JobExecutionException e2 = new JobExecutionException(e);

        Thread.sleep(10000); //sleep for 10 secs

        //fire it again
        e2.refireImmediately();
        throw e2;
    }
  }
}

Saturday, December 11, 2010

Throw a checked exception from a method without declaring it

When you try to throw a checked exeption from a method in Java, the compiler will force you to either catch it or declare it to be thrown in the method declaration. For example, the following method fails to compile:
public void go(){
    throw new IOException();
}
The compiler says:
Dummy.java:15: unreported exception java.io.IOException;
must be caught or declared to be thrown
    throw new IOException();
    ^
1 error
However, if you declare it to be thrown in the method declaration, like this:
public void go() throws IOException{
    throw new IOException();
}
then it compiles successfully.

But is it possible to throw a checked exception WITHOUT declaring it to be thrown? You could wrap it in a RuntimeException (for example, new RuntimeException(new IOException()), but then you lose the ability to catch the checked exception in the caller method, because you have changed the type of the exception.

There is another trick you can use. I first noticed this being done in the JDK's java.lang.Class#newInstance0 method:

private T newInstance0()
    throws InstantiationException, IllegalAccessException
{
    ...
    // Run constructor
    try {
        return tmpConstructor.newInstance((Object[])null);
    } catch (InvocationTargetException e) {
        Unsafe.getUnsafe().throwException(e.getTargetException());
        // Not reached
        return null;
    }
    ...
}
As shown above, the method throws an InvocationTargetException but only declares the exceptions InstantiationException and IllegalAccessException to be thrown! The Sun utility class sun.misc.Unsafe is being used to throw a checked exception without declaring it. We could use the same approach, but unfortunately our code throws a security exception when we try to use it: java.lang.SecurityException: Unsafe. However, we can bypass this by using reflection to get hold of the unsafe variable directly, as shown below:
public void go() {
  getUnsafe().throwException(new IOException());
}

private Unsafe getUnsafe() {
  try {
    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    return (Unsafe) field.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}
So, why did the JDK developers do it this way? I don't know, but I'm sure they had a good reason. Although this is a neat trick to impress your friends, I wouldn't recommend using it. This is non-standard, undocumented, Sun-specific code which could change in future releases and may not be compatible with all JVMs. It also makes code harder to understand for others and violates the POLA.

Further Reading:
Avoiding Checked Exceptions [O'Reilly]