/* * Copyright (C) 2011 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.util; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.io.ByteSource; import com.google.common.io.Closer; import com.google.common.io.Resources; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public final class Util { private Util() {} // Users have no idea that nested classes are identified with '$', not '.', so if class lookup // fails try replacing the last . with $. public static Class lenientClassForName(String className) throws ClassNotFoundException { try { return loadClass(className); } catch (ClassNotFoundException ignored) { // try replacing the last dot with a $, in case that helps // example: tutorial.Tutorial.Benchmark1 becomes tutorial.Tutorial$Benchmark1 // amusingly, the $ character means three different things in this one line alone String newName = className.replaceFirst("\\.([^.]+)$", "\\$$1"); return loadClass(newName); } } /** * Search for a class by name. * * @param className the name of the class. * @return the class. * @throws ClassNotFoundException if the class could not be found. */ public static Class loadClass(String className) throws ClassNotFoundException { // Use the thread context class loader. This is necessary because in some configurations, e.g. // when run from a single JAR containing caliper and all its dependencies the caliper JAR // ends up on the boot class path of the Worker and so needs to the use thread context class // loader to load classes provided by the user. return Class.forName(className, true, Thread.currentThread().getContextClassLoader()); } public static ImmutableMap loadProperties(ByteSource is) throws IOException { Properties props = new Properties(); Closer closer = Closer.create(); InputStream in = closer.register(is.openStream()); try { props.load(in); } finally { closer.close(); } return Maps.fromProperties(props); } public static ByteSource resourceSupplier(final Class c, final String name) { return Resources.asByteSource(c.getResource(name)); } private static ImmutableMap prefixedSubmap( Map props, String prefix) { ImmutableMap.Builder submapBuilder = ImmutableMap.builder(); for (Map.Entry entry : props.entrySet()) { String name = entry.getKey(); if (name.startsWith(prefix)) { submapBuilder.put(name.substring(prefix.length()), entry.getValue()); } } return submapBuilder.build(); } /** * Returns a map containing only those entries whose key starts with {@code .}. * *

The keys in the returned map have had their {@code .} prefix removed. * *

e.g. If given a map that contained {@code group.key1 -> value1, key2 -> value2} and a * {@code groupName} of {@code group} it would produce a map containing {@code key1 -> value1}. */ public static ImmutableMap subgroupMap( Map map, String groupName) { return prefixedSubmap(map, groupName + "."); } public static boolean isPublic(Member member) { return Modifier.isPublic(member.getModifiers()); } public static boolean isStatic(Member member) { return Modifier.isStatic(member.getModifiers()); } private static final long FORCE_GC_TIMEOUT_SECS = 2; public static void forceGc() { System.gc(); System.runFinalization(); final CountDownLatch latch = new CountDownLatch(1); new Object() { @Override protected void finalize() { latch.countDown(); } }; System.gc(); System.runFinalization(); try { latch.await(FORCE_GC_TIMEOUT_SECS, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public static ImmutableBiMap assignNames(Set items) { ImmutableList itemList = ImmutableList.copyOf(items); ImmutableBiMap.Builder itemNamesBuilder = ImmutableBiMap.builder(); for (int i = 0; i < itemList.size(); i++) { itemNamesBuilder.put(itemList.get(i), generateUniqueName(i)); } return itemNamesBuilder.build(); } private static String generateUniqueName(int index) { if (index < 26) { return String.valueOf((char) ('A' + index)); } else { return generateUniqueName(index / 26 - 1) + generateUniqueName(index % 26); } } }