/*
* 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.docs;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.PersistentCacheManager;
import org.ehcache.ValueSupplier;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.builders.WriteBehindConfigurationBuilder;
import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.docs.plugs.ListenerObject;
import org.ehcache.expiry.Duration;
import org.ehcache.expiry.Expirations;
import org.ehcache.expiry.Expiry;
import org.ehcache.impl.serialization.JavaSerializer;
import org.ehcache.docs.plugs.OddKeysEvictionAdvisor;
import org.ehcache.docs.plugs.SampleLoaderWriter;
import org.ehcache.event.EventFiring;
import org.ehcache.event.EventOrdering;
import org.ehcache.event.EventType;
import org.ehcache.impl.copy.ReadWriteCopier;
import org.junit.Test;
import java.io.File;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.util.EnumSet;
import java.util.concurrent.TimeUnit;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* Samples to get started with Ehcache 3
*
* If you add new examples, you should use tags to have them included in the README.adoc
* You need to edit the README.adoc too to add your new content.
* The callouts are also used in docs/user/index.adoc
*/
@SuppressWarnings("unused")
public class GettingStarted {
@Test
public void cachemanagerExample() {
// tag::cachemanagerExample[]
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder() // <1>
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))) // <2>
.build(); // <3>
cacheManager.init(); // <4>
Cache<Long, String> preConfigured =
cacheManager.getCache("preConfigured", Long.class, String.class); // <5>
Cache<Long, String> myCache = cacheManager.createCache("myCache", // <6>
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));
myCache.put(1L, "da one!"); // <7>
String value = myCache.get(1L); // <8>
cacheManager.removeCache("preConfigured"); // <9>
cacheManager.close(); // <10>
// end::cachemanagerExample[]
}
@Test
public void threeTiersCacheManager() throws Exception {
// tag::threeTiersCacheManager[]
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(new File(getStoragePath(), "myData"))) // <1>
.withCache("threeTieredCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES) // <2>
.offheap(1, MemoryUnit.MB) // <3>
.disk(20, MemoryUnit.MB, true) // <4>
)
).build(true);
Cache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class, String.class);
threeTieredCache.put(1L, "stillAvailableAfterRestart"); // <5>
persistentCacheManager.close();
// end::threeTiersCacheManager[]
}
@Test
public void testCacheEventListener() {
// tag::cacheEventListener[]
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(new ListenerObject(), EventType.CREATED, EventType.UPDATED) // <1>
.unordered().asynchronous(); // <2>
final CacheManager manager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("foo",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class, ResourcePoolsBuilder.heap(10))
.add(cacheEventListenerConfiguration) // <3>
).build(true);
final Cache<String, String> cache = manager.getCache("foo", String.class, String.class);
cache.put("Hello", "World"); // <4>
cache.put("Hello", "Everyone"); // <5>
cache.remove("Hello"); // <6>
// end::cacheEventListener[]
manager.close();
}
@Test
public void writeThroughCache() throws ClassNotFoundException {
// tag::writeThroughCache[]
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);
Cache<Long, String> writeThroughCache = cacheManager.createCache("writeThroughCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))
.withLoaderWriter(new SampleLoaderWriter<Long, String>(singletonMap(41L, "zero"))) // <1>
.build());
assertThat(writeThroughCache.get(41L), is("zero")); // <2>
writeThroughCache.put(42L, "one"); // <3>
assertThat(writeThroughCache.get(42L), equalTo("one"));
cacheManager.close();
// end::writeThroughCache[]
}
@Test
public void writeBehindCache() throws ClassNotFoundException {
// tag::writeBehindCache[]
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);
Cache<Long, String> writeBehindCache = cacheManager.createCache("writeBehindCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))
.withLoaderWriter(new SampleLoaderWriter<Long, String>(singletonMap(41L, "zero"))) // <1>
.add(WriteBehindConfigurationBuilder // <2>
.newBatchedWriteBehindConfiguration(1, TimeUnit.SECONDS, 3)// <3>
.queueSize(3)// <4>
.concurrencyLevel(1) // <5>
.enableCoalescing()) // <6>
.build());
assertThat(writeBehindCache.get(41L), is("zero"));
writeBehindCache.put(42L, "one");
writeBehindCache.put(43L, "two");
writeBehindCache.put(42L, "This goes for the record");
assertThat(writeBehindCache.get(42L), equalTo("This goes for the record"));
cacheManager.close();
// end::writeBehindCache[]
}
@Test
public void registerListenerAtRuntime() throws InterruptedException {
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(10L)))
.build(true);
Cache<Long, String> cache = cacheManager.getCache("cache", Long.class, String.class);
// tag::registerListenerAtRuntime[]
ListenerObject listener = new ListenerObject(); // <1>
cache.getRuntimeConfiguration().registerCacheEventListener(listener, EventOrdering.ORDERED,
EventFiring.ASYNCHRONOUS, EnumSet.of(EventType.CREATED, EventType.REMOVED)); // <2>
cache.put(1L, "one");
cache.put(2L, "two");
cache.remove(1L);
cache.remove(2L);
cache.getRuntimeConfiguration().deregisterCacheEventListener(listener); // <3>
cache.put(1L, "one again");
cache.remove(1L);
// end::registerListenerAtRuntime[]
cacheManager.close();
}
@Test
public void configuringEventProcessing() {
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(ListenerObject.class, EventType.EVICTED).ordered().synchronous();
// tag::configuringEventProcessingQueues[]
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(5L))
.withDispatcherConcurrency(10) // <1>
.withEventListenersThreadPool("listeners-pool")
.build();
// end::configuringEventProcessingQueues[]
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache("cache", cacheConfiguration)
.build(true);
cacheManager.close();
}
@Test
public void cacheEvictionAdvisor() throws Exception {
// tag::cacheEvictionAdvisor[]
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(2L)) // <1>
.withEvictionAdvisor(new OddKeysEvictionAdvisor<Long, String>()) // <2>
.build();
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("cache", cacheConfiguration)
.build(true);
Cache<Long, String> cache = cacheManager.getCache("cache", Long.class, String.class);
// Work with the cache
cache.put(42L, "The Answer!");
cache.put(41L, "The wrong Answer!");
cache.put(39L, "The other wrong Answer!");
cacheManager.close();
// end::cacheEvictionAdvisor[]
}
@Test
public void expiry() throws Exception {
// tag::expiry[]
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100)) // <1>
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.SECONDS))) // <2>
.build();
// end::expiry[]
}
@Test
public void customExpiry() throws Exception {
// tag::customExpiry[]
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.withExpiry(new CustomExpiry()) // <1>
.build();
// end::customExpiry[]
}
private static class Description {
int id;
String alias;
Description(Description other) {
this.id = other.id;
this.alias = other.alias;
}
Description(int id, String alias) {
this.id = id;
this.alias = alias;
}
@Override
public boolean equals(final Object other) {
if(this == other) return true;
if(other == null || this.getClass() != other.getClass()) return false;
Description that = (Description)other;
if(id != that.id) return false;
if ((alias == null) ? (alias != null) : !alias.equals(that.alias)) return false;
return true;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + id;
result = 31 * result + (alias == null ? 0 : alias.hashCode());
return result;
}
}
private static class Person implements Serializable {
String name;
int age;
Person(Person other) {
this.name = other.name;
this.age = other.age;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(final Object other) {
if(this == other) return true;
if(other == null || this.getClass() != other.getClass()) return false;
Person that = (Person)other;
if(age != that.age) return false;
if((name == null) ? (that.name != null) : !name.equals(that.name)) return false;
return true;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + age;
result = 31 * result + (name == null ? 0 : name.hashCode());
return result;
}
}
public static class DescriptionCopier extends ReadWriteCopier<Description> {
@Override
public Description copy(final Description obj) {
return new Description(obj);
}
}
public static class PersonCopier extends ReadWriteCopier<Person> {
@Override
public Person copy(final Person obj) {
return new Person(obj);
}
}
static class PersonSerializer extends JavaSerializer<Person> {
public PersonSerializer() {
super(ClassLoader.getSystemClassLoader());
}
}
private String getStoragePath() throws URISyntaxException {
return getClass().getClassLoader().getResource(".").toURI().getPath();
}
public static class CustomExpiry implements Expiry<Long, String> {
@Override
public Duration getExpiryForCreation(Long key, String value) {
throw new UnsupportedOperationException("TODO Implement me!");
}
@Override
public Duration getExpiryForAccess(Long key, ValueSupplier<? extends String> value) {
throw new UnsupportedOperationException("TODO Implement me!");
}
@Override
public Duration getExpiryForUpdate(Long key, ValueSupplier<? extends String> oldValue, String newValue) {
throw new UnsupportedOperationException("TODO Implement me!");
}
}
}