/******************************************************************************* * Copyright (c) 2008, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMware Inc. - initial contribution *******************************************************************************/ package org.eclipse.virgo.kernel.services.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import org.eclipse.virgo.nano.shim.serviceability.TracingService; /** * Delegate object that encapsulates common operations for {@link ExecutorService} implementations. * <p/> * Each {@link ExecutorService} should maintain its own instance of <code>ExecutorServiceDelegate</code>. * * <strong>Concurrent Semantics</strong><br/> * * Threadsafe. * */ final class ExecutorServiceDelegate { private final ApplicationNameAccessor accessor; private final Object monitor = new Object(); private long totalExecutionTime; public ExecutorServiceDelegate(TracingService tracingService) { this.accessor = new ApplicationNameAccessor(tracingService); } /** * Gets an estimate of the average amount of time spent processing successful tasks. * @param completedTaskCount * @return the estimate of time spent. * @see ThreadPoolExecutor#getCompletedTaskCount() */ public long getAverageExecutionTime(long completedTaskCount) { synchronized (this.monitor) { return completedTaskCount == 0 ? this.totalExecutionTime : this.totalExecutionTime / completedTaskCount; } } /** * Gets an estimate of the total amount of time spent processing successful tasks. * * @return the estimate of time spent. * @see ThreadPoolExecutor#getCompletedTaskCount() */ public long getExecutionTime() { synchronized (this.monitor) { return this.totalExecutionTime; } } /** * Creates a {@link Runnable} wrapper that gathers execution statistics for the supplied {@link Runnable}. * * @param delegate the <code>Runnable</code> to gather the statistics for. * @return the wrapper. */ public Runnable decorate(Runnable delegate) { return new KernelRunnable(delegate); } /** * Simple {@link Runnable} that tracks execution statistics for another, wrapped <code>Runnable</code> instance. * <p/> * * <strong>Concurrent Semantics</strong><br/> * * Threadsafe. * */ private class KernelRunnable implements Runnable { private final Runnable delegate; private final String applicationName; /** * @param delegate */ public KernelRunnable(Runnable delegate) { this.delegate = delegate; this.applicationName = accessor.getCurrentApplicationName(); } /** * {@inheritDoc} */ public void run() { long timeBefore = System.currentTimeMillis(); accessor.setCurrentApplicationName(this.applicationName); try { this.delegate.run(); } finally { accessor.setCurrentApplicationName(null); ExecutorServiceDelegate outer = ExecutorServiceDelegate.this; long time = System.currentTimeMillis() - timeBefore; synchronized (outer.monitor) { outer.totalExecutionTime += time; } } } } /** * Wrapper around {@link TracingService} that handles the service proxy disappearing. * <p/> * * <strong>Concurrent Semantics</strong><br /> * * Threadsafe. * */ private static class ApplicationNameAccessor { private final TracingService tracingService; public ApplicationNameAccessor(TracingService tracingService) { this.tracingService = tracingService; } /** * @return application name * @see TracingService#getCurrentApplicationName() */ public String getCurrentApplicationName() { return this.tracingService.getCurrentApplicationName(); } /** * @param applicationName * @see TracingService#setCurrentApplicationName(String) */ public void setCurrentApplicationName(String applicationName) { this.tracingService.setCurrentApplicationName(applicationName); } } }