1   package com.trendmicro.grid.acl.ds.cache.aspects;
2   
3   import com.trendmicro.grid.acl.ds.cache.CacheSettings;
4   import com.trendmicro.grid.acl.ds.cache.ThirdLevelCacheStatisticsSummary;
5   import com.trendmicro.grid.acl.l0.datatypes.Tagged;
6   import net.sf.tinyjee.cache.config.CacheRegion;
7   import net.sf.tinyjee.cache.config.CacheRegions;
8   
9   import javax.annotation.Resource;
10  import java.util.ArrayList;
11  import java.util.Collection;
12  import java.util.Map;
13  import java.util.concurrent.Callable;
14  
15  import static com.trendmicro.grid.acl.ds.cache.CacheDestination.Mode;
16  import static java.util.concurrent.TimeUnit.HOURS;
17  import static java.util.concurrent.TimeUnit.MINUTES;
18  import static net.sf.tinyjee.cache.config.DistributionPolicy.DISTRIBUTE_VALUES;
19  import static net.sf.tinyjee.cache.config.DistributionPolicy.REPLICATE_VALUES;
20  import static net.sf.tinyjee.cache.config.EvictionPolicy.LIRS;
21  import static net.sf.tinyjee.cache.config.PersistentMode.TEMPORARY;
22  
23  /**
24   * Is the base to all aspects that deal with caching and defines all cache regions at a central location.
25   *
26   * @author Juergen_Kellerer, 2011-02-19
27   * @version 1.0
28   */
29  @CacheRegions({
30  		// START-SNIPPET: 3rdLevelCacheRegions
31  		@CacheRegion(name = CacheSettings.CACHE_REGION_FILE_DETAILS,
32  				// Using 4% of heap to cache file details (assuming an entry weights 2kb).
33  				// At least 250 entries are kept in memory.
34  				maxElementsInMemoryExpression = "${max(250, memoryPercent(5) / kb(2))}",
35  				persistentMode = TEMPORARY,
36  				evictionPolicy = LIRS,
37  				distributionPolicy = DISTRIBUTE_VALUES,
38  				// Clean entries if not accessed for 6 hours
39  				idleTime = 6, idleTimeUnit = HOURS,
40  				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
41  				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 6000}", defaultExpirationTimeUnit = MINUTES),
42  
43  		@CacheRegion(name = CacheSettings.CACHE_REGION_FILE_INFORMATION,
44  				// Using 15% of heap to cache file information (assuming an entry weights 256b).
45  				// At least 250 entries are kept in memory.
46  				maxElementsInMemoryExpression = "${max(250, memoryPercent(15) / 256)}",
47  				persistentMode = TEMPORARY,
48  				evictionPolicy = LIRS,
49  				distributionPolicy = DISTRIBUTE_VALUES,
50  				// Clean entries if not accessed for 6 hours
51  				idleTime = 6, idleTimeUnit = HOURS,
52  				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
53  				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 6000}", defaultExpirationTimeUnit = MINUTES),
54  
55  		@CacheRegion(name = CacheSettings.CACHE_REGION_PACKAGE_DETAILS,
56  				// Using 2% of heap to cache package details (assuming an entry weights 4kb).
57  				// At least 250 entries are kept in memory.
58  				maxElementsInMemoryExpression = "${max(250, memoryPercent(3) / kb(4))}",
59  				persistentMode = TEMPORARY,
60  				evictionPolicy = LIRS,
61  				distributionPolicy = DISTRIBUTE_VALUES,
62  				// Clean entries if not accessed for 6 hours
63  				idleTime = 6, idleTimeUnit = HOURS,
64  				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
65  				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 6000}", defaultExpirationTimeUnit = MINUTES),
66  
67  		@CacheRegion(name = CacheSettings.CACHE_REGION_PACKAGE_INFORMATION,
68  				// Using 4% of heap to cache package information (assuming an entry weights 512b).
69  				// At least 250 entries are kept in memory.
70  				maxElementsInMemoryExpression = "${max(250, memoryPercent(5) / 512)}",
71  				persistentMode = TEMPORARY,
72  				evictionPolicy = LIRS,
73  				distributionPolicy = DISTRIBUTE_VALUES,
74  				// Clean entries if not accessed for 6 hours
75  				idleTime = 6, idleTimeUnit = HOURS,
76  				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
77  				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 6000}", defaultExpirationTimeUnit = MINUTES),
78  
79  		@CacheRegion(name = CacheSettings.CACHE_REGION_PACKAGE_FILE_IDENTIFIERS,
80  				// Using 2% of heap to cache package name to id mapping (assuming an entry weights 128b).
81  				// At least 250 entries are kept in memory.
82  				maxElementsInMemoryExpression = "${max(250, memoryPercent(2) / 128)}",
83  				persistentMode = TEMPORARY,
84  				evictionPolicy = LIRS,
85  				distributionPolicy = REPLICATE_VALUES,
86  				// Clean entries if not accessed for 6 hours
87  				idleTime = 6, idleTimeUnit = HOURS,
88  				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
89  				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 6000}", defaultExpirationTimeUnit = MINUTES),
90  
91  		@CacheRegion(name = CacheSettings.CACHE_REGION_UNKNOWN_FILE_IDENTIFIERS,
92  				// Using 0.5% of heap to cache unknown identifiers (assuming an entry weights 64b).
93  				// At least 512 entries are kept in memory.
94  				maxElementsInMemoryExpression = "${max(512, memoryPercent(0.5) / 64)}",
95  				persistentMode = TEMPORARY,
96  				evictionPolicy = LIRS,
97  				distributionPolicy = REPLICATE_VALUES,
98  				// Clean entries if not accessed for 6 hours
99  				idleTime = 6, idleTimeUnit = HOURS,
100 				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
101 				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 120}", defaultExpirationTimeUnit = MINUTES),
102 
103 		@CacheRegion(name = CacheSettings.CACHE_REGION_UNKNOWN_NAMES,
104 				// Using 0.5% of heap to cache unknown names (assuming an entry weights 64b).
105 				// At least 512 entries are kept in memory.
106 				maxElementsInMemoryExpression = "${max(512, memoryPercent(0.5) / 64)}",
107 				persistentMode = TEMPORARY,
108 				evictionPolicy = LIRS,
109 				distributionPolicy = REPLICATE_VALUES,
110 				// Clean entries if not accessed for 6 hours
111 				idleTime = 6, idleTimeUnit = HOURS,
112 				// Expire entries after 15 minutes if we're not running clustered or in 'readonly' mode.
113 				defaultExpirationTimeExpression = "${not runClustered || readonly ? 15 : 120}", defaultExpirationTimeUnit = MINUTES)
114 		// END-SNIPPET: 3rdLevelCacheRegions
115 })
116 public abstract class AbstractCacheAspect {
117 
118 	public static <V> Callable<Collection<V>> chainOf(final Callable<V>... callables) {
119 		return new Callable<Collection<V>>() {
120 			@Override
121 			public Collection<V> call() throws Exception {
122 				final Collection<V> results = new ArrayList<V>(callables.length);
123 				for (Callable<V> callable : callables) results.add(callable.call());
124 
125 				return results;
126 			}
127 		};
128 	}
129 
130 	public static <V> Callable<V> ofFirst(final Callable<V> first, final Callable... runAfters) {
131 		return new Callable<V>() {
132 			@Override
133 			public V call() throws Exception {
134 				try {
135 					return first.call();
136 				} finally {
137 					for (Callable runAfter : runAfters) runAfter.call();
138 				}
139 			}
140 		};
141 	}
142 
143 	public static <K, V> Collection<V> call(Callable<Map<K, V>> callable) throws Exception {
144 		return callable.call().values();
145 	}
146 
147 	/**
148 	 * Returns true if the element is tagged with the given tags.
149 	 *
150 	 * @param element the element to check.
151 	 * @param tags    the tags to verify.
152 	 * @return true if the element contains all the tags, false if not, 'null' if the element was 'null'.
153 	 */
154 	protected static Boolean isTaggedWith(Tagged element, String[] tags) {
155 		if (element == null)
156 			return null;
157 		else {
158 			for (String tag : tags) {
159 				boolean invert = tag.startsWith("-");
160 				boolean containsTag = element.containsTag(invert ? tag.substring(1) : tag);
161 				if (invert ? containsTag : !containsTag) return false;
162 			}
163 			return true;
164 		}
165 	}
166 
167 	@Resource
168 	private ThirdLevelCacheStatisticsSummary cacheStatistics;
169 
170 	final boolean sync = CacheSettings.IS_SYNCHRONOUS;
171 
172 	final Mode cacheWriteMode = Mode.Put; // Mode.putIfAbsent - would be enough but is not stable in unit tests.
173 
174 	public ThirdLevelCacheStatisticsSummary getCacheStatistics() {
175 		return cacheStatistics;
176 	}
177 
178 	public boolean isSync() {
179 		return sync;
180 	}
181 
182 	public Mode getCacheWriteMode() {
183 		return cacheWriteMode;
184 	}
185 }