/* * Copyright Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ehcache.impl.internal.store.heap; import org.ehcache.Cache; import org.ehcache.CacheManager; import org.ehcache.config.Eviction; import org.ehcache.config.EvictionAdvisor; import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.impl.config.copy.DefaultCopierConfiguration; import org.ehcache.core.spi.store.StoreAccessException; import org.ehcache.spi.serialization.SerializerException; import org.ehcache.expiry.Expirations; import org.ehcache.expiry.Expiry; import org.ehcache.core.spi.function.Function; import org.ehcache.impl.copy.SerializingCopier; import org.ehcache.core.spi.time.SystemTimeSource; import org.ehcache.core.spi.time.TimeSource; import org.ehcache.core.spi.store.AbstractValueHolder; import org.ehcache.core.spi.store.Store.ValueHolder; import org.ehcache.impl.serialization.JavaSerializer; import org.ehcache.spi.copy.Copier; import org.junit.Test; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import static org.ehcache.config.builders.ResourcePoolsBuilder.heap; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.Assert.fail; @SuppressWarnings("serial") public abstract class OnHeapStoreByValueTest extends BaseOnHeapStoreTest { static class LongCopier implements Copier<Long> { int copyForReadCount = 0; int copyForWriteCount = 0; @Override public Long copyForRead(Long obj) { copyForReadCount++; return obj; } @Override public Long copyForWrite(Long obj) { copyForWriteCount++; return obj; } } @Test public void testKeyCopierCalledOnGetOrComputeIfAbsent() throws Exception { LongCopier keyCopier = new LongCopier(); OnHeapStore<Long, Long> store = newStore(SystemTimeSource.INSTANCE, Expirations.noExpiration(), Eviction.noAdvice(), keyCopier, new SerializingCopier<Long>(new JavaSerializer<Long>(ClassLoader.getSystemClassLoader())), 100); ValueHolder<Long> computed = store.getOrComputeIfAbsent(1L, new Function<Long, ValueHolder<Long>>() { @Override public ValueHolder<Long> apply(final Long key) { return new AbstractValueHolder<Long>(-1, -1) { @Override public Long value() { return key * 1000L; } @Override protected TimeUnit nativeTimeUnit() { return TimeUnit.MILLISECONDS; } }; } }); assertThat(computed.value(), is(1000L)); assertThat(keyCopier.copyForWriteCount, is(1)); assertThat(keyCopier.copyForReadCount, is(0)); } @Test public void testPutNotSerializableValue() throws Exception { OnHeapStore<Serializable, Serializable> store = newStore(); try { store.put("key1", new ArrayList<Object>() {{ add(new Object()); }}); fail(); } catch (StoreAccessException cae) { assertThat(cae.getCause(), instanceOf(SerializerException.class)); } } @Test public void testPutNotSerializableKey() throws Exception { OnHeapStore<Serializable, Serializable> store = newStore(); try { store.put(new ArrayList<Object>() {{ add(new Object()); }}, "value"); fail(); } catch (StoreAccessException cae) { assertThat(cae.getCause(), instanceOf(SerializerException.class)); } } @Test public void testValueUniqueObject() throws Exception { OnHeapStore<Serializable, Serializable> store = newStore(); String key = "key"; List<String> value = new ArrayList<String>(); value.add("value"); store.put(key, (Serializable) value); // mutate the value -- should not affect cache value.clear(); ValueHolder<Serializable> valueHolder = store.get(key); if (valueHolder.value() == value || ! valueHolder.value().equals(Collections.singletonList("value"))) { throw new AssertionError(); } } @Test public void testKeyUniqueObject() throws Exception { OnHeapStore<Serializable, Serializable> store = newStore(); List<String> key = new ArrayList<String>(); key.add("key"); String value = "value"; store.put((Serializable)key, value); // mutate the key -- should not affect cache key.clear(); Serializable storeKey = store.iterator().next().getKey(); if (storeKey == key || ! storeKey.equals(Collections.singletonList("key"))) { throw new AssertionError(); } } @Test public void testStoreByValue() { CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(false); cacheManager.init(); DefaultCopierConfiguration<String> copierConfiguration = new DefaultCopierConfiguration<String>( SerializingCopier.<String>asCopierClass(), DefaultCopierConfiguration.Type.VALUE); final Cache<Long, String> cache1 = cacheManager.createCache("cache1", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, heap(1)) .build()); performAssertions(cache1, true); final Cache<Long, String> cache2 = cacheManager.createCache("cache2", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, heap(1)) .add(copierConfiguration) .build()); performAssertions(cache2, false); final Cache<Long, String> cache3 = cacheManager.createCache("cache3", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, heap(1)) .build()); performAssertions(cache3, true); cacheManager.close(); } @Override protected <K, V> OnHeapStore<K, V> newStore(TimeSource timeSource, Expiry<? super K, ? super V> expiry, EvictionAdvisor<? super K, ? super V> evictionAdvisor) { Copier<K> keyCopier = new SerializingCopier<K>(new JavaSerializer<K>(getClass().getClassLoader())); Copier<V> valueCopier = new SerializingCopier<V>(new JavaSerializer<V>(getClass().getClassLoader())); return newStore(timeSource, expiry, evictionAdvisor, keyCopier, valueCopier, 100); } protected abstract <K, V> OnHeapStore<K, V> newStore(TimeSource timeSource, Expiry<? super K, ? super V> expiry, EvictionAdvisor<? super K, ? super V> evictionAdvisor, Copier<K> keyCopier, Copier<V> valueCopier, int capacity); private void performAssertions(Cache<Long, String> cache, boolean same) { cache.put(1L, "one"); String s1 = cache.get(1L); String s2 = cache.get(1L); String s3 = cache.get(1L); assertThat(s1 == s2, is(same)); assertThat(s2 == s3, is(same)); } }