Skip to content

Commit

Permalink
chore: Update EhCache V2 (#3102)
Browse files Browse the repository at this point in the history
Signed-off-by: Pavel Jareš <[email protected]>
  • Loading branch information
pj892031 authored Oct 3, 2023
1 parent 41a31e5 commit f0ac1e7
Show file tree
Hide file tree
Showing 19 changed files with 231 additions and 164 deletions.
4 changes: 2 additions & 2 deletions api-catalog-services/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ logging:
com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient: OFF
com.netflix.discovery.DiscoveryClient: OFF
org.springframework.boot.web.embedded.tomcat.TomcatWebServer: INFO
net.sf.ehcache: WARN
org.ehcache: WARN
org.springframework.security.config.annotation.web.builders.WebSecurity: ERROR

# New Config
Expand Down Expand Up @@ -206,7 +206,7 @@ logging:
org.apache: INFO
org.apache.http: DEBUG
com.netflix: INFO
net.sf.ehcache: INFO
org.ehcache: INFO
com.netflix.discovery.shared.transport.decorator: DEBUG

---
Expand Down
4 changes: 2 additions & 2 deletions api-catalog-services/src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ logging:
com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient: OFF
com.netflix.discovery.DiscoveryClient: OFF
org.springframework.boot.web.embedded.tomcat.TomcatWebServer: INFO
net.sf.ehcache: WARN
org.ehcache: WARN

# New Config
org.apache: WARN #org.apache.catalina, org.apache.coyote, org.apache.tomcat
Expand Down Expand Up @@ -191,7 +191,7 @@ logging:
org.apache: INFO
org.apache.http: DEBUG
com.netflix: INFO
net.sf.ehcache: INFO
org.ehcache: INFO

---
spring:
Expand Down
2 changes: 1 addition & 1 deletion caching-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ logging:
com.netflix: INFO
org.hibernate: INFO
org.springframework.web.servlet.PageNotFound: WARN
net.sf.ehcache: INFO
org.ehcache: INFO
org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter: INFO
com.netflix.discovery.shared.transport.decorator: DEBUG

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@

package org.zowe.apiml.util;

import net.sf.ehcache.Element;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.zowe.apiml.cache.CompositeKey;

import java.util.List;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
* This utils offer base operation with cache, which can be shared to multiple codes.
Expand Down Expand Up @@ -61,18 +63,15 @@ public void evictSubset(CacheManager cacheManager, String cacheName, Predicate<C
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) throw new IllegalArgumentException("Unknown cache " + cacheName);
final Object nativeCache = cache.getNativeCache();
if (nativeCache instanceof net.sf.ehcache.Cache) {
final net.sf.ehcache.Cache ehCache = (net.sf.ehcache.Cache) nativeCache;

for (final Object key : ehCache.getKeys()) {
if (key instanceof CompositeKey) {
// if entry is compositeKey and first param is different, skip it (be sure this is not to evict)
final CompositeKey compositeKey = ((CompositeKey) key);
if (!keyPredicate.test(compositeKey)) continue;
}
// if key is not composite key (unknown for evict) or has same serviceId, evict record
ehCache.remove(key);
}
if (nativeCache instanceof javax.cache.Cache) {
Spliterator<javax.cache.Cache.Entry<Object, Object>> spliterator = ((javax.cache.Cache<Object, Object>) nativeCache).spliterator();
Set<Object> keysToRemove = StreamSupport.stream(spliterator, true)
// if the key matches the predicate then evict the record or
// if the key is not compositeKey (unknown for evict) evict record (as failover)
.filter(e -> !(e.getKey() instanceof CompositeKey) || keyPredicate.test((CompositeKey) e.getKey()))
.map(javax.cache.Cache.Entry::getKey)
.collect(Collectors.toSet());
((javax.cache.Cache<Object, Object>) nativeCache).removeAll(keysToRemove);
} else {
// in case of using different cache manager, evict all records for sure
cache.clear();
Expand All @@ -93,14 +92,9 @@ public <T> List<T> getAllRecords(CacheManager cacheManager, String cacheName) {
if (cache == null) throw new IllegalArgumentException("Unknown cache " + cacheName);

final Object nativeCache = cache.getNativeCache();
if (nativeCache instanceof net.sf.ehcache.Cache) {
final net.sf.ehcache.Cache ehCache = (net.sf.ehcache.Cache) nativeCache;

return (List<T>) ehCache.getAll(ehCache.getKeys())
.values()
.stream()
.map(Element::getObjectValue)
.collect(Collectors.toList());
if (nativeCache instanceof javax.cache.Cache) {
Spliterator<javax.cache.Cache.Entry<Object, T>> spliterator = ((javax.cache.Cache<Object, T>) nativeCache).spliterator();
return StreamSupport.stream(spliterator, true).map(javax.cache.Cache.Entry::getValue).collect(Collectors.toList());
} else {
throw new IllegalArgumentException("Unsupported type of cache : " + nativeCache.getClass());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,16 @@

package org.zowe.apiml.util;

import net.sf.ehcache.Element;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.zowe.apiml.cache.CompositeKey;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class CacheUtilsTest {

Expand All @@ -49,6 +31,25 @@ void setUp() {
underTest = new CacheUtils();
}

private javax.cache.Cache.Entry<Object, Object> createEntry(Object key, Object value) {
return new javax.cache.Cache.Entry<Object, Object>() {
@Override
public Object getKey() {
return key;
}

@Override
public Object getValue() {
return value;
}

@Override
public <T> T unwrap(Class<T> clazz) {
return (T) value;
}
};
}

@Test
void testEvictSubset() {
CacheManager cacheManager = mock(CacheManager.class);
Expand All @@ -60,7 +61,7 @@ void testEvictSubset() {

Cache cache2 = mock(Cache.class);
when(cacheManager.getCache("cache2")).thenReturn(cache2);
net.sf.ehcache.Cache ehCache2 = mock(net.sf.ehcache.Cache.class);
javax.cache.Cache ehCache2 = mock(javax.cache.Cache.class);

when(cache2.getNativeCache()).thenReturn(ehCache2);
List<Object> keys = Arrays.asList(
Expand All @@ -69,7 +70,14 @@ void testEvictSubset() {
new CompositeKey("next", 10),
new CompositeKey("next", 15)
);
when(ehCache2.getKeys()).thenReturn(keys);
List<javax.cache.Cache.Entry<Object, Object>> values = Arrays.asList(
createEntry(keys.get(0), "A"),
createEntry(keys.get(1), "B"),
createEntry(keys.get(2), "C"),
createEntry(keys.get(3), "D")
);

when(ehCache2.spliterator()).thenAnswer(invocation -> values.spliterator());

try {
underTest.evictSubset(cacheManager, "missing", x -> true);
Expand All @@ -79,34 +87,20 @@ void testEvictSubset() {
assertTrue(e.getMessage().contains("missing"));
}

// not EhCache - clean all, dont use keyPredicate
// not EhCache - clean all, do not use keyPredicate
verify(cache1, never()).clear();
underTest.evictSubset(cacheManager, "cache1", x -> false);
verify(cache1, times(1)).clear();

final Answer<Boolean> answer = invocation -> {
removeCounter++;
return true;
};

doAnswer(answer).when(ehCache2).remove(any(Serializable.class));
doAnswer(answer).when(ehCache2).remove((Object) any());

assertEquals(0, removeCounter);
// in all cases remove entries without CompositeKey
underTest.evictSubset(cacheManager, "cache2", x -> false);
assertEquals(1, removeCounter);
verify(ehCache2, times(1)).remove(keys.get(0));
verify(ehCache2, times(1)).removeAll(Collections.singleton(keys.get(0)));

underTest.evictSubset(cacheManager, "cache2", x -> x.equals(0, "test"));
assertEquals(3, removeCounter);
verify(ehCache2, times(2)).remove(keys.get(0));
verify(ehCache2, times(1)).remove(keys.get(1));
verify(ehCache2, times(1)).removeAll(new HashSet(Arrays.asList(keys.get(0), keys.get(1))));

underTest.evictSubset(cacheManager, "cache2", x -> (Integer) x.get(1) > 10);
assertEquals(5, removeCounter);
verify(ehCache2, times(3)).remove(keys.get(0));
verify(ehCache2, times(1)).remove(keys.get(3));
verify(ehCache2, times(1)).removeAll(new HashSet(Arrays.asList(keys.get(0), keys.get(3))));
}

@Test
Expand All @@ -132,30 +126,21 @@ void givenUnsupportedCacheManager_whenGetAllRecords_thenThrowsException() {
assertTrue(iae.getMessage().startsWith("Unsupported type of cache : "));
}

private Map<Object, Element> convert(Map<Integer, String> in) {
Map<Object, Element> out = new HashMap<>();
for (Map.Entry<Integer, String> entry : in.entrySet()) {
out.put(entry.getKey(), new Element(entry.getKey(), entry.getValue()));
}
return out;
}

@Test
void givenValidCacheManager_whenGetAllRecords_thenReadAllStoredRecords() {
CacheManager cacheManager = mock(CacheManager.class);
Cache cache = mock(Cache.class);
net.sf.ehcache.Cache ehCache = mock(net.sf.ehcache.Cache.class);
javax.cache.Cache ehCache = mock(javax.cache.Cache.class);

Map<Integer, String> entries = new HashMap<>();
entries.put(1, "a");
entries.put(2, "b");
entries.put(3, "c");
List<Object> keys = new ArrayList<>(entries.keySet());
List entries = Arrays.asList(
createEntry(1, "a"),
createEntry(2, "b"),
createEntry(3, "c")
);

when(cacheManager.getCache("knownCacheName")).thenReturn(cache);
when(cache.getNativeCache()).thenReturn(ehCache);
when(ehCache.getKeys()).thenReturn(keys);
when(ehCache.getAll(keys)).thenReturn(convert(entries));
when(ehCache.spliterator()).thenAnswer(invocation -> entries.spliterator());

Collection<String> values = underTest.getAllRecords(cacheManager, "knownCacheName");
assertNotNull(values);
Expand Down
3 changes: 0 additions & 3 deletions config/local-multi/gateway-service-1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ spring:
output:
ansi:
enabled: always
cache:
ehcache:
config: classpath:ehcache.xml

server:
internal:
Expand Down
3 changes: 0 additions & 3 deletions config/local-multi/gateway-service-2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ spring:
output:
ansi:
enabled: always
cache:
ehcache:
config: classpath:ehcache.xml

server:
internal:
Expand Down
3 changes: 0 additions & 3 deletions config/local/gateway-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ spring:
output:
ansi:
enabled: always
cache:
ehcache:
config: classpath:ehcache.xml

server:
internal:
Expand Down
4 changes: 2 additions & 2 deletions discovery-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ logging:
com.netflix.discovery.DiscoveryClient: OFF
org.springframework.boot.web.embedded.tomcat.TomcatWebServer: INFO
com.sun.jersey.server.impl.application.WebApplicationImpl: WARN
net.sf.ehcache: WARN
org.ehcache: WARN
org.springframework.security.config.annotation.web.builders.WebSecurity: ERROR

# New Config
Expand Down Expand Up @@ -165,7 +165,7 @@ logging:
org.apache.http: DEBUG
com.netflix: INFO
com.sun.jersey.server.impl.application.WebApplicationImpl: INFO
net.sf.ehcache: INFO
org.ehcache: INFO
com.netflix.discovery.shared.transport.decorator: DEBUG

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.cache.jcache.JCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
Expand All @@ -23,6 +23,7 @@
import org.zowe.apiml.util.CacheUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;

/**
* Spring configuration to use EhCache. This context is using from application and also from tests.
Expand All @@ -48,18 +49,17 @@ public void afterPropertiesSet() {
}

@Bean
public CacheManager cacheManager() {
net.sf.ehcache.CacheManager cache = ehCacheCacheManager().getObject();
assert cache != null;
return new EhCacheCacheManager(cache);
public JCacheManagerFactoryBean cacheManagerFactoryBean() throws IOException {
JCacheManagerFactoryBean jCacheManagerFactoryBean = new JCacheManagerFactoryBean();
jCacheManagerFactoryBean.setCacheManagerUri(new ClassPathResource("ehcache.xml").getURI());
return jCacheManagerFactoryBean;
}

@Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
public CacheManager cacheManager() throws IOException {
final JCacheCacheManager jCacheCacheManager = new JCacheCacheManager();
jCacheCacheManager.setCacheManager(cacheManagerFactoryBean().getObject());
return jCacheCacheManager;
}

@Bean(CacheConfig.COMPOSITE_KEY_GENERATOR)
Expand Down
Loading

0 comments on commit f0ac1e7

Please sign in to comment.