diff --git a/pom.xml b/pom.xml index 6f635d7..c2f9bc6 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 12.3.1 1.11.0 1.3.5 - 2.10.9.2 + 3.11.1 4.5.14 4.4.16 2.20.1 @@ -181,16 +181,22 @@ jakarta.xml.bind-api ${jakarta.xml.bind-api.version} - - net.sf.ehcache - ehcache - ${ehcache.version} - org.apache.httpcomponents httpclient ${httpclient.version} + + org.ehcache + ehcache + ${ehcache.version} + + + org.glassfish.jaxb + jaxb-runtime + + + org.jsoup jsoup diff --git a/src/main/java/ac/simons/oembed/OembedResponseExpiryPolicy.java b/src/main/java/ac/simons/oembed/OembedResponseExpiryPolicy.java new file mode 100644 index 0000000..6db88c0 --- /dev/null +++ b/src/main/java/ac/simons/oembed/OembedResponseExpiryPolicy.java @@ -0,0 +1,92 @@ +/* + * Created by Michael Simons, michael-simons.eu + * and released under The BSD License + * http://www.opensource.org/licenses/bsd-license.php + * + * Copyright (c) 2010-2026, Michael Simons + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of michael-simons.eu nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package ac.simons.oembed; + +import java.time.Duration; +import java.util.function.Supplier; + +import org.ehcache.expiry.ExpiryPolicy; + +/** + * A custom {@link ExpiryPolicy} for Ehcache 3.x that extracts the TTL from an + * {@link OembedResponse}, enabling per-entry expiration times. + * + * @author Oliver Lockwood + * @author Michael J. Simons + * @since 2026-01-17 + */ +final class OembedResponseExpiryPolicy implements ExpiryPolicy { + + /** + * Time in seconds responses are cached. Used if the response has no cache_age. + */ + private long defaultCacheAge = 3600; + + @Override + public Duration getExpiryForCreation(String key, OembedResponseWrapper value) { + return getExpiryOf(value); + } + + @Override + public Duration getExpiryForAccess(String key, Supplier value) { + return null; + } + + @Override + public Duration getExpiryForUpdate(String key, Supplier oldValue, + OembedResponseWrapper newValue) { + return getExpiryOf(newValue); + } + + Duration getExpiryOf(OembedResponseWrapper wrapper) { + long cacheAge; + if (wrapper.value() != null && wrapper.value().getCacheAge() != null) { + // Cache at least 60 seconds + cacheAge = Math.max(60, wrapper.value().getCacheAge()); + } + else { + cacheAge = this.defaultCacheAge; + } + return Duration.ofSeconds(Math.min(cacheAge, Integer.MAX_VALUE)); + } + + long getDefaultCacheAge() { + return this.defaultCacheAge; + } + + void setDefaultCacheAge(long defaultCacheAge) { + this.defaultCacheAge = defaultCacheAge; + } + +} diff --git a/src/main/java/ac/simons/oembed/OembedResponseWrapper.java b/src/main/java/ac/simons/oembed/OembedResponseWrapper.java new file mode 100644 index 0000000..670aab6 --- /dev/null +++ b/src/main/java/ac/simons/oembed/OembedResponseWrapper.java @@ -0,0 +1,45 @@ +/* + * Created by Michael Simons, michael-simons.eu + * and released under The BSD License + * http://www.opensource.org/licenses/bsd-license.php + * + * Copyright (c) 2010-2026, Michael Simons + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of michael-simons.eu nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package ac.simons.oembed; + +/** + * EHCache 3 is unhappy with {@literal null} values, so we wrap them. + * + * @param value actual OEmbed response, might be {@literal null} + * @author Oliver Lockwood + * @author Michael J. Simons + * @since 2026-01-17 + */ +record OembedResponseWrapper(OembedResponse value) { +} diff --git a/src/main/java/ac/simons/oembed/OembedService.java b/src/main/java/ac/simons/oembed/OembedService.java index bb28fa5..004e701 100644 --- a/src/main/java/ac/simons/oembed/OembedService.java +++ b/src/main/java/ac/simons/oembed/OembedService.java @@ -50,14 +50,16 @@ import java.util.stream.Collectors; import ac.simons.oembed.OembedResponse.Format; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.Ehcache; import org.apache.commons.beanutils.BeanUtils; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.util.EntityUtils; +import org.ehcache.Cache; +import org.ehcache.CacheManager; +import org.ehcache.config.builders.CacheConfigurationBuilder; +import org.ehcache.config.builders.ResourcePoolsBuilder; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -84,7 +86,7 @@ public class OembedService { /** * An optional cache manager used for caching oembed responses. */ - private final Optional cacheManager; + private final CacheManager cacheManager; /** * The user agent to use. We want to be a goot net citizen and provide some info about @@ -123,11 +125,6 @@ public class OembedService { */ private String cacheName = OembedService.class.getName(); - /** - * Time in seconds responses are cached. Used if the response has no cache_age. - */ - private long defaultCacheAge = 3600; - /** * Used for auto-discovered endpoints. */ @@ -138,6 +135,8 @@ public class OembedService { */ private final OembedResponseRenderer defaultRenderer = new DefaultOembedResponseRenderer(); + private final OembedResponseExpiryPolicy expiryPolicy = new OembedResponseExpiryPolicy(); + /** * Creates a new {@code OembedService}. This service depends on a {@link HttpClient} * and can use a {@link CacheManager} for caching requests. @@ -149,7 +148,7 @@ public class OembedService { public OembedService(final HttpClient httpClient, final CacheManager cacheManager, final List endpoints, final String applicationName) { this.httpClient = httpClient; - this.cacheManager = Optional.ofNullable(cacheManager); + this.cacheManager = cacheManager; final Properties version = new Properties(); try { version.load(OembedService.class.getResourceAsStream("/oembed.properties")); @@ -236,8 +235,9 @@ public String getCacheName() { * @param cacheName the new cache name */ public void setCacheName(final String cacheName) { - if (this.cacheManager.isPresent() && this.cacheManager.get().cacheExists(this.cacheName)) { - this.cacheManager.get().removeCache(this.cacheName); + if (this.cacheManager != null + && this.cacheManager.getCache(this.cacheName, String.class, OembedResponseWrapper.class) != null) { + this.cacheManager.removeCache(this.cacheName); } this.cacheName = cacheName; } @@ -246,7 +246,7 @@ public void setCacheName(final String cacheName) { * {@return the default time in seconds responses are cached} */ public long getDefaultCacheAge() { - return this.defaultCacheAge; + return this.expiryPolicy.getDefaultCacheAge(); } /** @@ -254,7 +254,7 @@ public long getDefaultCacheAge() { * @param defaultCacheAge new default cache age in seconds */ public void setDefaultCacheAge(final long defaultCacheAge) { - this.defaultCacheAge = defaultCacheAge; + this.expiryPolicy.setDefaultCacheAge(defaultCacheAge); } /** @@ -331,6 +331,26 @@ final InputStream executeRequest(final HttpGet request) { return rv; } + /** + * Gets or creates the cache for oembed responses. In Ehcache 3.x, caches need to be + * explicitly created with a configuration. + * @return the cache instance or null if there is no cache manager + */ + private Cache getOrCreateCache() { + if (this.cacheManager == null) { + return null; + } + var cache = this.cacheManager.getCache(this.cacheName, String.class, OembedResponseWrapper.class); + if (cache != null) { + return cache; + } + + return this.cacheManager.createCache(this.cacheName, CacheConfigurationBuilder + .newCacheConfigurationBuilder(String.class, OembedResponseWrapper.class, ResourcePoolsBuilder.heap(1000)) + .withExpiry(new OembedResponseExpiryPolicy()) + .build()); + } + /** * Tries to find an {@link OembedResponse} for the URL {@code url}. If a cache manager * is present, it tries that first. If an {@code OembedResponse} can be discovered and @@ -345,8 +365,9 @@ public Optional getOembedResponseFor(final String url) { return Optional.empty(); } - var rv = this.cacheManager.map(cm -> cm.addCacheIfAbsent(this.cacheName).get(trimmedUrl)) - .map(element -> (OembedResponse) element.getObjectValue()); + var rv = Optional.ofNullable(this.getOrCreateCache()) + .map(cache -> cache.get(trimmedUrl)) + .map(OembedResponseWrapper::value); // If there's already an oembed response cached, use that if (rv.isPresent()) { LOGGER.debug("Using OembedResponse from cache for '{}'...", trimmedUrl); @@ -371,15 +392,12 @@ public Optional getOembedResponseFor(final String url) { return oembedResponse; }); - if (this.cacheManager.isPresent()) { - final Ehcache cache = this.cacheManager.get().addCacheIfAbsent(this.cacheName); - // Cache at least 60 seconds - final int cacheAge = (int) Math.min( - Math.max(60L, rv.map(OembedResponse::getCacheAge).orElse(this.defaultCacheAge)), Integer.MAX_VALUE); + if (this.cacheManager != null) { + var cache = getOrCreateCache(); // We're adding failed urls to the cache as well to prevent them // from being tried again over and over (at least for some seconds) - cache.put(new net.sf.ehcache.Element(trimmedUrl, rv.orElse(null), cacheAge, cacheAge)); - LOGGER.debug("Cached {} for {} seconds for url '{}'...", rv, cacheAge, trimmedUrl); + cache.put(trimmedUrl, new OembedResponseWrapper(rv.orElse(null))); + LOGGER.debug("Cached response {} from url '{}'...", rv, trimmedUrl); } return rv; diff --git a/src/test/java/ac/simons/oembed/OembedResponseExpiryPolicyTests.java b/src/test/java/ac/simons/oembed/OembedResponseExpiryPolicyTests.java new file mode 100644 index 0000000..bb90454 --- /dev/null +++ b/src/test/java/ac/simons/oembed/OembedResponseExpiryPolicyTests.java @@ -0,0 +1,89 @@ +/* + * Created by Michael Simons, michael-simons.eu + * and released under The BSD License + * http://www.opensource.org/licenses/bsd-license.php + * + * Copyright (c) 2010-2026, Michael Simons + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of michael-simons.eu nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package ac.simons.oembed; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Oliver Lockwood + * @author Michael J. Simons + * @since 2026-01-17 + */ +class OembedResponseExpiryPolicyTests { + + @Test + void expiryPolicyShouldReturnCorrectDuration() { + OembedResponse response = new OembedResponse(); + response.setType("rich"); + response.setVersion("1.0"); + response.setCacheAge(120L); + + OembedResponseExpiryPolicy policy = new OembedResponseExpiryPolicy(); + OembedResponseWrapper cached = new OembedResponseWrapper(response); + + Duration duration = policy.getExpiryForCreation("key", cached); + assertThat(duration).isEqualTo(Duration.ofSeconds(120)); + } + + @Test + void expiryPolicyShouldReturnNullForAccess() { + OembedResponseExpiryPolicy policy = new OembedResponseExpiryPolicy(); + + Duration duration = policy.getExpiryForAccess("key", () -> new OembedResponseWrapper(null)); + assertThat(duration).isNull(); + } + + @Test + void expiryPolicyShouldReturnDurationForUpdate() { + OembedResponse oldValue = new OembedResponse(); + oldValue.setType("rich"); + oldValue.setVersion("1.0"); + oldValue.setCacheAge(120L); + + OembedResponse newValue = new OembedResponse(); + newValue.setType("rich"); + newValue.setVersion("1.0"); + newValue.setCacheAge(300L); + + OembedResponseExpiryPolicy policy = new OembedResponseExpiryPolicy(); + Duration duration = policy.getExpiryForUpdate("key", () -> new OembedResponseWrapper(oldValue), + new OembedResponseWrapper(newValue)); + assertThat(duration).isEqualTo(Duration.ofSeconds(300)); + } + +} diff --git a/src/test/java/ac/simons/oembed/OembedServiceTests.java b/src/test/java/ac/simons/oembed/OembedServiceTests.java index 26c862a..2aa54cd 100644 --- a/src/test/java/ac/simons/oembed/OembedServiceTests.java +++ b/src/test/java/ac/simons/oembed/OembedServiceTests.java @@ -42,12 +42,11 @@ import java.util.Optional; import ac.simons.oembed.OembedResponse.Format; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.Ehcache; -import net.sf.ehcache.Element; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; +import org.ehcache.Cache; +import org.ehcache.CacheManager; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -77,6 +76,9 @@ public class OembedServiceTests { @Mock private CacheManager cacheManager; + @Mock + private Cache cache; + private final String responseString = "{\"author_name\":\"Michael J. Simons\",\"author_url\":\"http://michael-simons.eu\",\"cache_age\":86400,\"html\":\"\",\"provider_name\":\"biking2\",\"provider_url\":\"https://biking.michael-simons.eu\",\"title\":\"Aachen - Maastricht - Aachen\",\"type\":\"rich\",\"version\":\"1.0\"}"; private final OembedResponse response1; @@ -249,8 +251,9 @@ public void executeRequestShouldWork3() throws IOException { @Test public void setCacheNameShouldWork() { - given(this.cacheManager.cacheExists("ac.simons.oembed.OembedService")).willReturn(false); - given(this.cacheManager.cacheExists("x")).willReturn(true); + given(this.cacheManager.getCache("ac.simons.oembed.OembedService", String.class, OembedResponseWrapper.class)) + .willReturn(null); + given(this.cacheManager.getCache("x", String.class, OembedResponseWrapper.class)).willReturn(this.cache); OembedService oembedService; oembedService = new OembedService(this.defaultHttpClient, null, new ArrayList<>(), null); @@ -264,8 +267,8 @@ public void setCacheNameShouldWork() { oembedService.setCacheName("y"); assertThat(oembedService.getCacheName()).isEqualTo("y"); - verify(this.cacheManager).cacheExists(OembedService.class.getName()); - verify(this.cacheManager).cacheExists("x"); + verify(this.cacheManager).getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class); + verify(this.cacheManager).getCache("x", String.class, OembedResponseWrapper.class); verify(this.cacheManager).removeCache("x"); Mockito.verifyNoMoreInteractions(this.cacheManager); } @@ -283,10 +286,12 @@ public void getOembedResponseForShouldWork1() { */ @Test public void getOembedResponseForShouldWork2() { - Ehcache cache = Mockito.mock(Ehcache.class); String embeddableUrl = "https://biking.michael-simons.eu/tracks/1"; - given(cache.get(embeddableUrl)).willReturn(new Element(embeddableUrl, this.response1)); - given(this.cacheManager.addCacheIfAbsent("testCache")).willReturn(cache); + given(this.cache.get(embeddableUrl)).willReturn(new OembedResponseWrapper(this.response1)); + given(this.cacheManager.getCache("testCache", String.class, OembedResponseWrapper.class)) + .willReturn(this.cache); + given(this.cacheManager.getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class)) + .willReturn(null); OembedService oembedService = new OembedService(this.defaultHttpClient, this.cacheManager, new ArrayList<>(), null); @@ -308,10 +313,10 @@ public void getOembedResponseForShouldWork2() { assertThat(response.getVersion()).isEqualTo("1.0"); assertThat(oembedService.getCacheName()).isEqualTo("testCache"); - verify(this.cacheManager).addCacheIfAbsent("testCache"); - verify(this.cacheManager).cacheExists(OembedService.class.getName()); - verify(cache).get(embeddableUrl); - Mockito.verifyNoMoreInteractions(cache, this.cacheManager); + verify(this.cacheManager).getCache("testCache", String.class, OembedResponseWrapper.class); + verify(this.cacheManager).getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class); + verify(this.cache).get(embeddableUrl); + Mockito.verifyNoMoreInteractions(this.cache, this.cacheManager); Mockito.verifyNoInteractions(this.defaultHttpClient); } @@ -337,9 +342,11 @@ public void getOembedResponseForShouldWork3() throws IOException { given(this.defaultHttpClient.execute(any(HttpGet.class))).willReturn(r); - Ehcache cache = Mockito.mock(Ehcache.class); - given(cache.get(embeddableUrl)).willReturn(null); - given(this.cacheManager.addCacheIfAbsent("testCache")).willReturn(cache); + given(this.cache.get(embeddableUrl)).willReturn(null); + given(this.cacheManager.getCache("testCache", String.class, OembedResponseWrapper.class)) + .willReturn(this.cache); + given(this.cacheManager.getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class)) + .willReturn(null); OembedService oembedService = new OembedService(this.defaultHttpClient, this.cacheManager, List.of(oembedEndpoint), null); @@ -350,12 +357,12 @@ public void getOembedResponseForShouldWork3() throws IOException { assertThat(argumentCaptor.getValue().getURI()).hasToString( "https://biking.michael-simons.eu/oembed?format=json&url=https%3A%2F%2Fbiking.michael-simons.eu%2Ftracks%2F1&maxwidth=480&maxheight=360"); - verify(this.cacheManager, times(2)).addCacheIfAbsent("testCache"); - verify(this.cacheManager).cacheExists(OembedService.class.getName()); - verify(cache).get(embeddableUrl); - verify(cache).put(any(Element.class)); + verify(this.cacheManager, times(2)).getCache("testCache", String.class, OembedResponseWrapper.class); + verify(this.cacheManager).getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class); + verify(this.cache).get(embeddableUrl); + verify(this.cache).put(any(String.class), any(OembedResponseWrapper.class)); - verifyNoMoreInteractions(cache, this.cacheManager, this.defaultHttpClient); + verifyNoMoreInteractions(this.cache, this.cacheManager, this.defaultHttpClient); } /** @@ -380,9 +387,11 @@ public void getOembedResponseForShouldWork4() throws IOException { given(this.defaultHttpClient.execute(any(HttpGet.class))).willReturn(r); - Ehcache cache = Mockito.mock(Ehcache.class); - given(cache.get(embeddableUrl)).willReturn(null); - given(this.cacheManager.addCacheIfAbsent("testCache")).willReturn(cache); + given(this.cache.get(embeddableUrl)).willReturn(null); + given(this.cacheManager.getCache("testCache", String.class, OembedResponseWrapper.class)) + .willReturn(this.cache); + given(this.cacheManager.getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class)) + .willReturn(null); OembedService oembedService = new OembedService(this.defaultHttpClient, this.cacheManager, List.of(oembedEndpoint), null); @@ -393,12 +402,12 @@ public void getOembedResponseForShouldWork4() throws IOException { assertThat(argumentCaptor.getValue().getURI()).hasToString( "https://biking.michael-simons.eu/oembed?format=json&url=https%3A%2F%2Fbiking.michael-simons.eu%2Ftracks%2F1&maxwidth=480&maxheight=360"); - verify(this.cacheManager, times(2)).addCacheIfAbsent("testCache"); - verify(this.cacheManager).cacheExists(OembedService.class.getName()); - verify(cache).get(embeddableUrl); - verify(cache).put(any(Element.class)); + verify(this.cacheManager, times(2)).getCache("testCache", String.class, OembedResponseWrapper.class); + verify(this.cacheManager).getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class); + verify(this.cache).get(embeddableUrl); + verify(this.cache).put(any(String.class), any(OembedResponseWrapper.class)); - verifyNoMoreInteractions(cache, this.cacheManager, this.defaultHttpClient); + verifyNoMoreInteractions(this.cache, this.cacheManager, this.defaultHttpClient); } /** @@ -455,10 +464,12 @@ public void embedUrlsShouldWork1() { */ @Test public void embedUrlsShouldWork2() { - Ehcache cache = Mockito.mock(Ehcache.class); String embeddableUrl = "https://biking.michael-simons.eu/tracks/1"; - given(cache.get(embeddableUrl)).willReturn(new Element(embeddableUrl, this.response1)); - given(this.cacheManager.addCacheIfAbsent("testCache")).willReturn(cache); + given(this.cache.get(embeddableUrl)).willReturn(new OembedResponseWrapper(this.response1)); + given(this.cacheManager.getCache("testCache", String.class, OembedResponseWrapper.class)) + .willReturn(this.cache); + given(this.cacheManager.getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class)) + .willReturn(null); OembedService oembedService = new OembedService(this.defaultHttpClient, this.cacheManager, new ArrayList<>(), null); @@ -472,10 +483,12 @@ public void embedUrlsShouldWork2() { @Test public void embedUrlsShouldWork3() { - Ehcache cache = Mockito.mock(Ehcache.class); String embeddableUrl = "https://biking.michael-simons.eu/tracks/1"; - given(cache.get(embeddableUrl)).willReturn(new Element(embeddableUrl, this.response1)); - given(this.cacheManager.addCacheIfAbsent("testCache")).willReturn(cache); + given(this.cache.get(embeddableUrl)).willReturn(new OembedResponseWrapper(this.response1)); + given(this.cacheManager.getCache("testCache", String.class, OembedResponseWrapper.class)) + .willReturn(this.cache); + given(this.cacheManager.getCache(OembedService.class.getName(), String.class, OembedResponseWrapper.class)) + .willReturn(null); OembedEndpoint oembedEndpoint = new OembedEndpoint(); oembedEndpoint.setName("biking");