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