View Javadoc
1   /**
2    * This file Copyright (c) 2017-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.cache.ehcache3.setup;
35  
36  import info.magnolia.jcr.util.NodeTypes;
37  import info.magnolia.jcr.util.NodeUtil;
38  import info.magnolia.jcr.util.PropertyUtil;
39  import info.magnolia.module.InstallContext;
40  import info.magnolia.module.cache.ehcache3.EhCache3Factory;
41  import info.magnolia.module.cache.ehcache3.configuration.EhCache3ConfigurationBuilder;
42  import info.magnolia.module.cache.ehcache3.configuration.EhCache3Expiry;
43  import info.magnolia.module.cache.ehcache3.configuration.Ehcache3ResourcePoolBuilder;
44  import info.magnolia.module.cache.ehcache3.configuration.Ehcache3ResourcePoolsBuilder;
45  import info.magnolia.module.delta.AbstractRepositoryTask;
46  import info.magnolia.module.delta.RemoveNodeTask;
47  import info.magnolia.module.delta.TaskExecutionException;
48  
49  import java.io.Serializable;
50  
51  import javax.jcr.Node;
52  import javax.jcr.NodeIterator;
53  import javax.jcr.Property;
54  import javax.jcr.RepositoryException;
55  import javax.jcr.Session;
56  
57  import org.ehcache.config.ResourceType;
58  import org.ehcache.config.units.EntryUnit;
59  import org.ehcache.config.units.MemoryUnit;
60  
61  /**
62   * <code>VersionHandler</code> implementation for the EhCache3 module.
63   */
64  public class MigrateEhCache2ConfigurationTask extends AbstractRepositoryTask {
65  
66      private static final String[] NOT_SUPPORTED_PROPERTIES = new String[]{
67              "diskSpoolBufferSizeMB",
68              "diskExpiryThreadIntervalSeconds",
69              "memoryStoreEvictionPolicy",
70              "timeToIdleSeconds",
71      };
72  
73      public MigrateEhCache2ConfigurationTask() {
74          super("EhCache persistence settings", "Migrates Ehcache 2.x config to Ehcache 3.x");
75      }
76  
77      @Override
78      protected void doExecute(InstallContext ctx) throws RepositoryException, TaskExecutionException {
79          final Session session = ctx.getConfigJCRSession();
80          final Node ehCacheFactory = session.getNode("/modules/cache/config/cacheFactory/delegateFactories/ehcache/");
81          final Property factoryClass = PropertyUtil.getPropertyOrNull(ehCacheFactory, "class");
82          if (!"info.magnolia.module.cache.ehcache.EhCacheFactory".equals(factoryClass.getString())) {
83              ctx.warn(String.format("Cannot migrate EhCache 2.x to EhCache3.x, expected {%s/%s}} but got {%s}", "/modules/cache/config/cacheFactory/class", "info.magnolia.module.cache.ehcache.EhCacheFactory", factoryClass.getString()));
84              return;
85          }
86          factoryClass.setValue(EhCache3Factory.class.getName());
87  
88          NodeUtil.renameNode(ehCacheFactory, "ehcache3");
89  
90          NodeIterator cachesIterator = ehCacheFactory.getNode("caches").getNodes();
91          while (cachesIterator.hasNext()) {
92              final Node cache = cachesIterator.nextNode();
93              cache.setProperty("class", EhCache3ConfigurationBuilder.class.getName());
94              cache.setProperty("keyType", Serializable.class.getName());
95              cache.setProperty("valueType", Serializable.class.getName());
96  
97              final Node expiry = cache.addNode("expiry", NodeTypes.ContentNode.NAME);
98              expiry.setProperty("class", EhCache3Expiry.class.getName());
99              final String timeToLiveSeconds = getValueAndRemove(cache, "timeToLiveSeconds", null);
100             final String eternal = getValueAndRemove(cache, "eternal", Boolean.FALSE.toString());
101             if (Boolean.FALSE.toString().equals(eternal) && timeToLiveSeconds != null) {
102                 expiry.setProperty("create", Long.valueOf(timeToLiveSeconds));
103             }
104             final Node resourcePoolsBuilder = cache.addNode("resourcePoolsBuilder", NodeTypes.ContentNode.NAME);
105             resourcePoolsBuilder.setProperty("class", Ehcache3ResourcePoolsBuilder.class.getName());
106             final Node resourcePools = resourcePoolsBuilder.addNode("pools", NodeTypes.ContentNode.NAME);
107 
108             final Node heap = resourcePools.addNode("heap", NodeTypes.ContentNode.NAME);
109             heap.setProperty("class", Ehcache3ResourcePoolBuilder.class.getName());
110             heap.setProperty("resourceType", ResourceType.Core.HEAP.name());
111             heap.setProperty("resourceUnit", EntryUnit.ENTRIES.name());
112             heap.setProperty("size", Long.valueOf(getValueAndRemove(cache, "maxElementsInMemory", "10000")));
113 
114             final Boolean overflowToOffHeap = Boolean.valueOf(getValueAndRemove(cache, "overflowToOffHeap", Boolean.FALSE.toString()));
115             if (overflowToOffHeap) {
116                 final String maxBytesLocalOffHeap = getValueAndRemove(cache, "maxBytesLocalOffHeap", null);
117                 final Node offHeap = resourcePools.addNode("offheap", NodeTypes.ContentNode.NAME);
118                 offHeap.setProperty("class", Ehcache3ResourcePoolBuilder.class.getName());
119                 offHeap.setProperty("resourceType", ResourceType.Core.OFFHEAP.name());
120                 offHeap.setProperty("resourceUnit", MemoryUnit.MB.name());
121                 offHeap.setProperty("size", Long.valueOf(maxBytesLocalOffHeap) / 1000000);
122             }
123 
124             //remove not supported properties
125             for (String property : NOT_SUPPORTED_PROPERTIES) {
126                 getValueAndRemove(cache, property, null);
127             }
128 
129             final Node persistence = cache.getNode("persistence");
130             final String strategy = getValueAndRemove(persistence, "strategy", "LOCALTEMPSWAP").toUpperCase();
131             persistence.remove();
132             if ("DISTRIBUTED".equals(strategy)) {
133                 ctx.warn(String.format("You are using {DISTRIBUTED} persistence. You have to extend {%s} and set up a clustered cache manager according to {%s} to support distributed configuration.", "info.magnolia.module.cache.ehcache3.EhCache3Factory.init()", "http://www.ehcache.org/documentation/3.3/clustered-cache.html#creating-a-cache-manager-with-clustering-capabilities"));
134             } else if (!"NONE".equals(strategy)) {
135                 final Node disk = resourcePools.addNode("disk", NodeTypes.ContentNode.NAME);
136                 disk.setProperty("class", Ehcache3ResourcePoolBuilder.class.getName());
137                 disk.setProperty("persistent", Boolean.TRUE);
138                 disk.setProperty("resourceType", ResourceType.Core.DISK.name());
139                 disk.setProperty("resourceUnit", MemoryUnit.MB.name());
140                 disk.setProperty("size", Long.valueOf(getValueAndRemove(cache, "maxElementsOnDisk", "10000000")) / 10000);
141             }
142         }
143         new RemoveNodeTask("", "/modules/ehcache").execute(ctx);
144     }
145 
146     private String getValueAndRemove(Node node, String propertyName, String defaultValue) throws RepositoryException {
147         String value = defaultValue;
148         if (node.hasProperty(propertyName)) {
149             final Property maxElementsInMemoryProperty = node.getProperty(propertyName);
150             value = maxElementsInMemoryProperty.getString();
151             maxElementsInMemoryProperty.remove();
152         }
153         return value;
154     }
155 }