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.ehcache;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.cms.util.DeprecationUtil;
38 import info.magnolia.cms.util.MBeanUtil;
39 import info.magnolia.init.MagnoliaInitPaths;
40 import info.magnolia.module.cache.Cache;
41 import info.magnolia.module.cache.CacheFactory;
42 import info.magnolia.module.cache.CacheModule;
43 import info.magnolia.module.cache.mbean.CacheMonitor;
44 import info.magnolia.objectfactory.Components;
45
46 import java.util.Arrays;
47 import java.util.HashMap;
48 import java.util.List;
49 import java.util.Map;
50
51 import javax.inject.Inject;
52 import javax.management.MBeanServer;
53
54 import org.apache.commons.lang3.StringUtils;
55
56 import net.sf.ehcache.CacheManager;
57 import net.sf.ehcache.Ehcache;
58 import net.sf.ehcache.config.Configuration;
59 import net.sf.ehcache.config.DiskStoreConfiguration;
60 import net.sf.ehcache.config.generator.ConfigurationSource;
61 import net.sf.ehcache.constructs.blocking.BlockingCache;
62 import net.sf.ehcache.management.ManagementService;
63
64
65
66
67 public class EhCacheFactory implements CacheFactory {
68 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EhCacheFactory.class);
69
70 private final CacheMonitor cacheMonitor;
71
72 private CacheManager cacheManager;
73 private CacheModule cacheModule;
74 private MagnoliaInitPaths magnoliaInitPaths;
75 private Map<String, EhCacheConfiguration> caches = new HashMap<String, EhCacheConfiguration>();
76 private String diskStorePath;
77
78 private int blockingTimeout = 10000;
79
80 @Inject
81 public EhCacheFactory(CacheMonitor cacheMonitor, CacheModule cacheModule, MagnoliaInitPaths magnoliaInitPaths) {
82 this.cacheMonitor = cacheMonitor;
83 this.cacheModule = cacheModule;
84 this.magnoliaInitPaths = magnoliaInitPaths;
85 diskStorePath = Path.getCacheDirectoryPath();
86 }
87
88
89
90
91 public EhCacheFactory(CacheMonitor cacheMonitor) {
92 this(cacheMonitor, Components.getComponent(CacheModule.class), Components.getComponent(MagnoliaInitPaths.class));
93 }
94
95 @Deprecated
96 public EhCacheConfiguration getDefaultCacheConfiguration() {
97 DeprecationUtil.isDeprecated("Code should not be calling info.magnolia.module.cache.ehcache.EhCacheFactory#getDefaultCacheConfiguration");
98 return getCaches().get(DEFAULT_CACHE_NAME);
99 }
100
101
102 @Deprecated
103 public void setDefaultCacheConfiguration(EhCacheConfiguration defaultCacheConfiguration) {
104 if (!isDefaultCacheName(defaultCacheConfiguration.getName())) {
105 log.warn("Calling setDefaultCacheConfiguration with a CacheConfiguration of name " + defaultCacheConfiguration.getName() + "; it should be unnamed.");
106 }
107 if (!getCaches().containsKey(DEFAULT_CACHE_NAME)) {
108 DeprecationUtil.isDeprecated("Configure your default cache settings under modules/cache/configuration/cacheFactory/caches/default rather than modules/cache/configuration/cacheFactory/defaultCacheConfiguration");
109 getCaches().put(DEFAULT_CACHE_NAME, defaultCacheConfiguration);
110 } else {
111 log.warn("You already have a configuration at modules/cache/configuration/cacheFactory/caches/default, ignoring modules/cache/configuration/cacheFactory/defaultCacheConfiguration");
112 }
113 }
114
115
116
117
118 public Map<String, EhCacheConfiguration> getCaches() {
119 return caches;
120 }
121
122 public void setCaches(Map<String, EhCacheConfiguration> caches) {
123 this.caches = caches;
124 }
125
126 public String getDiskStorePath() {
127 return diskStorePath;
128 }
129
130 public void setDiskStorePath(String diskStorePath) {
131 this.diskStorePath = diskStorePath;
132 }
133
134 public int getBlockingTimeout() {
135 return blockingTimeout;
136 }
137
138 public void setBlockingTimeout(int blockingTimeout) {
139 this.blockingTimeout = blockingTimeout;
140 }
141
142
143
144
145 @Override
146 public List getCacheNames() {
147 return Arrays.asList(cacheManager.getCacheNames());
148 }
149
150 @Override
151 public Cache getCache(String name) {
152 if (isDefaultCacheName(name)) {
153 throw new IllegalArgumentException("'" + name + "' is not a valid cache name.");
154 }
155 Ehcache ehcache = cacheManager.getEhcache(name);
156
157
158 if (ehcache == null) {
159
160 createCache(name);
161 return getCache(name);
162 }
163
164
165 if (!(ehcache instanceof BlockingCache)) {
166 ehcache = decorateAndSubstitute(ehcache);
167 }
168 return wrap(name, ehcache);
169 }
170
171
172 protected void createCache(String name) {
173 synchronized (this.getClass()) {
174 cacheManager.addCache(name);
175 }
176 }
177
178 protected BlockingCache decorateAndSubstitute(Ehcache ehcache) {
179 synchronized (this.getClass()) {
180 BlockingCache newBlockingCache = new BlockingCache(ehcache);
181 newBlockingCache.setTimeoutMillis(getBlockingTimeout());
182 cacheManager.replaceCacheWithDecoratedCache(ehcache, newBlockingCache);
183 return newBlockingCache;
184 }
185 }
186
187 protected EhCacheWrapper wrap(String name, Ehcache ehcache) {
188 return new EhCacheWrapper(cacheModule, ehcache, cacheMonitor, name);
189 }
190
191 private boolean isDefaultCacheName(String name) {
192 return DEFAULT_CACHE_NAME.equals(name) || name == null;
193 }
194
195 @Override
196 public void start(boolean isRestart) {
197 final Configuration cfg = new Configuration();
198
199
200 for (EhCacheConfiguration cacheConfig : caches.values()) {
201
202 if (!isDefaultCacheName(cacheConfig.getName())) {
203 cfg.addCache(cacheConfig);
204 }
205 }
206
207 EhCacheConfiguration defaultCacheConfiguration = caches.get(DEFAULT_CACHE_NAME);
208 if (defaultCacheConfiguration != null) {
209
210 defaultCacheConfiguration.resetName();
211 } else {
212 log.warn("Default cache configuration is not set.");
213 defaultCacheConfiguration = new EhCacheConfiguration();
214 defaultCacheConfiguration.setMaxEntriesLocalHeap(10000);
215 }
216 cfg.setDefaultCacheConfiguration(defaultCacheConfiguration);
217
218
219 if (!caches.isEmpty()) {
220 cfg.setSource(new DescribingConfigurationSource("Magnolia-based cache configuration"));
221 }
222 if (diskStorePath != null) {
223 cfg.diskStore(new DiskStoreConfiguration().path(diskStorePath));
224 cfg.setSource(new DescribingConfigurationSource("Magnolia-based diskStorePath"));
225 }
226 cfg.setName(this.getCacheManagerIdentifier());
227 cacheManager = CacheManager.getCacheManager(cfg.getName());
228 if (cacheManager == null) {
229 cacheManager = new CacheManager(cfg);
230 final MBeanServer mBeanServer = MBeanUtil.getMBeanServer();
231 ManagementService.registerMBeans(cacheManager, mBeanServer, true, true, true, true, false);
232 }
233 }
234
235 private String getCacheManagerIdentifier() {
236 return StringUtils.removeStart(magnoliaInitPaths.getContextPath(), "/") + "#" + getClass().getName() + "#cacheManager";
237 }
238
239 @Override
240 public void stop(boolean isRestart) {
241 if (!isRestart) {
242 cacheManager.shutdown();
243 }
244 }
245
246 public CacheManager getWrappedCacheManager() {
247 return cacheManager;
248 }
249
250 private static final class DescribingConfigurationSource extends ConfigurationSource {
251 private final String description;
252
253 private DescribingConfigurationSource(String description) {
254 this.description = description;
255 }
256
257 @Override
258 public Configuration createConfiguration() {
259 throw new IllegalStateException("not implemented - not needed");
260 }
261
262 @Override
263 public String toString() {
264 return description;
265 }
266 }
267 }