View Javadoc
1   /**
2    * This file Copyright (c) 2003-2017 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.setup;
35  
36  import info.magnolia.context.MgnlContext;
37  import info.magnolia.jcr.util.NodeTypes;
38  import info.magnolia.module.DefaultModuleVersionHandler;
39  import info.magnolia.module.InstallContext;
40  import info.magnolia.module.cache.AbstractCacheModule;
41  import info.magnolia.module.delta.AbstractRepositoryTask;
42  import info.magnolia.module.delta.ArrayDelegateTask;
43  import info.magnolia.module.delta.BootstrapSingleModuleResource;
44  import info.magnolia.module.delta.BootstrapSingleResource;
45  import info.magnolia.module.delta.CheckAndModifyPropertyValueTask;
46  import info.magnolia.module.delta.CheckOrCreatePropertyTask;
47  import info.magnolia.module.delta.DeltaBuilder;
48  import info.magnolia.module.delta.FilterOrderingTask;
49  import info.magnolia.module.delta.HasPropertyDelegateTask;
50  import info.magnolia.module.delta.MoveNodeTask;
51  import info.magnolia.module.delta.NodeExistsDelegateTask;
52  import info.magnolia.module.delta.OrderNodeToFirstPositionTask;
53  import info.magnolia.module.delta.PartialBootstrapTask;
54  import info.magnolia.module.delta.RemoveNodeTask;
55  import info.magnolia.module.delta.RemoveNodeWoChildren;
56  import info.magnolia.module.delta.RemoveNodesTask;
57  import info.magnolia.module.delta.RemovePropertyTask;
58  import info.magnolia.module.delta.RenameNodeTask;
59  import info.magnolia.module.delta.RenamePropertyTask;
60  import info.magnolia.module.delta.SetPropertyTask;
61  import info.magnolia.module.delta.Task;
62  import info.magnolia.module.delta.TaskExecutionException;
63  import info.magnolia.repository.RepositoryConstants;
64  import info.magnolia.voting.voters.URIStartsWithVoter;
65  
66  import java.util.ArrayList;
67  import java.util.Arrays;
68  import java.util.List;
69  
70  import javax.jcr.Node;
71  import javax.jcr.RepositoryException;
72  import javax.jcr.Session;
73  
74  /**
75   * <code>VersionHandler</code> implementation for the cache module.
76   */
77  public class CacheModuleVersionHandler extends DefaultModuleVersionHandler {
78  
79      protected static final String OBSOLETE_COMPRESSIBLE_CONFIGURATION_PATH = "modules/cache/config/configurations/default/executors/store/cacheContent/compressible";
80      public static final String CONFIGURATION_PATH = "modules/cache/config/contentCaching/";
81      protected static final String OBSOLETE_DEFAULT_CONFIGURATION_PATH = "/modules/cache/config/configurations/default/";
82      protected static final String BROWSER_CACHE_POLICIES_CONTENT_TYPE_ALLOWED = "/modules/cache/config/contentCaching/defaultPageCache/browserCachePolicy/policies/resources/voters/contentType/allowed";
83  
84      private final FilterOrderingTask placeGzipFilter = new FilterOrderingTask("gzip", new String[]{"context", "multipartRequest"}, new String[]{"activation", "publishing"});
85      private final FilterOrderingTask placeCacheFilter = new FilterOrderingTask("cache", new String[]{"gzip", "range", "i18n"});
86  
87      private final Task addUidlCachePolicy = new AbstractRepositoryTask("Add uidl cache policy voter", "") {
88          final String path = "/modules/cache/config/configurations/default/cachePolicy/voters/deny";
89  
90          @Override
91          protected void doExecute(InstallContext installContext) throws RepositoryException, TaskExecutionException {
92              Session session = MgnlContext.getJCRSession(RepositoryConstants.CONFIG);
93              if (session.nodeExists(path) && !session.nodeExists(path + "/uidl")) {
94                  Node uidlNode = session.getNode(path).addNode("uidl", NodeTypes.ContentNode.NAME);
95                  uidlNode.setProperty("class", URIStartsWithVoter.class.getName());
96                  uidlNode.setProperty("enabled", "true");
97                  uidlNode.setProperty("level", "2");
98                  uidlNode.setProperty("pattern", "/.magnolia/admincentral/UIDL");
99              }
100         }
101     };
102 
103     public CacheModuleVersionHandler() {
104         register(DeltaBuilder.checkPrecondition("4.4.6", "4.5"));
105 
106         register(DeltaBuilder.update("4.5", "")
107                 .addTask(placeGzipFilter)
108                 .addTask(placeCacheFilter)
109         );
110 
111         register(DeltaBuilder.update("5.1.1", "")
112                 .addTask(new RemovePropertyTask("Remove hardcoded label", "Remove hardcoded label of Cache tools app", RepositoryConstants.CONFIG, "/modules/ui-admincentral/apps/cacheTools", "label"))
113                 .addTask(new RemovePropertyTask("Remove hardcoded icon", "Remove hardcoded icon of Cache tools app", RepositoryConstants.CONFIG, "/modules/ui-admincentral/apps/cacheTools", "icon")));
114 
115         register(DeltaBuilder.update("5.2", "")
116                 .addTask(addUidlCachePolicy)
117         );
118 
119         register(DeltaBuilder.update("5.4", "")
120 
121                 .addTask(new ArrayDelegateTask("Remove deprecated configuration",
122                         new RemoveNodeTask("Remove obsolete compressible configuration.", "/" + OBSOLETE_COMPRESSIBLE_CONFIGURATION_PATH),
123                         new MoveNodeTask("", OBSOLETE_DEFAULT_CONFIGURATION_PATH + "cachePolicy/voters", OBSOLETE_DEFAULT_CONFIGURATION_PATH + "cachePolicy/shouldBypassVoters", false),
124                         new RemoveNodesTask("Remove deprecated cacheable voters",
125                                 RepositoryConstants.CONFIG, Arrays.asList(OBSOLETE_DEFAULT_CONFIGURATION_PATH + "executors/store/cacheContent/isCacheableVoters"), false)
126                 ))
127 
128                 .addTask(new ArrayDelegateTask("Renaming of 'configurations' to 'contentCaching'",
129                         String.format("Renames the 'configurations' nodes of the cache module to 'contentCaching'. Also renames the 'cacheConfigurationName' property of the cache filter to '%s'.", AbstractCacheModule.DEFAULT_CACHE_CONFIG),
130                         new RenameNodeTask("", RepositoryConstants.CONFIG, "/modules/cache/config", "configurations", "contentCaching", false),
131                         new RenameNodeTask("", RepositoryConstants.CONFIG, "/modules/cache/config/contentCaching", "default", "defaultPageCache", false),
132                         // incorrect update task fixed by MigrateCacheFilterConfigurationTask in 5.4.1 delta
133                         new RenamePropertyTask("", RepositoryConstants.CONFIG, "/server/filters/cache", "cacheConfigurationName", AbstractCacheModule.DEFAULT_CACHE_CONFIG, false),
134                         new CheckAndModifyPropertyValueTask("", "", RepositoryConstants.CONFIG, "/server/filters/cache", AbstractCacheModule.DEFAULT_CACHE_CONFIG, "default", "defaultPageCache")
135                         // end of incorrect part
136                 ))
137 
138                 .addTask(new ArrayDelegateTask("Bootstrap new configuration",
139                         new BootstrapSingleResource("Bootstrap voters for TTL", "Bootstrap voters for Time To Live", "/mgnl-bootstrap/cache/config.modules.cache.config.contentCaching.defaultPageCache.cachePolicy.ttlVoters.xml"),
140                         new PartialBootstrapTask("Rebootstrap new default flush cache policy configuration",
141                                 "/mgnl-bootstrap/cache/config.modules.cache.config.contentCaching.defaultPageCache.xml", "defaultPageCache/flushPolicy/policies/flushAll"),
142                         new PartialBootstrapTask("Rebootstrap new uuid-key-mapping flush cache policy configuration",
143                                 "/mgnl-bootstrap/cache/config.modules.cache.config.contentCaching.uuid-key-mapping.xml", "uuid-key-mapping/flushPolicy/policies/flushAll")
144                 ))
145 
146                 .addTask(new NodeExistsDelegateTask("Remove old cache tools app", "/modules/ui-admincentral/apps/cacheTools",
147                         new RemoveNodeTask("", "/modules/ui-admincentral/apps/cacheTools")))
148                 .addTask(new NodeExistsDelegateTask("Remove cache tools page", "/modules/cache/pages/cachePage",
149                         new RemoveNodeTask("", "/modules/cache/pages/cachePage")))
150                 .addTask(new RemoveNodeWoChildren("Remove pages node if there are no pages registered.", "/modules/cache/pages"))
151                 .addTask(new RemoveVirtualUriMappingTask())
152                 .addTask(new CheckAndModifyPropertyValueTask("Browser cache policy for far-future caching", "Fixes pattern for far-future browser cache policy.", RepositoryConstants.CONFIG, "/modules/cache/config/contentCaching/defaultPageCache/browserCachePolicy/policies/farFuture/voters/dotCacheExtension", "pattern", ".*\\.cache\\.[^\\.]*", ".*[~.]cache\\.[^\\.]*"))
153         );
154 
155         register(DeltaBuilder.update("5.4.1", "")
156                 .addTask(new MigrateCacheFilterConfigurationTask())
157         );
158         register(DeltaBuilder.update("5.5.2", "")
159                 .addTask(new ArrayDelegateTask("Disable browser cache only when magnolia.develop=true",
160                         new RemoveNodeTask("", "/modules/cache/config/contentCaching/defaultPageCache/browserCachePolicy/policies/never"),
161                         new PartialBootstrapTask("", "/mgnl-bootstrap/cache/config.modules.cache.config.contentCaching.defaultPageCache.xml", "/defaultPageCache/browserCachePolicy/policies/disableBrowserCacheInDevelopMode"),
162                         new OrderNodeToFirstPositionTask("", "modules/cache/config/contentCaching/defaultPageCache/browserCachePolicy/policies/disableBrowserCacheInDevelopMode")
163                 ))
164         );
165         register(DeltaBuilder.update("5.5.5", "")
166                 .addTask(new SupportForMultipleCacheImplementationsTask())
167         );
168         register(DeltaBuilder.update("5.6.1", "")
169                 .addTask(new BootstrapSingleModuleResource("config.modules.cache.config.contentCaching.defaultPageCache.flushPolicy.policies.lightModule.xml"))
170                 .addTask(new NodeExistsDelegateTask("If compression config exists, update JS mime types", "/modules/cache/config/compression/voters/contentType/allowed",
171                         new ArrayDelegateTask("Update compression config",
172                         new CheckOrCreatePropertyTask("Add gzip support for new JS mime type", "/modules/cache/config/compression/voters/contentType/allowed", "4", "application/javascript"),
173                         new HasPropertyDelegateTask("If javascript property is present...",
174                                 BROWSER_CACHE_POLICIES_CONTENT_TYPE_ALLOWED,
175                                 "javascript", new ArrayDelegateTask("Rename property and set new value",
176                                 new RenamePropertyTask("Rename old JS mimetype property in caching policy", RepositoryConstants.CONFIG,
177                                         BROWSER_CACHE_POLICIES_CONTENT_TYPE_ALLOWED, "javascript", "x-javascript", true),
178                                 new SetPropertyTask(RepositoryConstants.CONFIG,
179                                         BROWSER_CACHE_POLICIES_CONTENT_TYPE_ALLOWED, "x-javascript", "application/x-javascript"))
180                         ))))
181                 .addTask(new NodeExistsDelegateTask("If default page cache config exists, update JS mime types", BROWSER_CACHE_POLICIES_CONTENT_TYPE_ALLOWED,
182                         new CheckOrCreatePropertyTask("Add support for new JS mimetype in caching policy",
183                                 BROWSER_CACHE_POLICIES_CONTENT_TYPE_ALLOWED,
184                                 "javascript", "application/javascript")))
185         );
186     }
187 
188     @Override
189     protected List<Task> getExtraInstallTasks(InstallContext installContext) {
190         final List<Task> tasks = new ArrayList<Task>();
191         tasks.add(placeGzipFilter);
192         tasks.add(placeCacheFilter);
193         tasks.add(addUidlCachePolicy);
194         return tasks;
195     }
196 
197     @Override
198     protected List<Task> getStartupTasks(InstallContext installContext) {
199         final List<Task> tasks = new ArrayList<Task>();
200         tasks.addAll(super.getStartupTasks(installContext));
201 
202         tasks.add(new RemoveCacheTempFilesTask());
203         return tasks;
204     }
205 }