Skip to content

Commit

Permalink
MGR-140
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Müller authored and Matthias Müller committed Jul 27, 2022
1 parent 70b3a6e commit 097f713
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 80 deletions.
174 changes: 94 additions & 80 deletions src/main/java/org/appng/application/manager/business/Cache.java
Expand Up @@ -52,6 +52,7 @@
import org.appng.xml.platform.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -87,98 +88,111 @@ public DataContainer getData(Site site, Application application, Environment env
Map<String, Site> siteMap = env.getAttribute(Scope.PLATFORM, Platform.Environment.SITES);
Optional<Site> cacheSite = siteMap.values().stream().filter(s -> s.getId().equals(siteId)).findFirst();

if (STATISTICS.equals(mode)) {
List<Entry<String, String>> cacheStats = getCacheStats(request, cacheSite);
dataContainer.setItems(cacheStats);
} else if (ENTRIES.equals(mode)) {
Page<CacheEntry> cacheEntries = getCacheEntries(request, fp, cacheSite, dataContainer);
dataContainer.setPage(cacheEntries);
}

return dataContainer;
}

public List<Entry<String, String>> getCacheStats(Request request, Optional<Site> cacheSite) {
List<Entry<String, String>> result = new ArrayList<>();
if (cacheSite.isPresent()) {
if (STATISTICS.equals(mode)) {
List<Entry<String, String>> result = new ArrayList<>();
Map<String, String> stats = CacheService.getCacheStatistics(cacheSite.get());
if (!stats.isEmpty()) {
result.add(getStatEntry(request, stats, CacheService.STATS_NAME));
result.add(getStatEntry(request, stats, CacheService.STATS_SIZE));
result.add(getStatEntry(request, stats, CacheService.STATS_HITS));
result.add(getStatEntry(request, stats, CacheService.STATS_HITS_PERCENT));
result.add(getStatEntry(request, stats, CacheService.STATS_MISSES));
result.add(getStatEntry(request, stats, CacheService.STATS_MISSES_PERCENT));
result.add(getStatEntry(request, stats, CacheService.STATS_PUTS));
result.add(getStatEntry(request, stats, CacheService.STATS_AVG_PUT_TIME));
result.add(getStatEntry(request, stats, CacheService.STATS_GETS));
result.add(getStatEntry(request, stats, CacheService.STATS_AVG_GET_TIME));
result.add(getStatEntry(request, stats, CacheService.STATS_REMOVALS));
result.add(getStatEntry(request, stats, CacheService.STATS_AVG_REMOVAL_TIME));
}
dataContainer.setItems(result);
} else if (ENTRIES.equals(mode)) {
Pageable pageable = fp.getPageable();
List<CacheEntry> cacheEntries = new ArrayList<>();

javax.cache.Cache<String, CachedResponse> cache = CacheService.getCache(cacheSite.get());
int cacheSize = 0;
if (null != cache) {
cacheSize = cache.unwrap(ICache.class).size();

if (cacheSize > maxCacheEntries) {
Iterator<javax.cache.Cache.Entry<String, CachedResponse>> elements = cache.iterator();
int idx = 0;
int startIdx = pageable.getOffset();
int endIdx = pageable.getOffset() + pageable.getPageSize();
while (elements.hasNext()) {
javax.cache.Cache.Entry<java.lang.String, CachedResponse> entry = elements.next();
CachedResponse cachedResponse = entry.getValue();
// entry may have been removed meanwhile
if (null != cachedResponse) {
if (idx >= startIdx && idx < endIdx) {
cacheEntries.add(new CacheEntry(cachedResponse));
}
if (idx++ >= endIdx) {
break;
}
} else {
endIdx++;
Map<String, String> stats = CacheService.getCacheStatistics(cacheSite.get());
if (!stats.isEmpty()) {
result.add(getStatEntry(request, stats, CacheService.STATS_NAME));
result.add(getStatEntry(request, stats, CacheService.STATS_SIZE));
result.add(getStatEntry(request, stats, CacheService.STATS_HITS));
result.add(getStatEntry(request, stats, CacheService.STATS_HITS_PERCENT));
result.add(getStatEntry(request, stats, CacheService.STATS_MISSES));
result.add(getStatEntry(request, stats, CacheService.STATS_MISSES_PERCENT));
result.add(getStatEntry(request, stats, CacheService.STATS_PUTS));
result.add(getStatEntry(request, stats, CacheService.STATS_AVG_PUT_TIME));
result.add(getStatEntry(request, stats, CacheService.STATS_GETS));
result.add(getStatEntry(request, stats, CacheService.STATS_AVG_GET_TIME));
result.add(getStatEntry(request, stats, CacheService.STATS_REMOVALS));
result.add(getStatEntry(request, stats, CacheService.STATS_AVG_REMOVAL_TIME));
}
}
return result;
}

public Page<CacheEntry> getCacheEntries(Request request, FieldProcessor fp, Optional<Site> cacheSite,
DataContainer dataContainer) {
Pageable pageable = fp.getPageable();
List<CacheEntry> cacheEntries = new ArrayList<>();
int cacheSize = 0;
if (cacheSite.isPresent()) {
javax.cache.Cache<String, CachedResponse> cache = CacheService.getCache(cacheSite.get());
if (null != cache) {
cacheSize = cache.unwrap(ICache.class).size();

if (cacheSize > maxCacheEntries) {
Iterator<javax.cache.Cache.Entry<String, CachedResponse>> elements = cache.iterator();
int idx = 0;
int startIdx = pageable.getOffset();
int endIdx = pageable.getOffset() + pageable.getPageSize();
while (elements.hasNext()) {
javax.cache.Cache.Entry<java.lang.String, CachedResponse> entry = elements.next();
CachedResponse cachedResponse = entry.getValue();
// entry may have been removed meanwhile
if (null != cachedResponse) {
if (idx >= startIdx && idx < endIdx) {
cacheEntries.add(new CacheEntry(cachedResponse));
}
if (idx++ >= endIdx) {
break;
}
} else {
endIdx++;
}
}

fp.getFields().stream().filter(f -> !"id".equals(f.getBinding())).forEach(f -> f.setSort(null));
SortOrder idOrder = fp.getField("id").getSort().getOrder();
if (null != idOrder) {
Collections.sort(cacheEntries, (e1, e2) -> StringUtils.compare(e1.getId(), e2.getId()));
if (SortOrder.DESC.equals(idOrder)) {
Collections.reverse(cacheEntries);
}
fp.getFields().stream().filter(f -> !"id".equals(f.getBinding())).forEach(f -> f.setSort(null));
SortOrder idOrder = fp.getField("id").getSort().getOrder();
if (null != idOrder) {
Collections.sort(cacheEntries, (e1, e2) -> StringUtils.compare(e1.getId(), e2.getId()));
if (SortOrder.DESC.equals(idOrder)) {
Collections.reverse(cacheEntries);
}
}

} else {
String entryName = request.getParameter(F_ETR);
String entryType = request.getParameter(F_CTYPE);
boolean filterName = StringUtils.isNotBlank(entryName);
boolean filterType = StringUtils.isNotBlank(entryType);
for (javax.cache.Cache.Entry<String, CachedResponse> entry : cache) {
String entryId = entry.getKey();
CachedResponse cachedResponse = entry.getValue();
// entry may have been removed meanwhile
if (null != cachedResponse) {
boolean nameMatches = !filterName || FilenameUtils.wildcardMatch(
entryId.substring(entryId.indexOf('/')), entryName, IOCase.INSENSITIVE);
boolean typeMatches = !filterType || FilenameUtils
.wildcardMatch(cachedResponse.getContentType(), entryType, IOCase.INSENSITIVE);
if (nameMatches && typeMatches) {
cacheEntries.add(new CacheEntry(cachedResponse));
}
} else {
String entryName = request.getParameter(F_ETR);
String entryType = request.getParameter(F_CTYPE);
boolean filterName = StringUtils.isNotBlank(entryName);
boolean filterType = StringUtils.isNotBlank(entryType);
for (javax.cache.Cache.Entry<String, CachedResponse> entry : cache) {
String entryId = entry.getKey();
CachedResponse cachedResponse = entry.getValue();
// entry may have been removed meanwhile
if (null != cachedResponse) {
boolean nameMatches = !filterName || FilenameUtils.wildcardMatch(
entryId.substring(entryId.indexOf('/')), entryName, IOCase.INSENSITIVE);
boolean typeMatches = !filterType || FilenameUtils
.wildcardMatch(cachedResponse.getContentType(), entryType, IOCase.INSENSITIVE);
if (nameMatches && typeMatches) {
cacheEntries.add(new CacheEntry(cachedResponse));
}
}

Selection nameSelection = selectionFactory.getTextSelection(F_ETR, MessageConstants.NAME,
entryName);
Selection typeSelection = selectionFactory.getTextSelection(F_CTYPE, MessageConstants.TYPE,
entryType);
SelectionGroup selectionGroup = new SelectionGroup();
selectionGroup.getSelections().add(nameSelection);
selectionGroup.getSelections().add(typeSelection);
dataContainer.getSelectionGroups().add(selectionGroup);
}

Selection nameSelection = selectionFactory.getTextSelection(F_ETR, MessageConstants.NAME,
entryName);
Selection typeSelection = selectionFactory.getTextSelection(F_CTYPE, MessageConstants.TYPE,
entryType);
SelectionGroup selectionGroup = new SelectionGroup();
selectionGroup.getSelections().add(nameSelection);
selectionGroup.getSelections().add(typeSelection);
dataContainer.getSelectionGroups().add(selectionGroup);
}
dataContainer.setPage(new PageImpl<>(cacheEntries, pageable, cacheSize));
}
}
return dataContainer;
return new PageImpl<>(cacheEntries, pageable, cacheSize);
}

private Entry<String, String> getStatEntry(Request request, Map<String, String> statistics, String statKey) {
Expand Down
Expand Up @@ -70,6 +70,15 @@ public void testCache() throws Exception {
validate(datasource, new DateFieldDifferenceHandler());
}

@Test
public void testCacheNoSite() throws Exception {
addParameter("sortCacheElements", "pageSize:25;page:0");
initParameters();
CallableDataSource ds = getDataSource("cacheElements").withParam("siteid", "42").getCallableDataSource();
ds.perform("");
validate(ds.getDatasource());
}

@Test
public void testCacheStatistics() throws Exception {
CallableDataSource ds = getDataSource("cacheStatistics").withParam("siteid", "1").getCallableDataSource();
Expand Down
68 changes: 68 additions & 0 deletions src/test/resources/xml/CacheTest-testCacheNoSite.xml
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<datasource xmlns="http://www.appng.org/schema/platform" id="cacheElements">
<config>
<title id="cache.elements">Cache elements</title>
<permissions>
<permission ref="cache.elements.list" mode="set"></permission>
</permissions>
<params>
<param name="siteid">42</param>
<param name="deleteLink" />
<param name="clearLink" />
</params>
<meta-data bindClass="org.appng.application.manager.business.Cache$CacheEntry">
<field name="id" type="text" displayLength="75" binding="id">
<sort />
<label id="id">ID</label>
</field>
<field name="type" type="text" binding="type">
<sort />
<label id="type">Type</label>
</field>
<field name="size" type="decimal" format="#,##0 KB" binding="size">
<sort />
<label id="size">Size</label>
</field>
<field name="hits" type="text" binding="hits">
<sort />
<label id="hitCount">Hits</label>
</field>
<field name="created" type="date" format="HH:mm:ss" binding="created">
<sort />
<label id="created">Created</label>
</field>
<field name="expires" type="date" format="HH:mm:ss" binding="expires">
<sort />
<label id="expires">Expires</label>
</field>
<field name="actions" type="linkpanel" binding="actions">
<label id="actions">Actions</label>
</field>
</meta-data>
<linkpanel id="actions" location="inline">
<link id="actions[1]" mode="intern" target="${current.id}">
<permissions>
<permission ref="cache.element.expire" mode="set"></permission>
</permissions>
<label id="cache.element.expire">Remove element from cache</label>
<icon>delete</icon>
</link>
<link id="actions[2]" mode="extern" target="${current.path}">
<label id="show">show</label>
<icon>preview</icon>
</link>
</linkpanel>
<linkpanel id="other" location="bottom">
<link id="other[1]" mode="intern" target="">
<permissions>
<permission ref="cache.clear" mode="set"></permission>
</permissions>
<label id="cache.clear">Clear cache</label>
<icon>delete</icon>
</link>
</linkpanel>
</config>
<data>
<resultset chunk="0" chunkname="cacheElements" chunksize="25" nextchunk="0" previouschunk="0" firstchunk="0" lastchunk="-1" hits="0" />
</data>
</datasource>

0 comments on commit 097f713

Please sign in to comment.