Saturday, March 10, 2012

JEHA (Java Exception HAndler)

Exception handling is one of the most important features of Java language. Codifying try and catch blocks, however, is not a pleasant task. Sometimes it is necessary to repeat catch logic in many places of the program and be alert in choosing the correct exception class to use.

How about eliminate all code in catch blocks and make everything became annotations? This is the main idea of Jeha: Annotate your class. Jeha do the rest.

http://jeha.sourceforge.net/

Reverse Line Reader

We would need a class to read the log files in reverse order to display the latest message.

   1: package com.whitelotus.util;
   2:  
   3: import java.io.ByteArrayOutputStream;
   4: import java.io.File;
   5: import java.io.IOException;
   6: import java.io.RandomAccessFile;
   7: import java.io.UnsupportedEncodingException;
   8: import java.nio.ByteBuffer;
   9: import java.nio.channels.FileChannel;
  10:  
  11:  
  12: public class ReverseLineReader {
  13:     private static final int BUFFER_SIZE = 8192;
  14:  
  15:     private final FileChannel channel;
  16:     private final String encoding;
  17:     private long filePos;
  18:     private ByteBuffer buf;
  19:     private int bufPos;
  20:     private byte lastLineBreak = '\n';
  21:     private ByteArrayOutputStream baos = new ByteArrayOutputStream();
  22:  
  23:     public ReverseLineReader(File file, String encoding) throws IOException {
  24:         RandomAccessFile raf = new RandomAccessFile(file, "r");
  25:         channel = raf.getChannel();
  26:         filePos = raf.length();
  27:         this.encoding = encoding;
  28:     }
  29:  
  30:     public String readLine() throws IOException {
  31:         while (true) {
  32:             if (bufPos < 0) {
  33:                 if (filePos == 0) {
  34:                     if (baos == null) {
  35:                         return null;
  36:                     }
  37:                     String line = bufToString();
  38:                     baos = null;
  39:                     return line;
  40:                 }
  41:  
  42:                 long start = Math.max(filePos - BUFFER_SIZE, 0);
  43:                 long end = filePos;
  44:                 long len = end - start;
  45:  
  46:                 buf = channel.map(FileChannel.MapMode.READ_ONLY, start,
  47:                         len);
  48:                 bufPos = (int) len;
  49:                 filePos = start;
  50:             }
  51:  
  52:             while (bufPos-- > 0) {
  53:                 byte c = buf.get(bufPos);
  54:                 if (c == '\r' || c == '\n') {
  55:                     if (c != lastLineBreak) {
  56:                         lastLineBreak = c;
  57:                         continue;
  58:                     }
  59:                     lastLineBreak = c;
  60:                     return bufToString();
  61:                 }
  62:                 baos.write(c);
  63:             }
  64:         }
  65:     }
  66:  
  67:     private String bufToString() throws UnsupportedEncodingException {
  68:         if (baos.size() == 0) {
  69:             return "";
  70:         }
  71:  
  72:         byte[] bytes = baos.toByteArray();
  73:         for (int i = 0; i < bytes.length / 2; i++) {
  74:             byte t = bytes[i];
  75:             bytes[i] = bytes[bytes.length - i - 1];
  76:             bytes[bytes.length - i - 1] = t;
  77:         }
  78:  
  79:         baos.reset();
  80:  
  81:         return new String(bytes, encoding);
  82:     }
  83: }

Using ReverseLineReader



   1: public static void main(String[] args) throws IOException {
   2:       File file = new File("tps.log");
   3:       RandomAccessFile raf = new RandomAccessFile(file, "rw");
   4:       for(int i=0;i<=10;i++) {
   5:           raf.writeBytes("HELLO " + i + "\n");
   6:       }
   7:       raf.close();
   8:       ReverseLineReader reader = new ReverseLineReader(file, "UTF-8");
   9:  
  10:       String line;
  11:       while ((line = reader.readLine()) != null) {
  12:           System.out.println(line);
  13:       }
  14:   }
  15:  
  16:  

Java retry strategy

http://fahdshariff.blogspot.in/2009/08/retrying-operations-in-java.html

There are many cases in which you may wish to retry an operation a certain number of times. Examples are database failures, network communication failures or file IO problems.
Approach 1
This is the traditional approach and involves a counter and a loop.
   1: final int numberOfRetries = 5 ;
   2: final long timeToWait = 1000 ;
   3:  
   4: for (int i=0; i<numberOfRetries; i++) {
   5:  //perform the operation
   6:  try {
   7:   Naming.lookup("rmi://localhost:2106/MyApp");
   8:   break;
   9:  }
  10:  catch (Exception e) {
  11:   logger.error("Retrying...",e);
  12:   try {
  13:    Thread.sleep(timeToWait);
  14:   }
  15:   catch (InterruptedException i) {
  16:   }
  17:  }
  18: }

