1e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin/* 2e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Copyright (C) 2011 Google Inc. 3e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * 4e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 5e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * you may not use this file except in compliance with the License. 6e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * You may obtain a copy of the License at 7e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * 8e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 9e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * 10e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Unless required by applicable law or agreed to in writing, software 11e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 12e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * See the License for the specific language governing permissions and 14e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * limitations under the License. 15e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin */ 16e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 17e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinpackage com.google.caliper.util; 18e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 19e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.ImmutableBiMap; 20e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.ImmutableList; 21e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.ImmutableMap; 22e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.Maps; 23e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.io.ByteSource; 24e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.io.Closer; 25e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.io.Resources; 26e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 27e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.io.IOException; 28e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.io.InputStream; 29e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.lang.reflect.Member; 30e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.lang.reflect.Modifier; 31e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.util.Map; 32e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.util.Properties; 33e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.util.Set; 34e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.util.concurrent.CountDownLatch; 35e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.util.concurrent.TimeUnit; 36e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 37e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinpublic final class Util { 38e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin private Util() {} 39e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 40e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // Users have no idea that nested classes are identified with '$', not '.', so if class lookup 41e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // fails try replacing the last . with $. 42e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static Class<?> lenientClassForName(String className) throws ClassNotFoundException { 43e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin try { 44e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return loadClass(className); 45e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } catch (ClassNotFoundException ignored) { 46e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // try replacing the last dot with a $, in case that helps 47e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // example: tutorial.Tutorial.Benchmark1 becomes tutorial.Tutorial$Benchmark1 48e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // amusingly, the $ character means three different things in this one line alone 49e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin String newName = className.replaceFirst("\\.([^.]+)$", "\\$$1"); 50e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return loadClass(newName); 51e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 52e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 53e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 54e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin /** 55e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Search for a class by name. 56e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * 57e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * @param className the name of the class. 58e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * @return the class. 59e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * @throws ClassNotFoundException if the class could not be found. 60e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin */ 61e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static Class<?> loadClass(String className) throws ClassNotFoundException { 62e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // Use the thread context class loader. This is necessary because in some configurations, e.g. 63e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // when run from a single JAR containing caliper and all its dependencies the caliper JAR 64e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // ends up on the boot class path of the Worker and so needs to the use thread context class 65e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin // loader to load classes provided by the user. 66e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return Class.forName(className, true, Thread.currentThread().getContextClassLoader()); 67e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 68e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 69e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static ImmutableMap<String, String> loadProperties(ByteSource is) throws IOException { 70e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin Properties props = new Properties(); 71e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin Closer closer = Closer.create(); 72e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin InputStream in = closer.register(is.openStream()); 73e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin try { 74e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin props.load(in); 75e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } finally { 76e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin closer.close(); 77e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 78e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return Maps.fromProperties(props); 79e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 80e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 81e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static ByteSource resourceSupplier(final Class<?> c, final String name) { 82e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return Resources.asByteSource(c.getResource(name)); 83e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 84e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 85e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin private static <T> ImmutableMap<String, T> prefixedSubmap( 86e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin Map<String, T> props, String prefix) { 87e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin ImmutableMap.Builder<String, T> submapBuilder = ImmutableMap.builder(); 88e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin for (Map.Entry<String, T> entry : props.entrySet()) { 89e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin String name = entry.getKey(); 90e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin if (name.startsWith(prefix)) { 91e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin submapBuilder.put(name.substring(prefix.length()), entry.getValue()); 92e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 93e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 94e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return submapBuilder.build(); 95e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 96e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 97e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin /** 98e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Returns a map containing only those entries whose key starts with {@code <groupName>.}. 99e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * 100e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * <p>The keys in the returned map have had their {@code <groupName>.} prefix removed. 101e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * 102e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * <p>e.g. If given a map that contained {@code group.key1 -> value1, key2 -> value2} and a 103e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * {@code groupName} of {@code group} it would produce a map containing {@code key1 -> value1}. 104e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin */ 105e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static ImmutableMap<String, String> subgroupMap( 106e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin Map<String, String> map, String groupName) { 107e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return prefixedSubmap(map, groupName + "."); 108e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 109e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 110e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static boolean isPublic(Member member) { 111e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return Modifier.isPublic(member.getModifiers()); 112e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 113e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 114e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static boolean isStatic(Member member) { 115e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return Modifier.isStatic(member.getModifiers()); 116e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 117e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 118e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin private static final long FORCE_GC_TIMEOUT_SECS = 2; 119e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 120e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static void forceGc() { 121e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin System.gc(); 122e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin System.runFinalization(); 123e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin final CountDownLatch latch = new CountDownLatch(1); 124e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin new Object() { 125e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin @Override protected void finalize() { 126e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin latch.countDown(); 127e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 128e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin }; 129e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin System.gc(); 130e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin System.runFinalization(); 131e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin try { 132e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin latch.await(FORCE_GC_TIMEOUT_SECS, TimeUnit.SECONDS); 133e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } catch (InterruptedException e) { 134e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin Thread.currentThread().interrupt(); 135e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 136e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 137e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 138e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin public static <T> ImmutableBiMap<T, String> assignNames(Set<T> items) { 139e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin ImmutableList<T> itemList = ImmutableList.copyOf(items); 140e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin ImmutableBiMap.Builder<T, String> itemNamesBuilder = ImmutableBiMap.builder(); 141e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin for (int i = 0; i < itemList.size(); i++) { 142e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin itemNamesBuilder.put(itemList.get(i), generateUniqueName(i)); 143e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 144e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return itemNamesBuilder.build(); 145e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 146e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin 147e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin private static String generateUniqueName(int index) { 148e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin if (index < 26) { 149e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return String.valueOf((char) ('A' + index)); 150e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } else { 151e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin return generateUniqueName(index / 26 - 1) + generateUniqueName(index % 26); 152e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 153e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin } 154e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin} 155