1 package com.trendmicro.grid.acl.ds.cache.aspects;
2
3 import com.trendmicro.grid.acl.ds.cache.CacheAdapter;
4 import com.trendmicro.grid.acl.ds.cache.CacheDestination;
5 import com.trendmicro.grid.acl.ds.cache.CacheSource;
6 import com.trendmicro.grid.acl.ds.cache.commands.GetFromCacheCommand;
7 import com.trendmicro.grid.acl.ds.cache.commands.GetFromPJPSourceCommand;
8 import com.trendmicro.grid.acl.ds.cache.commands.RemoveCommand;
9 import com.trendmicro.grid.acl.ds.cache.translation.IdentifierToNameTranslator;
10 import com.trendmicro.grid.acl.ds.cache.translation.PackageDetailsToFileIdentifierTranslator;
11 import com.trendmicro.grid.acl.ds.cache.translation.PackageDetailsToInformationTranslator;
12 import com.trendmicro.grid.acl.ds.datatypes.SharedPackageDetails;
13 import com.trendmicro.grid.acl.ds.datatypes.SharedPackageInformation;
14 import com.trendmicro.grid.acl.l0.datatypes.*;
15 import net.sf.tinyjee.cache.config.CacheRegion;
16 import org.aspectj.lang.ProceedingJoinPoint;
17 import org.aspectj.lang.annotation.AfterReturning;
18 import org.aspectj.lang.annotation.Around;
19 import org.aspectj.lang.annotation.Aspect;
20 import org.infinispan.Cache;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 import org.springframework.stereotype.Service;
24
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.atomic.AtomicLong;
30
31 import static com.trendmicro.grid.acl.ds.cache.CacheSettings.*;
32
33
34
35
36
37
38
39
40 @Aspect
41 @Service
42 public class PackageDetailsCacheAspect extends AbstractCacheAspect {
43
44 private static final Logger log = LoggerFactory.getLogger(PackageDetailsCacheAspect.class);
45
46 @CacheRegion(name = CACHE_REGION_PACKAGE_DETAILS)
47 Cache<String, SharedPackageDetails> cachedPackageDetails;
48 @CacheRegion(name = CACHE_REGION_PACKAGE_INFORMATION)
49 Cache<String, SharedPackageInformation> cachedPackageInformation;
50 @CacheRegion(name = CACHE_REGION_PACKAGE_FILE_IDENTIFIERS)
51 Cache<FileIdentifier, String> identifiersToNames;
52
53 @CacheRegion(name = CACHE_REGION_UNKNOWN_FILE_IDENTIFIERS)
54 Cache<FileIdentifier, Boolean> unknownFileIdentifiersCache;
55 @CacheRegion(name = CACHE_REGION_UNKNOWN_NAMES)
56 Cache<String, Boolean> unknownNamesCache;
57
58 private CacheAdapter<String, SharedPackageDetails> detailsAdapter;
59 private CacheSource<FileIdentifier, SharedPackageDetails> detailsByIdSource;
60 private CacheDestination<FileIdentifier, SharedPackageDetails> detailsByIdDestination;
61
62 private CacheSource<String, FileIdentifier> identifierFromDetails;
63 private CacheSource<String, SharedPackageInformation> informationFromDetails;
64 private CacheSource<FileIdentifier, SharedPackageInformation> informationFromDetailsById;
65
66 private CacheAdapter<String, SharedPackageInformation> informationAdapter;
67 private CacheSource<FileIdentifier, SharedPackageInformation> informationByIdSource;
68 private CacheDestination<FileIdentifier, SharedPackageInformation> informationByIdDestination;
69
70 private CacheAdapter<FileIdentifier, Boolean> unknownFileIdentifiers;
71 private CacheAdapter<String, Boolean> unknownNames;
72
73
74
75
76
77
78
79
80
81
82
83 @Around(value = "execution(* com.trendmicro.grid.acl.ds.PackageProvider.getPackageInformationListByName(..)) && " +
84 "args(packageNames) && @annotation(com.trendmicro.grid.acl.ds.RemoteCacheable)",
85 argNames = "pjp, packageNames")
86 public Collection<SharedPackageInformation> getPackageInformationListByName(
87 final ProceedingJoinPoint pjp, final Collection<String> packageNames) throws Exception {
88
89 return call(new GetFromCacheCommand<String, SharedPackageInformation>(packageNames, informationAdapter, informationFromDetails) {
90 @Override
91 protected Callable<Map<String, SharedPackageInformation>>
92 createGetFromSourceCommand(Collection<String> keys) {
93 return new GetFromPJPSourceCommand<String, SharedPackageInformation>(getCacheStatistics().getFetchedKeyCount(), keys, pjp);
94 }
95 }.useDestination(informationAdapter, cacheWriteMode).useUnknownKeysLookup(unknownNames, cacheWriteMode));
96 }
97
98
99
100
101
102
103
104
105
106
107
108 @Around(value = "execution(* com.trendmicro.grid.acl.ds.PackageProvider.getPackageInformationListById(..)) && " +
109 "args(files) && @annotation(com.trendmicro.grid.acl.ds.RemoteCacheable)",
110 argNames = "pjp, files")
111 public Collection<SharedPackageInformation> getPackageInformationListById(
112 final ProceedingJoinPoint pjp, final Collection<FileIdentifier> files) throws Exception {
113
114 return call(new GetFromCacheCommand<FileIdentifier, SharedPackageInformation>(files, informationByIdSource, informationFromDetailsById) {
115 @Override
116 protected Callable<Map<FileIdentifier, SharedPackageInformation>>
117 createGetFromSourceCommand(Collection<FileIdentifier> keys) {
118 return new GetFromPJPSourceCommand<FileIdentifier, SharedPackageInformation>(getCacheStatistics().getFetchedKeyCount(), keys, pjp);
119 }
120 }.useDestination(informationByIdDestination, cacheWriteMode).useUnknownKeysLookup(unknownFileIdentifiers, cacheWriteMode));
121 }
122
123
124
125
126
127
128
129
130
131
132 @Around(value = "execution(* com.trendmicro.grid.acl.ds.PackageProvider.getPackageDetailsListByName(..)) && " +
133 "args(packageNames) && @annotation(com.trendmicro.grid.acl.ds.RemoteCacheable)",
134 argNames = "pjp, packageNames")
135 public Collection<SharedPackageDetails> getPackageDetailsListByName(
136 final ProceedingJoinPoint pjp, final Collection<String> packageNames) throws Exception {
137
138 return call(new GetFromCacheCommand<String, SharedPackageDetails>(packageNames, detailsAdapter) {
139 @Override
140 protected Callable<Map<String, SharedPackageDetails>>
141 createGetFromSourceCommand(Collection<String> keys) {
142 return new GetFromSourceAndMapIdsCommand(getCacheStatistics().getFetchedKeyCount(), keys, pjp);
143 }
144 }.useDestination(detailsAdapter, cacheWriteMode).useUnknownKeysLookup(unknownNames, cacheWriteMode));
145 }
146
147
148
149
150
151
152
153
154
155
156 @Around(value = "execution(* com.trendmicro.grid.acl.ds.PackageProvider.getPackageDetailsListById(..)) && " +
157 "args(files) && @annotation(com.trendmicro.grid.acl.ds.RemoteCacheable)",
158 argNames = "pjp, files")
159 public Collection<SharedPackageDetails> getPackageDetailsListById(
160 final ProceedingJoinPoint pjp, final Collection<FileIdentifier> files) throws Exception {
161
162 return call(new GetFromCacheCommand<FileIdentifier, SharedPackageDetails>(files, detailsByIdSource) {
163 @Override
164 protected Callable<Map<FileIdentifier, SharedPackageDetails>>
165 createGetFromSourceCommand(Collection<FileIdentifier> keys) {
166 return new GetFromPJPSourceCommand<FileIdentifier, SharedPackageDetails>(getCacheStatistics().getFetchedKeyCount(), keys, pjp);
167 }
168 }.useDestination(detailsByIdDestination, cacheWriteMode).useUnknownKeysLookup(unknownFileIdentifiers, cacheWriteMode));
169 }
170
171
172
173
174
175
176
177
178
179
180 @Around(value = "execution(* com.trendmicro.grid.acl.ds.PackageProvider.getPackageFileIdentifiersByName(..)) && " +
181 "args(packageNames) && @annotation(com.trendmicro.grid.acl.ds.RemoteCacheable)",
182 argNames = "pjp, packageNames")
183 public Collection<FileIdentifier> getPackageFileIdentifiersByName(
184 final ProceedingJoinPoint pjp, final Collection<String> packageNames) throws Exception {
185
186 return call(new GetFromCacheCommand<String, FileIdentifier>(packageNames, identifierFromDetails) {
187 @Override
188 protected Callable<Map<String, FileIdentifier>> createGetFromSourceCommand(Collection<String> keys) {
189 return new GetFromPJPSourceCommand<String, FileIdentifier>(getCacheStatistics().getFetchedKeyCount(), keys, pjp);
190 }
191 }.useUnknownKeysLookup(unknownNames, cacheWriteMode));
192 }
193
194
195
196
197
198
199
200 @AfterReturning(value = "execution(* com.trendmicro.grid.acl.ds.ProcessingResultReceiver.receive(..)) && " +
201 "args(dataSets)", argNames = "dataSets")
202 public void invalidateCachesAfterReceivingUpdates(final Collection<ProcessPackageDataSet> dataSets) throws Exception {
203
204 final HashMap<String, FileIdentifier> contentToRemove = new HashMap<String, FileIdentifier>(dataSets.size());
205 for (ProcessPackageDataSet dataSet : dataSets) {
206 PackageDetails processedPackage = dataSet.getProcessedPackage();
207 if (processedPackage != null) {
208 PackageInformation information = processedPackage.getPackageInformation();
209 FileMetadata fm = processedPackage.getFileMetadata();
210
211 if (information != null && fm != null) {
212 contentToRemove.put(information.getName(), fm.getIdentifier());
213 removeNameMapping(information.getName(), fm.getIdentifier());
214
215 if (log.isTraceEnabled()) log.trace("Invalidated cached entries for package '{}'", information.getName());
216 }
217 }
218 }
219
220
221 call(new RemoveCommand<String, Object>(contentToRemove.keySet(), unknownNames, detailsAdapter, informationAdapter) {
222 @Override
223 protected void removeKeys() {
224 for (Map.Entry<String, FileIdentifier> entry : contentToRemove.entrySet())
225 removeNameMapping(entry.getKey(), entry.getValue());
226 super.removeKeys();
227 }
228 }.asBatchCommand());
229 }
230
231 private void removeNameMapping(String name, FileIdentifier newIdentifier) {
232 final SharedPackageDetails details = cachedPackageDetails.get(name);
233 final boolean hasFileMetadata = details != null && details.getFileMetadata() != null;
234 final FileIdentifier oldIdentifier = hasFileMetadata ? details.getFileMetadata().getIdentifier() : null;
235
236 if (oldIdentifier != null && !oldIdentifier.equals(newIdentifier)) {
237 for (FileIdentifier identifier : oldIdentifier.getVariants()) {
238 identifiersToNames.remove(identifier);
239 }
240
241 } else if (identifiersToNames.containsKey(newIdentifier) && !name.equals(identifiersToNames.get(newIdentifier))) {
242 log.warn("TMACL-01610:Failed to invalidate the old file identifier to package name mapping inside the " +
243 "3rd level cache for package '{}'. The existing identifier could not be resolved and " +
244 "the file content of the package changed. In the worst case, public queries return the same " +
245 "content for the new and old file-id until the old file-id gets updated as well or is " +
246 "auto-invalidated when it reaches its idle timeout.", name);
247 }
248 }
249
250
251 public void setIdentifiersToNames(Cache<FileIdentifier, String> identifiersToNames) {
252 this.identifiersToNames = identifiersToNames;
253 updateDependentAdapters(identifiersToNames);
254 }
255
256 public void setCachedPackageInformation(Cache<String, SharedPackageInformation> cachedPackageInformation) {
257 this.cachedPackageInformation = cachedPackageInformation;
258 informationAdapter = new CacheAdapter<String, SharedPackageInformation>(cachedPackageInformation, sync);
259 updateDependentAdapters(identifiersToNames);
260 }
261
262 public void setCachedPackageDetails(Cache<String, SharedPackageDetails> cachedPackageDetails) {
263 this.cachedPackageDetails = cachedPackageDetails;
264 detailsAdapter = new CacheAdapter<String, SharedPackageDetails>(cachedPackageDetails, sync);
265 informationFromDetails = new PackageDetailsToInformationTranslator<String>().newSource(detailsAdapter);
266 updateDependentAdapters(identifiersToNames);
267 }
268
269 private void updateDependentAdapters(Cache<FileIdentifier, String> identifiersToNames) {
270 if (detailsAdapter != null && informationAdapter != null && identifiersToNames != null) {
271 final IdentifierToNameTranslator<SharedPackageDetails> translator =
272 new IdentifierToNameTranslator<SharedPackageDetails>(identifiersToNames);
273 final IdentifierToNameTranslator<SharedPackageInformation> infoTranslator =
274 new IdentifierToNameTranslator<SharedPackageInformation>(identifiersToNames);
275
276 detailsByIdSource = translator.newSource(detailsAdapter);
277 detailsByIdDestination = translator.newDestination(detailsAdapter);
278 informationByIdSource = infoTranslator.newSource(informationAdapter);
279 informationByIdDestination = infoTranslator.newDestination(informationAdapter);
280
281 informationFromDetailsById = new PackageDetailsToInformationTranslator<FileIdentifier>().
282 newSource(detailsByIdSource);
283
284 identifierFromDetails = new PackageDetailsToFileIdentifierTranslator<String>().newSource(detailsAdapter);
285 }
286 }
287
288 public void setUnknownFileIdentifiersCache(Cache<FileIdentifier, Boolean> unknownFileIdentifiersCache) {
289 this.unknownFileIdentifiersCache = unknownFileIdentifiersCache;
290 unknownFileIdentifiers = new CacheAdapter<FileIdentifier, Boolean>(unknownFileIdentifiersCache, sync);
291 }
292
293 public void setUnknownNamesCache(Cache<String, Boolean> unknownNamesCache) {
294 this.unknownNamesCache = unknownNamesCache;
295 unknownNames = new CacheAdapter<String, Boolean>(unknownNamesCache, sync);
296 }
297
298 private class GetFromSourceAndMapIdsCommand extends GetFromPJPSourceCommand<String, SharedPackageDetails> {
299
300 private GetFromSourceAndMapIdsCommand(AtomicLong fetchedKeyCount, Collection<String> keys, ProceedingJoinPoint pjp) {
301 super(fetchedKeyCount, keys, pjp);
302 }
303
304 @Override
305 public Map<String, SharedPackageDetails> doCall() throws Exception {
306 Map<String, SharedPackageDetails> values = super.doCall();
307 mapNamesToIdentifiersFromValues(values);
308 return values;
309 }
310
311 private void mapNamesToIdentifiersFromValues(final Map<String, SharedPackageDetails> values) {
312 if (DISABLED)
313 return;
314
315 Map<FileIdentifier, String> mappings = new HashMap<FileIdentifier, String>(values.size());
316 for (Map.Entry<String, SharedPackageDetails> entry : values.entrySet()) {
317 if (entry.getValue() == null)
318 continue;
319 FileMetadata fm = entry.getValue().getFileMetadata();
320 if (fm != null)
321 mappings.put(fm.getIdentifier(), entry.getKey());
322 }
323
324 if (!mappings.isEmpty()) {
325 if (sync)
326 identifiersToNames.putAll(mappings);
327 else
328 identifiersToNames.putAllAsync(mappings);
329 }
330
331
332
333
334
335
336
337
338
339
340 }
341 }
342 }