Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Update EhCache V2 #3102

Merged
merged 4 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
achmelo marked this conversation as resolved.
Show resolved Hide resolved
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
Loading