1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.cache.ehcache3;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.init.MagnoliaConfigurationProperties;
38 import info.magnolia.init.MagnoliaInitPaths;
39 import info.magnolia.module.cache.Cache;
40 import info.magnolia.module.cache.CacheFactory;
41 import info.magnolia.module.cache.CacheModule;
42 import info.magnolia.module.cache.ehcache3.configuration.EhCache3Expiry;
43
44 import java.io.Serializable;
45 import java.util.ArrayList;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.Map;
49
50 import javax.inject.Inject;
51
52 import org.ehcache.CacheManager;
53 import org.ehcache.Status;
54 import org.ehcache.config.Builder;
55 import org.ehcache.config.CacheConfiguration;
56 import org.ehcache.config.builders.CacheConfigurationBuilder;
57 import org.ehcache.config.builders.CacheManagerBuilder;
58 import org.ehcache.config.builders.ResourcePoolsBuilder;
59 import org.ehcache.config.units.EntryUnit;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63
64
65
66 public class EhCache3Factory implements CacheFactory {
67
68 private static final Logger log = LoggerFactory.getLogger(EhCache3Factory.class);
69
70 static final String MAGNOLIA_PROPERTY_CACHE_MANAGER_ID = "magnolia.cache.manager.id";
71
72 private Map<String, Builder<? extends CacheConfiguration>> caches = new HashMap<>();
73 private final Map<String, CacheConfiguration> cachesConfiguration = new HashMap<>();
74 private CacheManager cacheManager;
75
76 private int blockingTimeout = 10000;
77 private String diskStorePath;
78
79 private final CacheModule cacheModule;
80
81 @Inject
82 public EhCache3Factory(CacheModule cacheModule, MagnoliaInitPaths magnoliaInitPaths, MagnoliaConfigurationProperties magnoliaConfigurationProperties) {
83 this.cacheModule = cacheModule;
84 this.diskStorePath = resolveDiskStorePath(magnoliaConfigurationProperties, magnoliaInitPaths);
85 getCaches().put(DEFAULT_CACHE_NAME,
86 CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
87 ResourcePoolsBuilder.newResourcePoolsBuilder()
88 .heap(10000, EntryUnit.ENTRIES)
89 ).withExpiry(new EhCache3Expiry<>())
90 );
91 }
92
93 public void init() {
94 this.cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
95 .with(CacheManagerBuilder.persistence(diskStorePath))
96 .build();
97 }
98
99 @Override
100 public void start(boolean isRestart) {
101 cacheManager.init();
102 }
103
104 @Override
105 public void stop(boolean isRestart) {
106 cacheManager.close();
107 }
108
109 @Override
110 public List<String> getCacheNames() {
111 return new ArrayList<>(cacheManager.getRuntimeConfiguration().getCacheConfigurations().keySet());
112 }
113
114 @Override
115 public Cache getCache(String name) {
116 Cache cache = null;
117 if (cacheManager.getStatus() == Status.AVAILABLE) {
118 final CacheConfiguration cacheConfiguration = getCacheConfiguration(name);
119 final org.ehcache.Cache ehcache = cacheManager.getCache(name, cacheConfiguration.getKeyType(), cacheConfiguration.getValueType());
120
121 if (ehcache == null) {
122
123 createCache(name);
124 cache = getCache(name);
125 } else {
126 cache = wrap(name, ehcache);
127 }
128 } else {
129 log.warn("Cache manager status is {{}} while retrieving cache named {{}}. Returning null.", cacheManager.getStatus(), name);
130 }
131 return cache;
132 }
133
134 private void createCache(String name) {
135 synchronized (this.getClass()) {
136 cacheManager.createCache(name, getCacheConfiguration(name));
137 }
138 }
139
140 private CacheConfiguration getCacheConfiguration(String name) {
141 CacheConfiguration cacheConfiguration;
142 if (cachesConfiguration.containsKey(name)) {
143 cacheConfiguration = cachesConfiguration.get(name);
144 } else {
145 try {
146 cacheConfiguration = getCaches().containsKey(name) ? getCaches().get(name).build() : getCaches().get(DEFAULT_CACHE_NAME).build();
147 } catch (IllegalArgumentException e) {
148 cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Serializable.class, Serializable.class, ResourcePoolsBuilder.heap(10000).build()).build();
149 log.error("Cache {{}} is misconfigured: {{}}. Returning fallback config", name, e.getMessage());
150 }
151 cachesConfiguration.put(name, cacheConfiguration);
152 }
153 return cacheConfiguration;
154 }
155
156
157 private EhCache3Wrapper wrap(String name, org.ehcache.Cache ehcache) {
158 return new EhCache3Wrapper(name, cacheModule, getBlockingTimeout(), ehcache);
159 }
160
161 public static String resolveDiskStorePath(MagnoliaConfigurationProperties magnoliaConfigurationProperties, MagnoliaInitPaths magnoliaInitPaths) {
162 return Path.getCacheDirectoryPath() + getCacheManagerIdentifier(magnoliaConfigurationProperties, magnoliaInitPaths);
163 }
164
165 private static String getCacheManagerIdentifier(MagnoliaConfigurationProperties magnoliaConfigurationProperties, MagnoliaInitPaths magnoliaInitPaths) {
166 if (magnoliaConfigurationProperties.hasProperty(MAGNOLIA_PROPERTY_CACHE_MANAGER_ID)) {
167 return magnoliaConfigurationProperties.getProperty(MAGNOLIA_PROPERTY_CACHE_MANAGER_ID);
168 } else {
169 return magnoliaInitPaths.getContextPath();
170 }
171 }
172
173 public Map<String, Builder<? extends CacheConfiguration>> getCaches() {
174 return caches;
175 }
176
177 public void setCaches(Map<String, Builder<? extends CacheConfiguration>> caches) {
178 this.caches = caches;
179 }
180
181 public String getDiskStorePath() {
182 return diskStorePath;
183 }
184
185 public void setDiskStorePath(String diskStorePath) {
186 this.diskStorePath = diskStorePath;
187 }
188
189 public int getBlockingTimeout() {
190 return blockingTimeout;
191 }
192
193 public void setBlockingTimeout(int blockingTimeout) {
194 this.blockingTimeout = blockingTimeout;
195 }
196
197 }