All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.sitebricks.stat.Stats Maven / Gradle / Ivy

package com.google.sitebricks.stat;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;

import static com.google.common.base.Preconditions.checkState;

/**
 * This class represents the collection of registered stats within an
 * injector. Its main roles are to act as a container for these stats, and
 * to provide access to them through its {@link #snapshot()} method.
 *
 * @author [email protected] (Dhanji R. Prasanna)
 */
@Singleton
final class Stats implements StatsSnapshotter {
  private static final Logger logger =
      Logger.getLogger(Stats.class.getCanonicalName());

  /** This is the value used for duplicate stats. */
  static final String DUPLICATED_STAT_VALUE = "duplicated value";

  private final ConcurrentMap stats =
      new MapMaker().makeMap();

  private Injector injector;

  @Inject Stats() { }

  @SuppressWarnings("UnusedDeclaration")
  @Inject void setInjector(Injector injector) {
    this.injector = injector;
    checkBindingsExistForExposers();
  }

  void register(StatDescriptor statDescriptor) {
    String statName = statDescriptor.getName();
    StatDescriptor existingDescriptor =
        stats.putIfAbsent(statName, statDescriptor);

    if (existingDescriptor != null &&
        !(existingDescriptor.getStatReader().equals(
            statDescriptor.getStatReader()))) {
      logger.warning(String.format(
          "You have two non-static stats using the same name [%s], "
              + "this is not allowed. \n"
              + "First encounter:  %s\nSecond encounter: %s",
          statName, existingDescriptor, statDescriptor));

      StatDescriptor syntheticDescriptor = StatDescriptor.of(
          statName, "Placeholder for duplicate stat",
          StatReaders.forObject(DUPLICATED_STAT_VALUE),
          StatExposers.IdentityExposer.class);
      stats.put(statName, syntheticDescriptor);
    } else {
      if (injector != null) {
        injector.getBinding(statDescriptor.getStatExposerClass());
      }
      stats.put(statName, statDescriptor);
    }
  }

  @Override
  public ImmutableMap snapshot() {
    checkState(injector != null,
        "Stats may not be snapshotted yet; injector has not been set");
    ImmutableMap.Builder builder =
        ImmutableMap.builder();
    for (StatDescriptor statDescriptor : stats.values()) {
      // Here we read the raw value
      Object statValue = statDescriptor.getStatReader().readStat();

      // And here we are careful to expose only the reference we should
      StatExposer statExposer =
          getStatExposer(statDescriptor.getStatExposerClass());
      @SuppressWarnings("unchecked") // We know we don't guarantee a  here.
      Object exposedValue = statExposer.expose(statValue);
      builder.put(statDescriptor, exposedValue);
    }
    return builder.build();
  }

  private StatExposer getStatExposer(
      Class statExposerClass) {
    return injector.getInstance(statExposerClass);
  }

  private void checkBindingsExistForExposers() {
    // We do an up-front check of
    Set> statExposerClasses = Sets.newHashSet();
    for (StatDescriptor statDescriptor : stats.values()) {
      statExposerClasses.add(statDescriptor.getStatExposerClass());
    }
    for (Class statExposerClass : statExposerClasses) {
      injector.getBinding(statExposerClass);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy