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