/** * */ package net.jxta.impl.util.threads; import java.util.concurrent.Callable; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import net.jxta.logging.Logging; /** * Decorator for Callable instances which will monitor how long it takes before the callable * is executed (the queue time), and how long it takes to execute. Some monitoring is done * in parallel with the task also, using a {@link LongTaskDetector}, to log warnings when * the task is taking an excessive amount of time to complete. * * @author iain.mcginniss@onedrum.com */ class RunMetricsWrapper<T> implements Callable<T>, Runnable { private Callable<T> wrappedRunnable; Thread executorThread; private long startTime; private ScheduledExecutorService longTaskMonitor; private String wrappedType; public RunMetricsWrapper(ScheduledExecutorService longTaskMonitor, Callable<T> wrapped) { this.wrappedRunnable = wrapped; this.longTaskMonitor = longTaskMonitor; this.wrappedType = wrapped.getClass().getName(); } public RunMetricsWrapper(ScheduledExecutorService longTaskMonitor, Runnable wrapped) { this(longTaskMonitor, new RunnableAsCallableWrapper<T>(wrapped)); this.wrappedType = wrapped.getClass().getName(); } public T call() throws Exception { executorThread = Thread.currentThread(); ScheduledFuture<?> future = longTaskMonitor.scheduleAtFixedRate(new LongTaskDetector(this), 1L, 5L, TimeUnit.SECONDS); startTime = System.currentTimeMillis(); T returnVal = wrappedRunnable.call(); long elapsedTime = System.currentTimeMillis() - startTime; future.cancel(true); if(elapsedTime > 200 && Logging.SHOW_WARNING && SharedThreadPoolExecutor.LOG.isLoggable(Level.WARNING)) { SharedThreadPoolExecutor.LOG.log(Level.WARNING, "task of type [{0}] took {1}ms to complete in the shared executor", new Object[] { getWrappedType(), elapsedTime }); } return returnVal; } public Object getExecutionTime() { return System.currentTimeMillis() - startTime; } public String getWrappedType() { return wrappedType; } public Object getExecutorThreadName() { return executorThread.getName(); } public StackTraceElement[] getStack() { return executorThread.getStackTrace(); } @Override public boolean equals(Object obj) { if(obj instanceof RunMetricsWrapper<?>) { wrappedRunnable.equals(((RunMetricsWrapper<?>)obj).wrappedRunnable); } return false; } @Override public int hashCode() { return wrappedRunnable.hashCode(); } public void run() { try { call(); } catch (Exception e) { } } }