/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2009-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.core.utils; import java.util.Map; import java.util.concurrent.TimeUnit; /** * Helper class used for tracking retires and timeouts for ServiceMonitors. * * @author <a href="mailto:ranger@opennms.org">Ben Reed</a> * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> * @author <a href="mailto:ranger@opennms.org">Ben Reed</a> * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> * @version $Id: $ */ public class TimeoutTracker { private final int m_retry; private final long m_timeoutInNanos; private final long m_timeoutInMillis; private final long m_timeoutInSeconds; private final boolean m_strictTimeouts; private int m_attempt = 0; private long m_nextRetryTimeNanos = -1L; private long m_attemptStartTimeNanos = -1L; /** * <p>Constructor for TimeoutTracker.</p> * * @param parameters a {@link java.util.Map} object. * @param defaultRetry a int. * @param defaultTimeout a int. */ public TimeoutTracker(Map<String,?> parameters, int defaultRetry, int defaultTimeout) { m_retry = ParameterMap.getKeyedInteger(parameters, "retry", defaultRetry); // make sure the timeout is a least 10 millis m_timeoutInMillis = Math.max(10L, ParameterMap.getKeyedInteger(parameters, "timeout", defaultTimeout)); m_timeoutInNanos = Math.max(10000000L, TimeUnit.NANOSECONDS.convert(m_timeoutInMillis, TimeUnit.MILLISECONDS)); m_timeoutInSeconds = Math.max(1L, TimeUnit.SECONDS.convert(m_timeoutInMillis, TimeUnit.MILLISECONDS)); m_strictTimeouts = ParameterMap.getKeyedBoolean(parameters, "strict-timeout", false); resetAttemptStartTime(); } /** * <p>shouldRetry</p> * * @return a boolean. */ public boolean shouldRetry() { return m_attempt <= m_retry; } /** * <p>getTimeoutInMillis</p> * * @return a long. */ public long getTimeoutInMillis() { return m_timeoutInMillis; } /** * <p>getTimeoutInSeconds</p> * * @return a long. */ public long getTimeoutInSeconds() { return m_timeoutInSeconds; } /** * <p>reset</p> */ public void reset() { m_attempt = 0; resetAttemptStartTime(); } private void resetAttemptStartTime() { m_attemptStartTimeNanos = -1L; } /** * <p>nextAttempt</p> */ public void nextAttempt() { m_attempt++; resetAttemptStartTime(); } /** * <p>getAttempt</p> * * @return a int. */ public int getAttempt() { return m_attempt; } /** * <p>startAttempt</p> */ public void startAttempt() { long now = System.nanoTime(); while (m_strictTimeouts && now < m_nextRetryTimeNanos) { sleep(m_nextRetryTimeNanos - now); now = System.nanoTime(); } m_attemptStartTimeNanos = System.nanoTime(); m_nextRetryTimeNanos = m_attemptStartTimeNanos + m_timeoutInNanos; } private void sleep(long nanos) { long millis = nanos / 1000000L; int remainingNanos = (int)(nanos % 1000000L); try { Thread.sleep(millis, remainingNanos); } catch (InterruptedException e) { // we ignore InterruptedExceptions } } private void assertStarted() { if (m_attemptStartTimeNanos < 0) { throw new IllegalStateException("Failed to call startAttempt before requesting elapsedTime.. This is most likely a bug"); } } /** * <p>elapsedTimeInMillis</p> * * @return a double. */ public double elapsedTimeInMillis() { return convertFromNanos(elapsedTimeNanos(), TimeUnit.MILLISECONDS); } /** * <p>elapsedTimeNanos</p> * * @return a long. */ public long elapsedTimeNanos() { long nanoTime = System.nanoTime(); assertStarted(); return nanoTime - m_attemptStartTimeNanos; } /** * <p>elapsedTime</p> * * @param unit a {@link java.util.concurrent.TimeUnit} object. * @return a double. */ public double elapsedTime(TimeUnit unit) { return convertFromNanos(elapsedTimeNanos(), unit); } private double convertFromNanos(double nanos, TimeUnit unit) { double nanosPerUnit = TimeUnit.NANOSECONDS.convert(1, unit); return nanos/nanosPerUnit; } /** {@inheritDoc} */ @Override public String toString() { return new StringBuilder(64) .append("timeout: ").append(getTimeoutInMillis()).append("ms") .append(" retry: ").append(m_attempt).append(" of ").append(m_retry) .toString(); } /** * <p>getSoTimeout</p> * * @return a int. */ public int getSoTimeout() { return (int)getTimeoutInMillis(); } /** * <p>getConnectionTimeout</p> * * @return a int. */ public int getConnectionTimeout() { return (int)getTimeoutInMillis(); } }