Java tutorial
/* * Copyright 2013 Robert Gacki <robert.gacki@cgi.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.otto.mongodb.profiler; import org.joda.time.DateTime; import org.joda.time.Interval; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * A base implementation for an AsyncProfiler that uses a guard ({@link AbstractAsyncProfiler.ExecutionGuard}) that * can be used by a Runnable to determine whether to execute the operation. * * @author Robert Gacki */ public abstract class AbstractAsyncProfiler implements AsyncProfiler { /** * The guard to check whether a profiling task should be executed. * * @author Robert Gacki */ public static class ExecutionGuard { private final AtomicBoolean execute; private ExecutionGuard(final AtomicBoolean execute) { this.execute = execute; } /** * Determines whether a profiler operation should be executed. Returns {@code true} if the operation should * executed and {@code false} if not. * * @return {@code true} if the operation should executed and {@code false} if not */ public boolean execute() { return execute.get(); } } private final AtomicBoolean execute; private final ExecutionGuard executionGuard; private final Timer stopProfilingTimer; private volatile StopProfilingTimeout currentStopProfilingTimeout; private volatile DateTime profilingStarted; private final List<Interval> profilingRuntimes; protected AbstractAsyncProfiler(final boolean execute) { this.execute = new AtomicBoolean(execute); this.executionGuard = new ExecutionGuard(this.execute); this.stopProfilingTimer = new Timer(); this.profilingRuntimes = Collections.synchronizedList(new ArrayList<Interval>(20)); } /** * Returns the execution guard. * * @return the execution guard */ protected ExecutionGuard getExecutionGuard() { return executionGuard; } @Override public synchronized boolean continueProfiling() { final boolean started = execute.compareAndSet(false, true); if (started) { profilingStarted = DateTime.now(); } return started; } @Override public synchronized DateTime continueProfiling(long duration, TimeUnit timeUnit) { if (duration < 1) { throw new IllegalArgumentException("untilInterval must not be lower 1!"); } if (currentStopProfilingTimeout != null) { throw new IllegalStateException("A timer is already set!"); } if (!continueProfiling()) { return null; } final DateTime until = DateTime.now().plus(timeUnit.toMillis(duration)); stopProfilingTimer.schedule(new StopProfilingTimeout(this, until), new Date(until.getMillis())); return until; } @Override public DateTime getProfilingStarted() { return profilingStarted; } @Override public List<Interval> getProfilingRuntimes() { return new ArrayList<>(profilingRuntimes); } @Override public DateTime getTimeout() { final StopProfilingTimeout timeout = currentStopProfilingTimeout; return timeout != null ? timeout.getWhen() : null; } @Override public synchronized boolean stopProfiling() { if (currentStopProfilingTimeout != null) { currentStopProfilingTimeout.cancel(); currentStopProfilingTimeout = null; } final boolean stopped = execute.compareAndSet(true, false); if (stopped) { profilingRuntimes.add(new Interval(profilingStarted, DateTime.now())); profilingStarted = null; } return stopped; } @Override public boolean isProfiling() { return execute.get(); } private static class StopProfilingTimeout extends TimerTask { private final AbstractAsyncProfiler profiler; private final DateTime when; private StopProfilingTimeout(final AbstractAsyncProfiler profiler, final DateTime when) { this.profiler = profiler; this.when = when; } private DateTime getWhen() { return when; } @Override public void run() { profiler.stopProfiling(); } } }