Package com.google.caliper.config

Source Code of com.google.caliper.config.CaliperConfig

/*
* Copyright (C) 2012 Google Inc.
*
* 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 com.google.caliper.config;

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

import com.google.caliper.api.ResultProcessor;
import com.google.caliper.config.VmConfig.Builder;
import com.google.caliper.util.Util;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.BiMap;
import com.google.common.collect.Collections2;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

/**
* Represents caliper configuration.  By default, {@code ~/.caliper/config.properties} and
* {@code global-config.properties}.
*
* @author gak@google.com (Gregory Kick)
*/
public final class CaliperConfig {
  @VisibleForTesting final ImmutableMap<String, String> properties;
  private final ImmutableMap<Class<? extends ResultProcessor>, ResultProcessorConfig>
      resultProcessorConfigs;

  @VisibleForTesting
  public CaliperConfig(ImmutableMap<String, String> properties)
      throws InvalidConfigurationException {
    this.properties = checkNotNull(properties);
    this.resultProcessorConfigs = findResultProcessorConfigs(subgroupMap(properties, "results"));
  }

  private static final Pattern CLASS_PROPERTY_PATTERN = Pattern.compile("(\\w+)\\.class");

  private static <T> ImmutableBiMap<String, Class<? extends T>> mapGroupNamesToClasses(
      ImmutableMap<String, String> groupProperties, Class<T> type)
          throws InvalidConfigurationException {
    BiMap<String, Class<? extends T>> namesToClasses = HashBiMap.create();
    for (Entry<String, String> entry : groupProperties.entrySet()) {
      Matcher matcher = CLASS_PROPERTY_PATTERN.matcher(entry.getKey());
      if (matcher.matches() && !entry.getValue().isEmpty()) {
        try {
          Class<?> someClass = Class.forName(entry.getValue());
          checkState(type.isAssignableFrom(someClass));
          @SuppressWarnings("unchecked")
          Class<? extends T> verifiedClass = (Class<? extends T>) someClass;
          namesToClasses.put(matcher.group(1), verifiedClass);
        } catch (ClassNotFoundException e) {
          throw new InvalidConfigurationException("Cannot find result processor class: "
              + entry.getValue());
        }
      }
    }
    return ImmutableBiMap.copyOf(namesToClasses);
  }

  private static ImmutableMap<Class<? extends ResultProcessor>, ResultProcessorConfig>
      findResultProcessorConfigs(ImmutableMap<String, String> resultsProperties)
          throws InvalidConfigurationException {
    ImmutableBiMap<String, Class<? extends ResultProcessor>> processorToClass =
        mapGroupNamesToClasses(resultsProperties, ResultProcessor.class);
    ImmutableMap.Builder<Class<? extends ResultProcessor>, ResultProcessorConfig> builder =
        ImmutableMap.builder();
    for (Entry<String, Class<? extends ResultProcessor>> entry : processorToClass.entrySet()) {
      builder.put(entry.getValue(), getResultProcessorConfig(resultsProperties, entry.getKey()));
    }
    return builder.build();
  }

  public ImmutableMap<String, String> properties() {
    return properties;
  }

  /**
   * Returns the configuration of the current host JVM (including the flags used to create it). Any
   * args specified using {@code vm.args} will also be applied
   */
  public VmConfig getDefaultVmConfig() {
    return new Builder(new File(System.getProperty("java.home")))
        .addAllOptions(Collections2.filter(ManagementFactory.getRuntimeMXBean().getInputArguments(),
            new Predicate<String>() {
              @Override public boolean apply(@Nullable String input) {
                // Exclude the -agentlib:jdwp param which configures the socket debugging protocol.
                // If this is set in the parent VM we do not want it to be inherited by the child
                // VM.  If it is, the child will die immediately on startup because it will fail to
                // bind to the debug port (because the parent VM is already bound to it).
                return !input.startsWith("-agentlib:jdwp");
              }
            }))
        // still incorporate vm.args
        .addAllOptions(getArgs(subgroupMap(properties, "vm")))
        .build();
  }

  public VmConfig getVmConfig(String name) throws InvalidConfigurationException {
    checkNotNull(name);
    ImmutableMap<String, String> vmGroupMap = subgroupMap(properties, "vm");
    ImmutableMap<String, String> vmMap = subgroupMap(vmGroupMap, name);
    File homeDir = getJdkHomeDir(vmGroupMap.get("baseDirectory"), vmMap.get("home"), name);
    return new VmConfig.Builder(homeDir)
        .addAllOptions(getArgs(vmGroupMap))
        .addAllOptions(getArgs(vmMap))
        .build();
  }

  private static final Pattern INSTRUMENT_CLASS_PATTERN = Pattern.compile("([^\\.]+)\\.class");

