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