1 package org.unicode.cldr.util; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.ExecutionException; 5 import java.util.regex.Pattern; 6 7 import com.google.common.cache.Cache; 8 import com.google.common.cache.CacheBuilder; 9 import com.google.common.cache.CacheStats; 10 11 /** 12 * Simple class for caching Patterns, possibly avoiding the cost of 13 * compilation if they are in the cache. 14 * 15 * 16 * @author ribnitz 17 * 18 */ 19 public class PatternCache { 20 private final static int INITIAL_CAPACITY = 30; 21 private final static int MAX_CAPACITY = 1000; 22 23 /** 24 * Variable to control whether patterns are cached (true); 25 * or whether they are created all the time */ 26 private final static boolean USE_CACHE = true; 27 28 /** 29 * Variable that controls whether statistics are recorded for the caching. 30 */ 31 private final static boolean RECORD_STATISTICS = false; 32 33 /** 34 * The cache object 35 */ 36 private final static Cache<String, Pattern> cache; 37 38 /* 39 * A static initialization block is used to be able to cleanly handle the three different cases: 40 * 41 * 1) no caching 42 * 2) caching without statistics collection 43 * 3) caching with statistics collection 44 */ 45 static { 46 if (USE_CACHE) { 47 if (RECORD_STATISTICS) { 48 cache = CacheBuilder.newBuilder().initialCapacity(INITIAL_CAPACITY).maximumSize(MAX_CAPACITY).recordStats().build(); 49 } else { 50 cache = CacheBuilder.newBuilder().initialCapacity(INITIAL_CAPACITY).maximumSize(MAX_CAPACITY).build(); 51 } 52 } else { 53 cache = null; 54 } 55 } 56 57 /** 58 * Obtain a compiled Pattern from the String given; results of the lookup are cached, a cached result will be returned if 59 * possible. 60 * @param patternStr the string to use for compilation 61 * @throws IllegalArgumentException The string provided was null or empty, or there was a problem compiling the Pattern from the String 62 */ get(final String patternStr)63 public static Pattern get(final String patternStr) { 64 // Pre-conditions: non-null, non-empty string 65 if (patternStr == null) { 66 throw new IllegalArgumentException("Please call with non-null argument"); 67 } 68 if (patternStr.isEmpty()) { 69 throw new IllegalArgumentException("Please call with non-empty argument"); 70 } 71 // If patterns are not cached, simply return a new compiled Pattern 72 if (!USE_CACHE) { 73 return Pattern.compile(patternStr); 74 } 75 Pattern result = null; 76 try { 77 result = cache.get(patternStr, new Callable<Pattern>() { 78 79 @Override 80 public Pattern call() throws Exception { 81 return Pattern.compile(patternStr); 82 } 83 }); 84 } catch (ExecutionException e) { 85 // realistically, this is a PatternSyntaxException 86 throw new IllegalArgumentException("The supplied pattern is not valid: " + patternStr, e); 87 } 88 return result; 89 } 90 91 /** 92 * Return true if the collection of statistics is enabled 93 * @return 94 */ isRecordStatistics()95 public static boolean isRecordStatistics() { 96 return RECORD_STATISTICS; 97 } 98 99 /** 100 * Return true if caching is enabled; in the case it isn't this class acts like a Factory 101 * for compiled Patterns 102 * 103 * @return 104 */ isCachingEnabled()105 public static boolean isCachingEnabled() { 106 return USE_CACHE; 107 } 108 109 /** 110 * Get Statistics for the Caching operation 111 * @return 112 */ getStatistics()113 public static CacheStats getStatistics() { 114 return cache.stats(); 115 } 116 117 }