package org.playorm.util.api.safethread; import java.util.TimerTask; import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; /** */ public abstract class SafeTimerTask extends TimerTask { private ExceptionListener listener = NullExceptionListener.singleton(); private Executor executor; private static final Logger log = Logger.getLogger(SafeTimerTask.class.getName()); private String id; /** * Creates an instance of SafeTimerTask. * @param h */ public SafeTimerTask(Executor exec, String id) { this(exec, null, id); } public SafeTimerTask(Executor exec, ExceptionListener listener, String id) { if(id == null) throw new IllegalArgumentException("id cannot be null"); if (listener != null) this.listener = listener; this.executor = exec; this.id = id; } /** * @see java.util.TimerTask#run() */ @Override public void run() { try { runImpl(); } catch(Throwable e) { log.log(Level.WARNING, "Exception running runnable possibly from the client's code. Check the stack trace", e); FireFailureOnClientThread r = new FireFailureOnClientThread(e); //put on event thread so client can't tie up our threads!!! executor.execute(r); } } private class FireFailureOnClientThread implements Runnable { private Throwable e; public FireFailureOnClientThread(Throwable e) { this.e = e; } public void run() { try { listener.fireFailure(e, id); } catch(Throwable e) { log.log(Level.WARNING, "Exception from client", e); } } } public void setExceptionHandler(ExceptionListener listener) { if(listener!=null) this.listener = listener; else this.listener = NullExceptionListener.singleton(); } protected abstract void runImpl() throws Throwable; }