1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.internal.cache.rendering

File DefaultRenderingCache.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

26
56
10
1
277
157
25
0.45
5.6
10
2.5

Classes

Class Line # Actions
DefaultRenderingCache 56 56 0% 25 22
0.7608695676.1%
 

Contributing tests

This file is covered by 15 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.internal.cache.rendering;
21   
22    import java.io.UnsupportedEncodingException;
23    import java.net.URLEncoder;
24    import java.util.LinkedList;
25    import java.util.List;
26    import java.util.Map;
27    import java.util.SortedMap;
28    import java.util.TreeMap;
29   
30    import javax.inject.Inject;
31    import javax.inject.Provider;
32    import javax.inject.Singleton;
33   
34    import org.xwiki.cache.CacheException;
35    import org.xwiki.cache.config.CacheConfiguration;
36    import org.xwiki.cache.eviction.LRUEvictionConfiguration;
37    import org.xwiki.component.annotation.Component;
38    import org.xwiki.component.phase.Initializable;
39    import org.xwiki.component.phase.InitializationException;
40    import org.xwiki.model.reference.DocumentReference;
41   
42    import com.xpn.xwiki.XWikiContext;
43    import com.xpn.xwiki.internal.cache.DocumentCache;
44    import com.xpn.xwiki.internal.cache.rendering.CachedItem.UsedExtension;
45    import com.xpn.xwiki.plugin.XWikiPluginInterface;
46    import com.xpn.xwiki.plugin.XWikiPluginManager;
47   
48    /**
49    * Default implementation of {@link RenderingCache}.
50    *
51    * @version $Id: 3b4b0fe1c9b16bd788110b89eb285d01714eecbe $
52    * @since 2.4M1
53    */
54    @Component
55    @Singleton
 
