1
18 package net.bull.javamelody.internal.model;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.Serializable;
23 import java.lang.reflect.InvocationTargetException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Properties;
28
29 import net.bull.javamelody.internal.common.LOG;
30 import net.sf.ehcache.CacheManager;
31 import net.sf.ehcache.Ehcache;
32 import net.sf.ehcache.Statistics;
33 import net.sf.ehcache.config.CacheConfiguration;
34 import net.sf.ehcache.management.CacheStatistics;
35
36
45 public class CacheInformations implements Serializable {
46 private static final long serialVersionUID = -3025833425994923286L;
47 private static final boolean EHCACHE_AVAILABLE = isEhcacheAvailable();
48 private static final boolean EHCACHE_2_7 = isEhcache27();
49 private static final boolean EHCACHE_1_6 = isEhcache16();
50 private static final boolean EHCACHE_1_2 = isEhcache12();
51 private static final boolean EHCACHE_1_2_X = isEhcache12x();
52
53 private final String name;
54 private final long inMemoryObjectCount;
55 private final int inMemoryPercentUsed;
56 private final long onDiskObjectCount;
57 private final long inMemoryHits;
58 private final long cacheHits;
59 private final long cacheMisses;
60 private final String configuration;
61 private final List<?> cacheKeys;
62
63 CacheInformations(Ehcache cache, boolean includeKeys) {
64 super();
65 assert cache != null;
66 this.name = cache.getName();
67
68 if (includeKeys) {
69 this.cacheKeys = cache.getKeys();
70 } else {
71 this.cacheKeys = null;
72 }
73
74 if (EHCACHE_2_7) {
75
76
77 final CacheStatistics statistics = new CacheStatistics(cache);
78 this.inMemoryObjectCount = statistics.getMemoryStoreObjectCount();
79 this.onDiskObjectCount = statistics.getDiskStoreObjectCount();
80 this.inMemoryHits = statistics.getInMemoryHits();
81 this.cacheHits = statistics.getCacheHits();
82 this.cacheMisses = statistics.getCacheMisses();
83
84
85 this.inMemoryPercentUsed = computeMemoryPercentUsed(cache);
86 this.configuration = buildConfiguration(cache);
87 return;
88 }
89
90 final Statistics statistics = cache.getStatistics();
91 assert statistics != null;
92 if (EHCACHE_1_6) {
93
94 this.inMemoryObjectCount = statistics.getMemoryStoreObjectCount();
95 this.onDiskObjectCount = statistics.getDiskStoreObjectCount();
96
97 assert statistics.getStatisticsAccuracy() == Statistics.STATISTICS_ACCURACY_BEST_EFFORT;
98 } else {
99 this.inMemoryObjectCount = cache.getMemoryStoreSize();
100 this.onDiskObjectCount = cache.getDiskStoreSize();
101 }
102
103
104 if (EHCACHE_1_2_X) {
105
106
107
108 this.inMemoryHits = invokeStatisticsMethod(statistics, "getInMemoryHits");
109 this.cacheHits = invokeStatisticsMethod(statistics, "getCacheHits");
110 this.cacheMisses = invokeStatisticsMethod(statistics, "getCacheMisses");
111
112 this.inMemoryPercentUsed = -1;
113 this.configuration = null;
114 } else if (EHCACHE_1_2) {
115 this.inMemoryHits = -1;
116 this.cacheHits = -1;
117 this.cacheMisses = -1;
118 this.inMemoryPercentUsed = -1;
119 this.configuration = null;
120 } else {
121 this.inMemoryHits = statistics.getInMemoryHits();
122 this.cacheHits = statistics.getCacheHits();
123 this.cacheMisses = statistics.getCacheMisses();
124 this.inMemoryPercentUsed = computeMemoryPercentUsed(cache);
125 this.configuration = buildConfiguration(cache);
126 }
127 }
128
129
130 private static long invokeStatisticsMethod(Object statistics, String methodName) {
131 try {
132
133
134
135 final Number result = (Number) Statistics.class.getMethod(methodName, (Class<?>[]) null)
136 .invoke(statistics, (Object[]) null);
137 return result.longValue();
138 } catch (final NoSuchMethodException e) {
139 throw new IllegalArgumentException(e);
140 } catch (final InvocationTargetException e) {
141 throw new IllegalStateException(e.getCause());
142 } catch (final IllegalAccessException e) {
143 throw new IllegalStateException(e);
144 }
145 }
146
147 private static boolean isEhcacheAvailable() {
148 try {
149 Class.forName("net.sf.ehcache.Cache");
150 return true;
151 } catch (final ClassNotFoundException | NoClassDefFoundError e) {
152
153 return false;
154 }
155 }
156
157 static List<CacheInformations> buildCacheInformationsList() {
158 if (!EHCACHE_AVAILABLE) {
159 return Collections.emptyList();
160 }
161 final List<CacheManager> allCacheManagers;
162 try {
163 allCacheManagers = new ArrayList<>(CacheManager.ALL_CACHE_MANAGERS);
164 } catch (final NoSuchFieldError e) {
165
166 return Collections.emptyList();
167 }
168 final List<CacheInformations> result = new ArrayList<>();
169 for (final CacheManager cacheManager : allCacheManagers) {
170 final String[] cacheNames = cacheManager.getCacheNames();
171 try {
172 for (final String cacheName : cacheNames) {
173 result.add(new CacheInformations(cacheManager.getEhcache(cacheName), false));
174 }
175 } catch (final Exception e) {
176
177
178
179 LOG.debug(e.toString(), e);
180 }
181 }
182 return result;
183 }
184
185 public static CacheInformations buildCacheInformationsWithKeys(String cacheId) {
186 assert EHCACHE_AVAILABLE;
187 assert cacheId != null;
188 final List<CacheManager> allCacheManagers = new ArrayList<>(
189 CacheManager.ALL_CACHE_MANAGERS);
190 for (final CacheManager cacheManager : allCacheManagers) {
191 final Ehcache ehcache = cacheManager.getEhcache(cacheId);
192 if (ehcache != null) {
193 return new CacheInformations(ehcache, true);
194 }
195 }
196 throw new IllegalArgumentException("Cache not found");
197 }
198
199 private static boolean isEhcache27() {
200 try {
201 final InputStream input = Class.forName("net.sf.ehcache.Ehcache")
202 .getResourceAsStream("/net/sf/ehcache/version.properties");
203 if (input != null) {
204 try {
205 try {
206 final Properties properties = new Properties();
207 properties.load(input);
208 final String version = properties.getProperty("version");
209 return "2.7".compareTo(version) <= 0 || "2.10".compareTo(version) <= 0;
210 } finally {
211 input.close();
212 }
213 } catch (final IOException e) {
214
215 }
216 }
217
218 Class.forName("net.sf.ehcache.statistics.StatisticsGateway");
219 return true;
220 } catch (final ClassNotFoundException e) {
221 return false;
222 }
223 }
224
225 private static boolean isEhcache16() {
226 try {
227
228 Class.forName("net.sf.ehcache.Statistics");
229
230 Statistics.class.getMethod("getMemoryStoreObjectCount");
231 return true;
232 } catch (final ClassNotFoundException | NoSuchMethodException e) {
233 return false;
234 }
235 }
236
237 private static boolean isEhcache12() {
238 try {
239
240 Class.forName("net.sf.ehcache.Ehcache");
241
242 Ehcache.class.getMethod("getCacheConfiguration");
243 return false;
244 } catch (final ClassNotFoundException | NoClassDefFoundError e) {
245
246 return false;
247 } catch (final NoSuchMethodException e) {
248 return true;
249 }
250 }
251
252 private static boolean isEhcache12x() {
253 try {
254
255 Class.forName("net.sf.ehcache.Statistics");
256 return isEhcache12();
257 } catch (final ClassNotFoundException e) {
258 return false;
259 }
260 }
261
262
263
264 private int computeMemoryPercentUsed(Object cache) {
265 final int maxElementsInMemory = ((Ehcache) cache).getCacheConfiguration()
266 .getMaxElementsInMemory();
267 if (maxElementsInMemory == 0) {
268
269 return -1;
270 }
271 return (int) (100 * inMemoryObjectCount / maxElementsInMemory);
272 }
273
274
275
276 private String buildConfiguration(Object cache) {
277 final StringBuilder sb = new StringBuilder();
278
279 final CacheConfiguration config = ((Ehcache) cache).getCacheConfiguration();
280 sb.append("ehcache [maxElementsInMemory = ").append(config.getMaxElementsInMemory());
281 final boolean overflowToDisk = config.isOverflowToDisk();
282 sb.append(", overflowToDisk = ").append(overflowToDisk);
283 if (overflowToDisk) {
284 sb.append(", maxElementsOnDisk = ").append(config.getMaxElementsOnDisk());
285 }
286 final boolean eternal = config.isEternal();
287 sb.append(", eternal = ").append(eternal);
288 if (!eternal) {
289 sb.append(", timeToLiveSeconds = ").append(config.getTimeToLiveSeconds());
290 sb.append(", timeToIdleSeconds = ").append(config.getTimeToIdleSeconds());
291 sb.append(", memoryStoreEvictionPolicy = ")
292 .append(config.getMemoryStoreEvictionPolicy());
293 }
294 sb.append(", diskPersistent = ").append(config.isDiskPersistent());
295 sb.append(']');
296 return sb.toString();
297 }
298
299 public String getName() {
300 return name;
301 }
302
303 public long getInMemoryObjectCount() {
304 return inMemoryObjectCount;
305 }
306
307 public long getInMemoryPercentUsed() {
308 return inMemoryPercentUsed;
309 }
310
311 public long getOnDiskObjectCount() {
312 return onDiskObjectCount;
313 }
314
315 public long getInMemoryHits() {
316 return inMemoryHits;
317 }
318
319 public long getCacheHits() {
320 return cacheHits;
321 }
322
323 public long getCacheMisses() {
324 return cacheMisses;
325 }
326
327
328 public int getInMemoryHitsRatio() {
329 if (cacheHits == 0) {
330 return -1;
331 }
332 return (int) (100 * inMemoryHits / cacheHits);
333 }
334
335
336 public int getHitsRatio() {
337 final long accessCount = cacheHits + cacheMisses;
338 if (accessCount == 0) {
339 return -1;
340 }
341 return (int) (100 * cacheHits / accessCount);
342 }
343
344 public String getConfiguration() {
345 return configuration;
346 }
347
348 public List<?> getCacheKeys() {
349 return cacheKeys;
350 }
351
352
353 @Override
354 public String toString() {
355 return getClass().getSimpleName() + "[name=" + getName() + ", inMemoryObjectCount="
356 + getInMemoryObjectCount() + ", inMemoryPercentUsed=" + getInMemoryPercentUsed()
357 + ", onDiskObjectCount=" + getOnDiskObjectCount() + ", inMemoryHitsRatio="
358 + getInMemoryHitsRatio() + ", hitsRatio=" + getHitsRatio() + ']';
359 }
360 }
361