View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 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.cms.beans.config.ContentRepository;
37  import info.magnolia.cms.core.Content;
38  import info.magnolia.cms.core.HierarchyManager;
39  import info.magnolia.cms.core.ItemType;
40  import info.magnolia.module.DefaultModuleVersionHandler;
41  import info.magnolia.module.InstallContext;
42  import info.magnolia.module.cache.RegisterWorkspaceForCacheFlushingTask;
43  import info.magnolia.module.delta.AbstractRepositoryTask;
44  import info.magnolia.module.delta.ArrayDelegateTask;
45  import info.magnolia.module.delta.BackupTask;
46  import info.magnolia.module.delta.BootstrapConditionally;
47  import info.magnolia.module.delta.BootstrapResourcesTask;
48  import info.magnolia.module.delta.BootstrapSingleResource;
49  import info.magnolia.module.delta.CheckAndModifyPropertyValueTask;
50  import info.magnolia.module.delta.Condition;
51  import info.magnolia.module.delta.CreateNodeTask;
52  import info.magnolia.module.delta.DeltaBuilder;
53  import info.magnolia.module.delta.FilterOrderingTask;
54  import info.magnolia.module.delta.MoveNodeTask;
55  import info.magnolia.module.delta.NewPropertyTask;
56  import info.magnolia.module.delta.NodeExistsDelegateTask;
57  import info.magnolia.module.delta.PropertyExistsDelegateTask;
58  import info.magnolia.module.delta.RemoveNodeTask;
59  import info.magnolia.module.delta.RemovePropertyTask;
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.module.delta.WarnTask;
64  import info.magnolia.module.delta.WebXmlConditionsUtil;
65  
66  import java.util.ArrayList;
67  import java.util.List;
68  
69  import javax.jcr.RepositoryException;
70  
71  /**
72   * <code>VersionHandler</code> implementation for the cache module.
73   * @author fgiust
74   * @author gjoseph
75   * @version $Revision: $ ($Author: $)
76   */
77  public class CacheModuleVersionHandler extends DefaultModuleVersionHandler {
78  
79      public CacheModuleVersionHandler() {
80          super();
81          final List<Condition> conditions = new ArrayList<Condition>();
82          final WebXmlConditionsUtil u = new WebXmlConditionsUtil(conditions);
83          u.servletIsRemoved("CacheServlet");
84          u.servletIsRemoved("CacheGeneratorServlet");
85          register(DeltaBuilder.update("3.5.0", "").addConditions(conditions)
86                  // bootstrap file removed - and not needed even if we're upgrading from 3.0
87                  // .addTask(new BootstrapSingleResource("Configured Observation", "Adds the repositories to be observed.", "/mgnl-bootstrap/cache/config.modules.cache.config.repositories.xml"))
88          );
89  
90          final NodeExistsDelegateTask addFilterIfNotExisting = new NodeExistsDelegateTask("Check cache filter", "A bug in previous 3.5 releases made it possible for the cache filter to be removed. This task readds it if necessary.",
91                  ContentRepository.CONFIG, "/server/filters/cache", null, new ArrayDelegateTask("",
92                          new BootstrapSingleResource("", "", "/mgnl-bootstrap/cache/config.server.filters.cache.xml"),
93                          new FilterOrderingTask("cache", new String[]{"i18n"}),
94                          new WarnTask("", "The cache filter was not found, and was just added. If you removed it on purpose, you should consider disabling it instead.")));
95  
96          register(DeltaBuilder.update("3.5.9", "")
97                  .addTask(addFilterIfNotExisting)
98          );
99  
100         register(DeltaBuilder.update("3.6", "New cache API and configuration.")
101                 .addTask(new BackupTask("config", "/modules/cache/config", true))
102                 .addTask(new BootstrapResourcesTask("New configuration", "Bootstraps new default cache configuration.") {
103                     protected String[] getResourcesToBootstrap(final InstallContext installContext) {
104                         return new String[]{
105                                 "/mgnl-bootstrap/cache/config.modules.cache.config.configurations.default.xml",
106                                 "/mgnl-bootstrap/cache/config.modules.cache.config.cacheFactory.xml"
107                         };
108                     }
109                 })
110                 .addTask(new ArrayDelegateTask("New cache filter", "Replaces the old cache filter with info.magnolia.module.cache.filter.CacheFilter.",
111                         new CheckAndModifyPropertyValueTask("", "", ContentRepository.CONFIG, "/server/filters/cache", "class", "info.magnolia.cms.cache.CacheFilter", "info.magnolia.module.cache.filter.CacheFilter"),
112                         new NewPropertyTask("", "", ContentRepository.CONFIG, "/server/filters/cache", "cacheConfigurationName", "default")
113                 ))
114                 .addTask(new FilterOrderingTask("cache", "The cache filter should now be placed before the i18n filter.", new String[]{"context", "multipartRequest", "activation"}))
115                 .addTask(new ArrayDelegateTask("New gzip filter", "Adds the new gzip filter.",
116                         new BootstrapSingleResource("", "", "/mgnl-bootstrap/cache/config.server.filters.gzip.xml"),
117                         new FilterOrderingTask("gzip", new String[]{"cache"})
118                 ))
119         );
120 
121         register(DeltaBuilder.update("3.6.2", "Updated executors and filter configuration.")
122                 .addTask(new BootstrapResourcesTask("Updated configuration", "Bootstraps new default cache configuration.") {
123                     protected String[] getResourcesToBootstrap(final InstallContext installContext) {
124                         return new String[]{
125                                 "/mgnl-bootstrap/cache/setup/config.modules.cache.config.configurations.default.executors.store.cacheContent.compressible.xml",
126                                 "/mgnl-bootstrap/cache/setup/config.modules.cache.config.configurations.default.executors.store.serveContent.xml"
127                         };
128                     }
129                 })
130                 .addTask(new FilterOrderingTask("cache", "The gzip filter should now be placed before the cache filter.", new String[]{"gzip"}))
131         );
132 
133         register(DeltaBuilder.update("3.6.4", "Update gzip and cache compression configuration.").addTasks(getTasksFor364()));
134 
135         register(DeltaBuilder.update("4.1", "New flush policy configuration.").addTask(
136                 new ArrayDelegateTask("New flush policy configuration", "Sets up the new flush policy configuration.",
137                         // move existing policy to temp
138                         new MoveNodeTask("","", ContentRepository.CONFIG, "/modules/cache/config/configurations/default/flushPolicy","/modules/cache/config/configurations/default/tmp", false),
139                         // create new policy configuration
140                         new CreateNodeTask("","", ContentRepository.CONFIG, "/modules/cache/config/configurations/default", "flushPolicy", ItemType.CONTENTNODE.getSystemName()),
141                         new SetPropertyTask(ContentRepository.CONFIG,"/modules/cache/config/configurations/default/flushPolicy", "class", "info.magnolia.module.cache.DelegateFlushPolicy"),
142                         new CreateNodeTask("","", ContentRepository.CONFIG, "/modules/cache/config/configurations/default/flushPolicy", "policies", ItemType.CONTENTNODE.getSystemName()),
143                         // move original config under the new one
144                         new MoveNodeTask("","", ContentRepository.CONFIG, "/modules/cache/config/configurations/default/tmp","/modules/cache/config/configurations/default/flushPolicy/policies/flushAll", false)
145                 )));
146 
147         register(DeltaBuilder.update("4.3", "Makes cache aware of different sites and locales used to access the content")
148                 .addTask(new NodeExistsDelegateTask("Check cache filter", "Reorder i18n filter prior to cache filter to allow cache access to i18n information.",
149                         ContentRepository.CONFIG, "/server/filters/cache", new FilterOrderingTask("cache", new String[]{"i18n"}),
150                                 new WarnTask("", "The cache filter was not found. If you removed it on purpose, you should consider disabling it instead.")))
151                 .addTask(new PropertyExistsDelegateTask("Cache policy re-configuration", "Removes no longer used multihost property from default cache policy.", ContentRepository.CONFIG, "/modules/cache/config/configurations/default/cachePolicy", "multiplehosts", new RemovePropertyTask("", "", ContentRepository.CONFIG, "/modules/cache/config/configurations/default/cachePolicy", "multiplehosts")))
152                 .addTask(new ArrayDelegateTask("Cache Flushing","Adds new commands to flush the cache.",
153                         new BootstrapSingleResource("", "", "/mgnl-bootstrap/cache/config.modules.cache.commands.cache.flushAll.xml"),
154                         new BootstrapSingleResource("", "", "/mgnl-bootstrap/cache/config.modules.cache.commands.cache.flushByUUID.xml")))
155                 .addTask(new BootstrapSingleResource("Cache Flushing", "Adds cache configuration for uuid-key caching.", "/mgnl-bootstrap/cache/config.modules.cache.config.configurations.uuid-key-mapping.xml"))
156                 );
157 
158         register(DeltaBuilder.update("4.3.1", "Disables server side re-caching of requests with no-cache header (shift reload)")
159                 .addTask(new NewPropertyTask("Disabling no-cache requests", "Disable server side re-caching of requests with no-cache header (shift reload)", "config", "/modules/cache/config/configurations/default/cachePolicy", "refreshOnNoCacheRequests", "false"))
160                 .addTask(new WarnTask("Warning", "Server side re-caching of requests with no-cache header (shift reload) were disabled. This can be changed at /modules/cache/config/configurations/default/cachePolicy/refreshOnNoCacheRequests"))
161                 );
162         register(DeltaBuilder.update("4.3.2", "Make waiting for cache entry configurable")
163                 .addTask(new NewPropertyTask("Set cache new entry timeout", "Makes sure incoming requests are not waiting for cache entries to be created longer then specified timeout", ContentRepository.CONFIG, "/modules/cache/config/cacheFactory", "blockingTimeout", "4000"))
164                 );
165         register(DeltaBuilder.update("4.3.7", "Adds cache tools")
166                 .addTask(new BootstrapConditionally("Cache tools", "Bootstrap for cache tools", "/mgnl-bootstrap/cache/config.modules.cache.commands.cache.flushNamedCache.xml", new WarnTask("Cache tools", "Skipped installation of the Cache Tools menu since such entry already exists.")))
167                 .addTask(new BootstrapConditionally("Cache tools", "Bootstrap for cache tools", "/mgnl-bootstrap/cache/admincentral/config.modules.adminInterface.config.menu.tools.cacheTools.xml", new WarnTask("Cache tools", "Skipped installation of the Cache Tools menu since such entry already exists.")))
168                 .addTask(new BootstrapConditionally("Cache tools", "Bootstrap for cache tools", "/mgnl-bootstrap/cache/config.modules.cache.pages.xml", new WarnTask("Cache tools", "Skipped installation of the Cache Tools menu since such entry already exists.")))
169                 );
170     }
171 
172     private List<Task> getTasksFor364() {
173         List<Task> list = new ArrayList<Task>();
174         // Add new compression types and user agents configuration
175         list.add(new BootstrapResourcesTask("Updated configuration", "Bootstraps cache compression configuration.") {
176             protected String[] getResourcesToBootstrap(final InstallContext installContext) {
177                 return new String[]{"/mgnl-bootstrap/cache/config.modules.cache.config.compression.xml"};
178             }
179         });
180 
181         // remove previously used compressible content types configuration
182         list.add(new DefaultCompressibleContentTypesCondition("Cache cleanup", "Removes obsolete cache compression list in favor of new global configuration.",
183                         new RemoveNodeTask("Remove obsolete compression list configuration.", "Removes cache executor specific compression list configuration in favor of using one global list for both cache and gzip.", ContentRepository.CONFIG, "/modules/cache/config/configurations/default/executors/store/cacheContent/compressible"),
184                         new WarnTask("Warning", "The compression list configuration have been relocated to /modules/cache/compression/voters/contentType, since you have modified the default configuration, please make sure your customization is applied also to new configuration."),
185                         "/modules/cache/config/configurations/default/executors/store/cacheContent/compressible"));
186 
187         // remove bypass for compressible content types from gzip filter
188         list.add(new DefaultCompressibleContentTypesCondition("GZip cleanup", "Removes obsolete gzip bypass in favor of new global configuration.",
189                         new RemoveNodeTask("Remove obsolete bypass.", "Removes content type bypass from gzip filter.", ContentRepository.CONFIG, "/server/filters/gzip/bypasses/contentType"),
190                         new WarnTask("Warning", "The list of compressible types have been relocated to /modules/cache/compression/voters/contentType, since you have modified the default configuration, please make sure your customization is applied also to new configuration."),
191                         "/server/filters/gzip/bypasses/contentType/allowed"));
192 
193         // add new bypass to GzipFilter that executes voters from new compression configuration in /modules/cache/config
194         list.add(new AbstractRepositoryTask("Add bypass", "Adds new bypass for GZip filter using global configuration.") {
195             protected void doExecute(InstallContext installContext) throws RepositoryException, TaskExecutionException {
196                 final HierarchyManager hm = installContext.getHierarchyManager(ContentRepository.CONFIG);
197                 Content content = hm.createContent("/server/filters/gzip/bypasses", "deletageBypass", ItemType.CONTENTNODE.getSystemName());
198                 content.setNodeData("class","info.magnolia.voting.voters.VoterSet");
199                 content.setNodeData("delegatePath","/modules/cache/config/compression/voters");
200             }
201         });
202 
203         list.add(new AbstractRepositoryTask("Cache Flushing", "Migrate old cache flushing configuration to new location." ) {
204             protected void doExecute(InstallContext installContext) throws RepositoryException, TaskExecutionException {
205                 final String reposPath= "/modules/cache/config/repositories";
206                 final HierarchyManager hm = installContext.getHierarchyManager(ContentRepository.CONFIG);
207                 if (!hm.isExist(reposPath)) {
208                     return;
209                 }
210                 Content cnt = hm.getContent(reposPath);
211                 for (Content c : cnt.getChildren()) {
212                     if (c.hasNodeData("name")) {
213                         new RegisterWorkspaceForCacheFlushingTask(c.getName()).execute(installContext);
214                     }
215                 }
216                 cnt.delete();
217             }});
218         return list;
219     }
220 
221     protected List<Task> getExtraInstallTasks(InstallContext installContext) {
222         final List<Task> tasks = new ArrayList<Task>();
223         tasks.add(new FilterOrderingTask("gzip", new String[]{"context", "multipartRequest", "activation"}));
224         tasks.add(new FilterOrderingTask("cache", new String[]{"gzip", "i18n"}));
225         return tasks;
226     }
227 
228 
229     /* TODO : if we keep this, they should move to cacheStrategy now
230     public List getStartupTasks(InstallContext installContext) {
231         List tasks = new ArrayList();
232 
233         // standard voters that should be always available. They can be disabled by setting the enable flag to false,
234         // but their presence will always be checked
235 
236         Map config = new HashMap();
237         config.put("enabled", Boolean.TRUE);
238         config.put("not", Boolean.TRUE);
239         tasks.add(new AddCacheVoterTask("notWithParametersVoter", RequestHasParametersVoter.class, config));
240 
241         // this was replaced by a simple bypass
242         config = new HashMap();
243         config.put("enabled", Boolean.TRUE);
244         config.put("falseValue", new Long(-1));
245         config.put("trueValue", new Long(0));
246         config.put("allow", "html,css,js,jpg,gif,png");
247         tasks.add(new AddCacheVoterTask("extensionVoter", ExtensionVoter.class, config));
248 
249         config = new HashMap();
250         config.put("enabled", Boolean.TRUE);
251         config.put("not", Boolean.TRUE);
252         tasks.add(new AddCacheVoterTask("notOnAdminVoter", OnAdminVoter.class, config));
253 
254         config = new HashMap();
255         config.put("enabled", Boolean.FALSE);
256         config.put("not", Boolean.TRUE);
257         tasks.add(new AddCacheVoterTask("notAuthenticatedVoter", AuthenticatedVoter.class, config));
258 
259         return tasks;
260     }
261     */
262 
263 }