56    public class DefaultRenderingCache implements RenderingCache, Initializable
57    {
58    /**
59    * UTF-8 encoding key.
60    */
61    private static final String UTF8 = "UTF-8";
62   
63    /**
64    * Identifier of the rendering cache.
65    */
66    private static final String NAME = "core.renderingcache";
67   
68    /**
69    * The name of the parameter used to force cache refresh.
70    */
71    private static final String PARAMETER_REFRESH = "refresh";
72   
73    /**
74    * Configuration of the rendering cache.
75    */
76    @Inject
77    private RenderingCacheConfiguration configuration;
78   
79    /**
80    * Provider of all components implementing RenderingCacheAware.
81    */
82    @Inject
83    private Provider<List<RenderingCacheAware>> renderingCacheAwareProvider;
84   
85    /**
86    * List of legacy plugin components implementing RenderingCacheAware.
87    */
88    private List<RenderingCacheAware> legacyRenderingCacheAware;
89   
90    /**
91    * Actually cache object.
92    */
93    @Inject
94    private DocumentCache<CachedItem> cache;
95   
 
96  47 toggle @Override
97    public void initialize() throws InitializationException
98    {
99  47 if (this.configuration.isEnabled()) {
100  1 CacheConfiguration cacheConfiguration = new CacheConfiguration();
101  1 cacheConfiguration.setConfigurationId(NAME);
102  1 LRUEvictionConfiguration lru = new LRUEvictionConfiguration();
103  1 lru.setMaxEntries(this.configuration.getSize());
104  1 lru.setLifespan(this.configuration.getDuration());
105  1 cacheConfiguration.put(LRUEvictionConfiguration.CONFIGURATIONID, lru);
106   
107  1 try {
108  1 this.cache.create(cacheConfiguration);
109    } catch (CacheException e) {
110  0 throw new InitializationException("Failed to initialize core rendering cache", e);
111    }
112    }
113    }
114   
115    // cache
116   
 
117  6352 toggle @Override
118    public String getRenderedContent(DocumentReference documentReference, String source, XWikiContext context)
119    {
120  6353 String renderedContent = null;
121   
122  6352 if (this.configuration.isCached(documentReference)) {
123  4 String refresh = context.getRequest() != null ? context.getRequest().getParameter(PARAMETER_REFRESH) : null;
124   
125  4 if (!"1".equals(refresh)) {
126  4 CachedItem cachedItem =
127    this.cache.get(documentReference, source, getAction(context), context.getLanguage(),
128    getRequestParameters(context));
129  4 if (cachedItem != null) {
130  2 renderedContent = restoreCachedItem(context, cachedItem);
131    }
132    }
133    }
134   
135  6352 return renderedContent;
136    }
137   
 
138  6350 toggle @Override
139    public void setRenderedContent(DocumentReference documentReference, String source, String renderedContent,
140    XWikiContext context)
141    {
142  6350 if (this.configuration.isCached(documentReference)) {
143  1 this.cache.set(buildCachedItem(context, renderedContent), documentReference, source, getAction(context),
144    context.getLanguage(), getRequestParameters(context));
145    }
146    }
147   
148    /**
149    * Create cached item with all dependencies.
150    *
151    * @param context current xwiki context
152    * @param renderedContent rendered page content
153    * @return properly cached item
154    */
 
155  1 toggle private CachedItem buildCachedItem(XWikiContext context, String renderedContent)
156    {
157  1 CachedItem cachedItem = new CachedItem();
158   
159  1 for (RenderingCacheAware component : this.renderingCacheAwareProvider.get()) {
160  0 cachedItem.extensions.put(component, component.getCacheResources(context));
161    }
162   
163    // support for legacy core -> build non-blocking list (lazy)
164  1 if (this.legacyRenderingCacheAware == null) {
165  1 this.legacyRenderingCacheAware = new LinkedList<RenderingCacheAware>();
166  1 XWikiPluginManager pluginManager = context.getWiki().getPluginManager();
167  1 for (String pluginName : pluginManager.getPlugins()) {
168  0 XWikiPluginInterface plugin = pluginManager.getPlugin(pluginName);
169   
170  0 if (plugin instanceof RenderingCacheAware) {
171  0 this.legacyRenderingCacheAware.add((RenderingCacheAware) plugin);
172    }
173    }
174    }
175   
176  1 for (RenderingCacheAware component : this.legacyRenderingCacheAware) {
177  0 cachedItem.extensions.put(component, component.getCacheResources(context));
178    }
179   
180  1 cachedItem.rendered = renderedContent;
181  1 return cachedItem;
182    }
183   
184    /**
185    * Restore component state from a cache entry and return correct content.
186    *
187    * @param context the current xwiki context
188    * @param cachedItem The cache item to return
189    * @return the rendered text
190    */
 
191  2 toggle private String restoreCachedItem(XWikiContext context, CachedItem cachedItem)
192    {
193  2 for (Map.Entry<RenderingCacheAware, UsedExtension> item : cachedItem.extensions.entrySet()) {
194  0 item.getKey().restoreCacheResources(context, item.getValue());
195    }
196   
197  2 return cachedItem.rendered;
198    }
199   
200    /**
201    * Extract action information from the context.
202    *
203    * @param context the XWiki context
204    * @return the current action
205    */
 
206  5 toggle private String getAction(XWikiContext context)
207    {
208  5 return context.getAction() != null ? context.getAction() : "view";
209    }
210   
211    /**
212    * Extract action information from the context.
213    *
214    * @param context the XWiki context
215    * @return the current request parameters
216    */
 
217  5 toggle private String getRequestParameters(XWikiContext context)
218    {
219  5 if (context.getRequest() != null) {
220  5 Map<String, String[]> parameters = context.getRequest().getParameterMap();
221   
222  5 if (parameters != null) {
223    // Sort the Map so that the returned value can be used as a key that doesn't change if the servlet
224    // container sends the parameter in a different order.
225  5 SortedMap<String, String[]> sortedMap = new TreeMap<String, String[]>(parameters);
226  5 return constructRequestString(sortedMap);
227    }
228    }
229   
230  0 return "";
231    }
232   
233    /**
234    * Encode the passed parameters in UTF-8 and return a String representing them.
235    *
236    * @param sortedMap the map representing the Request parameters
237    * @return the encoded parameters as a String
238    */
 
239  5 toggle private String constructRequestString(SortedMap<String, String[]> sortedMap)
240    {
241  5 StringBuilder sb = new StringBuilder();
242    // TODO: Create a common class to serialize and encode parameters since this is a common need, and use
243    // a Commons Collection Predicate to exclude the refresh parameter.
244  5 for (Map.Entry<String, String[]> entry : sortedMap.entrySet()) {
245    // If the parameter is the refresh parameter then ignore it
246  1 if (!entry.getKey().equals(PARAMETER_REFRESH)) {
247  1 for (String value : entry.getValue()) {
248  2 if (sb.length() > 0) {
249  1 sb.append('&');
250    }
251  2 try {
252  2 sb.append(URLEncoder.encode(entry.getKey(), UTF8)).append('=')
253    .append(URLEncoder.encode(value, UTF8));
254    } catch (UnsupportedEncodingException e) {
255    // That should never happen since UTF-8 is supposed to be available in any JVM.
256  0 throw new RuntimeException(
257    String.format("Failed to URL encode [[%s]:[%s]] parameter using UTF-8.",
258    entry.getKey(), entry.getValue()), e);
259    }
260    }
261    }
262    }
263  5 return sb.toString();
264    }
265   
 
266  0 toggle @Override
267    public void flushCache(DocumentReference documentReference)
268    {
269  0 this.cache.removeAll(documentReference);
270    }
271   
 
272  0 toggle @Override
273    public void flushWholeCache()
274    {
275  0 this.cache.removeAll();
276    }
277    }