  public ImmutableSet<String> getConfiguredInstruments() {
    ImmutableSet.Builder<String> resultBuilder = ImmutableSet.builder();
    for (String key : subgroupMap(properties, "instrument").keySet()) {
      Matcher matcher = INSTRUMENT_CLASS_PATTERN.matcher(key);
      if (matcher.matches()) {
        resultBuilder.add(matcher.group(1));
      }
    }
    return resultBuilder.build();
  }

  public InstrumentConfig getInstrumentConfig(String name) {
    checkNotNull(name);
    ImmutableMap<String, String> instrumentGroupMap = subgroupMap(properties, "instrument");
    ImmutableMap<String, String> insrumentMap = subgroupMap(instrumentGroupMap, name);
    @Nullable String className = insrumentMap.get("class");
    checkArgument(className != null, "no instrument configured named %s", name);
    return new InstrumentConfig.Builder()
        .className(className)
        .addAllOptions(subgroupMap(insrumentMap, "options"))
        .build();
  }

  public ImmutableSet<Class<? extends ResultProcessor>> getConfiguredResultProcessors() {
    return resultProcessorConfigs.keySet();
  }

  public ResultProcessorConfig getResultProcessorConfig(
      Class<? extends ResultProcessor> resultProcessorClass) {
    return resultProcessorConfigs.get(resultProcessorClass);
  }

  private static ResultProcessorConfig getResultProcessorConfig(
      ImmutableMap<String, String> resultsProperties, String name) {
    ImmutableMap<String, String> resultsMap = subgroupMap(resultsProperties, name);
    return new ResultProcessorConfig.Builder()
        .className(resultsMap.get("class"))
        .addAllOptions(subgroupMap(resultsMap, "options"))
        .build();
  }

  @Override public String toString() {
    return Objects.toStringHelper(this)
        .add("properties", properties)
        .toString();
  }

  private static final ImmutableMap<String, String> subgroupMap(ImmutableMap<String, String> map,
      String groupName) {
    return Util.prefixedSubmap(map, groupName + ".");
  }

  private static List<String> getArgs(Map<String, String> properties) {
    String argsString = Strings.nullToEmpty(properties.get("args"));
    ImmutableList.Builder<String> args = ImmutableList.builder();
    StringBuilder arg = new StringBuilder();
    for (int i = 0; i < argsString.length(); i++) {
      char c = argsString.charAt(i);
      switch (c) {
        case '\\':
          arg.append(argsString.charAt(++i));
          break;
        case ' ':
          if (arg.length() > 0) {
            args.add(arg.toString());
          }
          arg = new StringBuilder();
          break;
        default:
          arg.append(c);
          break;
      }
    }
    if (arg.length() > 0) {
      args.add(arg.toString());
    }
    return args.build();
  }

  // TODO(gak): check that the directory seems to be a jdk home (with a java binary and all of that)
  // TODO(gak): make this work with different directory layouts.  I'm looking at you OS X...
  private static File getJdkHomeDir(@Nullable String baseDirectoryPath,
      @Nullable String homeDirPath, String vmConfigName)
          throws InvalidConfigurationException {
    if (homeDirPath == null) {
      File baseDirectory = getBaseDirectory(baseDirectoryPath);
      File homeDir = new File(baseDirectory, vmConfigName);
      checkConfiguration(homeDir.isDirectory(), "%s is not a directory", homeDir);
      return homeDir;
    } else {
      File potentialHomeDir = new File(homeDirPath);
      if (potentialHomeDir.isAbsolute()) {
        checkConfiguration(potentialHomeDir.isDirectory(), "%s is not a directory",
            potentialHomeDir);
        return potentialHomeDir;
      } else {
        File baseDirectory = getBaseDirectory(baseDirectoryPath);
        File homeDir = new File(baseDirectory, homeDirPath);
        checkConfiguration(homeDir.isDirectory(), "%s is not a directory", potentialHomeDir);
        return homeDir;
      }
    }
  }

  private static File getBaseDirectory(@Nullable String baseDirectoryPath)
      throws InvalidConfigurationException {
    if (baseDirectoryPath == null) {
      throw new InvalidConfigurationException(
          "must set either a home directory or a base directory");
    } else {
      File baseDirectory = new File(baseDirectoryPath);
      checkConfiguration(baseDirectory.isAbsolute(), "base directory cannot be a relative path");
      checkConfiguration(baseDirectory.isDirectory(), "base directory must be a directory");
      return baseDirectory;
    }
  }

  private static void checkConfiguration(boolean check, String message)
      throws InvalidConfigurationException {
    if (!check) {
      throw new InvalidConfigurationException(message);
    }
  }

  private static void checkConfiguration(boolean check, String messageFormat, Object... args)
      throws InvalidConfigurationException {
    if (!check) {
      throw new InvalidConfigurationException(String.format(messageFormat, args));
    }
  }
}
TOP

Related Classes of com.google.caliper.config.CaliperConfig

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.