001package org.javasimon.callback.quantiles; 002 003import org.javasimon.Simon; 004import org.javasimon.Stopwatch; 005 006import java.util.Properties; 007 008/** 009 * Callback which stores data in buckets to compute quantiles. 010 * Buckets are created from configuration stored in a {@link java.util.Properties} 011 * file. Configuration file should look like: 012 * <pre> 013 * # Global default values are set on root 014 * .min=0 015 * .max=60000 016 * .nb=5 017 * .type=LINEAR 018 * 019 * # For org.javasimon group: more buckets 020 * org.javasimon.nb=10 021 * 022 * # SlowClass is a performance bottleneck: higher upper bound 023 * org.javasimon.slow.SlowClass.max=300000 024 * 025 * # Can use Exponential buckets for some Stopwatches 026 * org.javasimon.special.type=EXPONENTIAL 027 * </pre> 028 * 029 * @author gquintana 030 */ 031public class PropertiesQuantilesCallback extends QuantilesCallback { 032 033 /** Properties containing configuration. */ 034 private final Properties properties; 035 036 /** 037 * Main constructor. 038 * 039 * @param properties Properties containing configuration 040 */ 041 public PropertiesQuantilesCallback(Properties properties) { 042 this.properties = properties; 043 } 044 045 /** 046 * Create buckets using callback attributes. 047 * 048 * @param stopwatch Target stopwatch 049 * @return Created buckets for given stopwatch 050 */ 051 @Override 052 protected Buckets createBuckets(Stopwatch stopwatch) { 053 // Get configuration 054 BucketsType type = bucketsTypeEnumPropertyType.get(stopwatch, "type"); 055 Long min = longPropertyType.get(stopwatch, "min"); 056 Long max = longPropertyType.get(stopwatch, "max"); 057 Integer nb = integerPropertyType.get(stopwatch, "nb"); 058 // Build buckets 059 Buckets buckets = type.createBuckets(stopwatch, min, max, nb); 060 buckets.setLogTemplate(createLogTemplate(stopwatch)); 061 return buckets; 062 } 063 064 /** 065 * Returns value of Simon property. 066 * 067 * @param simon Simon 068 * @param name Property name 069 * @return Raw property value 070 */ 071 private String getProperty(Simon simon, String name) { 072 return properties.getProperty(simon.getName() + "." + name); 073 } 074 075 /** Remove space at both ends and convert empty strings to null. */ 076 private static String cleanString(String s) { 077 if (s != null) { 078 s = s.trim(); 079 if (s.equals("")) { 080 s = null; 081 } 082 } 083 return s; 084 } 085 086 /** Base class for property types. */ 087 private abstract class PropertyType<T> { 088 public abstract T parse(String value); 089 090 public T get(Simon simon, String name) { 091 Simon currentSimon = simon; 092 T result = null; 093 while (result == null && currentSimon != null) { 094 String s = getProperty(currentSimon, name); 095 s = cleanString(s); 096 if (s != null) { 097 result = parse(s); 098 } 099 currentSimon = currentSimon.getParent(); 100 } 101 return result; 102 } 103 } 104 105 /** Returns long property for Simon. */ 106 private final PropertyType<Long> longPropertyType = new PropertyType<Long>() { 107 @Override 108 public Long parse(String s) { 109 Long l; 110 try { 111 l = Long.valueOf(s); 112 } catch (NumberFormatException numberFormatException) { 113 l = null; 114 } 115 return l; 116 } 117 }; 118 119 /** Returns integer property for Simon. */ 120 private final PropertyType<Integer> integerPropertyType = new PropertyType<Integer>() { 121 @Override 122 public Integer parse(String s) { 123 Integer l; 124 try { 125 l = Integer.valueOf(s); 126 } catch (NumberFormatException numberFormatException) { 127 l = null; 128 } 129 return l; 130 } 131 }; 132 133 /** Returns enum property for Simon. */ 134 private class EnumPropertyType<E extends Enum<E>> extends PropertyType<E> { 135 private final Class<E> enumClass; 136 137 private EnumPropertyType(Class<E> enumClass) { 138 this.enumClass = enumClass; 139 } 140 141 @Override 142 public E parse(String s) { 143 E e; 144 try { 145 e = Enum.valueOf(enumClass, s.toUpperCase()); 146 } catch (IllegalArgumentException exc) { 147 e = null; 148 } 149 return e; 150 } 151 } 152 153 /** Returns bucket type property for Simon. */ 154 private final EnumPropertyType<BucketsType> bucketsTypeEnumPropertyType = new EnumPropertyType<BucketsType>(BucketsType.class) { 155 @Override 156 public BucketsType get(Simon simon, String name) { 157 BucketsType type = super.get(simon, name); 158 if (type == null) { 159 type = BucketsType.LINEAR; 160 } 161 return type; 162 } 163 }; 164}