de.otto.mongodb.profiler.AbstractAsyncProfiler.java Source code

Java tutorial

Introduction

Here is the source code for de.otto.mongodb.profiler.AbstractAsyncProfiler.java

Source

/*
 *  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();
        }
    }

}