Approach 2
In this approach, we hide the retry counter in a separate class called RetryStrategy and call it like this:  


   1: public class RetryStrategy
   2: {
   3:  public static final int DEFAULT_NUMBER_OF_RETRIES = 5;
   4:  public static final long DEFAULT_WAIT_TIME = 1000;
   5:  
   6:  private int numberOfRetries; //total number of tries
   7:  private int numberOfTriesLeft; //number left
   8:  private long timeToWait; //wait interval
   9:  
  10:  public RetryStrategy()
  11:  {
  12:   this(DEFAULT_NUMBER_OF_RETRIES, DEFAULT_WAIT_TIME);
  13:  }
  14:  
  15:  public RetryStrategy(int numberOfRetries, long timeToWait)
  16:  {
  17:   this.numberOfRetries = numberOfRetries;
  18:   numberOfTriesLeft = numberOfRetries;
  19:   this.timeToWait = timeToWait;
  20:  }
  21:  
  22:  /**
  23:   * @return true if there are tries left
  24:   */
  25:  public boolean shouldRetry()
  26:  {
  27:   return numberOfTriesLeft > 0;
  28:  }
  29:  
  30:  /**
  31:   * This method should be called if a try fails.
  32:   *
  33:   * @throws RetryException if there are no more tries left
  34:   */
  35:  public void errorOccured() throws RetryException
  36:  {
  37:   numberOfTriesLeft --;
  38:   if (!shouldRetry())
  39:   {
  40:    throw new RetryException(numberOfRetries +
  41:      " attempts to retry failed at " + getTimeToWait() +
  42:      "ms interval");
  43:   }
  44:   waitUntilNextTry();
  45:  }
  46:  
  47:  /**
  48:   * @return time period between retries
  49:   */
  50:  public long getTimeToWait()
  51:  {
  52:   return timeToWait ;
  53:  }
  54:  
  55:  /**
  56:   * Sleeps for the duration of the defined interval
  57:   */
  58:  private void waitUntilNextTry()
  59:  {
  60:   try
  61:   {
  62:    Thread.sleep(getTimeToWait());
  63:   }
  64:   catch (InterruptedException ignored) {}
  65:  }
  66:  
  67:  public static void main(String[] args) {
  68:   RetryStrategy retry = new RetryStrategy();
  69:   while (retry.shouldRetry()) {
  70:    try {
  71:     Naming.lookup("rmi://localhost:2106/MyApp");
  72:     break;
  73:    }
  74:    catch (Exception e) {
  75:     try {
  76:      retry.errorOccured();
  77:     }
  78:     catch (RetryException e1) {
  79:      e.printStackTrace();
  80:     }
  81:    }
  82:   }
  83:  }
  84: }

Approach 3
Approach 2, although cleaner, hasn't really reduced the number of lines of code we have to write. In the next approach, we hide the retry loop and all logic in a separate class called RetriableTask. We make the operation that we are going to retry Callable and wrap it in a RetriableTask which then handles all the retrying for us, behind-the-scenes:


   1: public class RetriableTask<T> implements Callable<T> {
   2:  
   3:  private Callable<T> task;
   4:  public static final int DEFAULT_NUMBER_OF_RETRIES = 5;
   5:  public static final long DEFAULT_WAIT_TIME = 1000;
   6:  
   7:  private int numberOfRetries; // total number of tries
   8:  private int numberOfTriesLeft; // number left
   9:  private long timeToWait; // wait interval
  10:  
  11:  public RetriableTask(Callable<T> task) {
  12:   this(DEFAULT_NUMBER_OF_RETRIES, DEFAULT_WAIT_TIME, task);
  13:  }
  14:  
  15:  public RetriableTask(int numberOfRetries, long timeToWait,
  16:                       Callable<T> task) {
  17:   this.numberOfRetries = numberOfRetries;
  18:   numberOfTriesLeft = numberOfRetries;
  19:   this.timeToWait = timeToWait;
  20:   this.task = task;
  21:  }
  22:  
  23:  public T call() throws Exception {
  24:   while (true) {
  25:    try {
  26:     return task.call();
  27:    }
  28:    catch (InterruptedException e) {
  29:     throw e;
  30:    }
  31:    catch (CancellationException e) {
  32:     throw e;
  33:    }
  34:    catch (Exception e) {
  35:     numberOfTriesLeft--;
  36:     if (numberOfTriesLeft == 0) {
  37:      throw new RetryException(numberOfRetries +
  38:      " attempts to retry failed at " + timeToWait +
  39:      "ms interval", e);
  40:     }
  41:     Thread.sleep(timeToWait);
  42:    }
  43:   }
  44:  }
  45:  
  46:  public static void main(String[] args) {
  47:   Callable<Remote> task = new Callable<Remote>() {
  48:    public Remote call() throws Exception {
  49:     String url="rmi://localhost:2106/MyApp";
  50:     return (Remote) Naming.lookup(url);
  51:    }
  52:   };
  53:  
  54:   RetriableTask<Remote> r = new RetriableTask<Remote>(task);
  55:   try {
  56:    r.call();
  57:   }
  58:   catch (Exception e) {
  59:    e.printStackTrace();
  60:   }
  61:  }
  62: }
//creates a task which will retry 3 times with an interval of 5 seconds
RetriableTask r = new RetriableTask(3, 5000, new Callable(){
    public Object call() throws Exception{
        //put your code here
    }
});
r.call();