content: package org.airsonic.player.monitor;
  
  import com.codahale.metrics.MetricRegistry;
  import com.codahale.metrics.jmx.JmxReporter;
  import org.airsonic.player.service.ApacheCommonsConfigurationService;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  
  import java.util.concurrent.TimeUnit;
  
  /**
   * Created by remi on 17/01/17.
   */
  @Service
  public class MetricsManager {
  
      @Autowired
      private ApacheCommonsConfigurationService configurationService;
  
      // Main metrics registry
      private static final MetricRegistry metrics = new MetricRegistry();
  
      private static volatile Boolean metricsActivatedByConfiguration = null;
      private static Object _lock = new Object();
  
      // Potential metrics reporters
      private static JmxReporter reporter;
  
      private void configureMetricsActivation() {
          if (configurationService.containsKey("Metrics")) {
              metricsActivatedByConfiguration = Boolean.TRUE;
  
              // Start a Metrics JMX reporter
              reporter = JmxReporter.forRegistry(metrics)
                      .convertRatesTo(TimeUnit.SECONDS)
                      .convertDurationsTo(TimeUnit.MILLISECONDS)
                      .build();
              reporter.start();
          } else {
              metricsActivatedByConfiguration = Boolean.FALSE;
          }
      }
  
      private boolean metricsActivatedByConfiguration() {
          if (metricsActivatedByConfiguration == null) {
              synchronized (_lock) {
                  if (metricsActivatedByConfiguration == null) {
                      configureMetricsActivation();
                  }
              }
          }
          return metricsActivatedByConfiguration;
      }
  
      /**
       * Creates a {@link Timer} whose name is based on a class name and a
       * qualified name.
       */
      public Timer timer(Class clazz, String name) {
          if (metricsActivatedByConfiguration()) {
              return new TimerBuilder().timer(clazz, name);
          } else {
              return nullTimerSingleton;
          }
      }
  
      /**
       * Creates a {@link Timer} whose name is based on an object's class name and a
       * qualified name.
       */
      public Timer timer(Object ref, String name) {
          return timer(ref.getClass(),name);
      }
  
      /**
       * Initiate a {@link TimerBuilder} using a condition.
       * If the condition is false, a void {@link Timer} will finally be built thus
       * no timer will be registered in the Metrics registry.
       */
      public TimerBuilder condition(boolean ifTrue) {
          if (metricsActivatedByConfiguration()) {
              if (!ifTrue) {
                  return conditionFalseTimerBuilderSingleton;
              }
              return new TimerBuilder();
          } else {
              return nullTimerBuilderSingleton;
          }
      }
  
      public void setConfigurationService(ApacheCommonsConfigurationService configurationService) {
          this.configurationService = configurationService;
      }
  
      /**
       * A class that builds a {@link Timer}
       */
      public static class TimerBuilder {
  
          public Timer timer(Class clazz, String name) {
              com.codahale.metrics.Timer t = metrics.timer(MetricRegistry.name(clazz,name));
              com.codahale.metrics.Timer.Context tContext = t.time();
              return new Timer(tContext);
          }
  
          public Timer timer(Object ref, String name) {
              return timer(ref.getClass(),name);
          }
  
      }
  
      /**
       * A class that holds a Metrics timer context implementing {@link AutoCloseable}
       * thus it can be used in a try-with-resources statement.
       */
      public static class Timer implements AutoCloseable {
  
          private com.codahale.metrics.Timer.Context timerContext;
  
          protected Timer(com.codahale.metrics.Timer.Context timerContext) {
              this.timerContext = timerContext;
          }
  
          @Override
          public void close() {
              timerContext.stop();
          }
  
      }
  
  
      // -----------------------------------------------------------------
      // Convenient singletons to avoid creating useless objects instances
      // -----------------------------------------------------------------
      private static final NullTimer nullTimerSingleton = new NullTimer(null);
      private static final NullTimerBuilder conditionFalseTimerBuilderSingleton = new NullTimerBuilder();
      private static final NullTimerBuilder nullTimerBuilderSingleton = new NullTimerBuilder();
  
      private static class NullTimer extends Timer {
  
          protected NullTimer(com.codahale.metrics.Timer.Context timerContext) {
              super(timerContext);
          }
  
          @Override
          public void close() {
              // Does nothing
          }
      }
  
      private static class NullTimerBuilder extends TimerBuilder {
          @Override
          public Timer timer(Class clazz, String name) {
              return nullTimerSingleton;
          }
      }
  
  }
  