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