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

File DefaultDocumentCache.java

 

Coverage histogram

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

Code metrics

14
46
12
2
255
143
19
0.41
3.83
6
1.58

Classes

Class Line # Actions
DefaultDocumentCache 58 42 0% 16 19
0.707692370.8%
DefaultDocumentCache.Listener 71 4 0% 3 0
1.0100%
 

Contributing tests

This file is covered by 3 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;
21   
22    import java.util.Arrays;
23    import java.util.Collection;
24    import java.util.HashSet;
25    import java.util.List;
26   
27    import javax.inject.Inject;
28   
29    import org.xwiki.bridge.event.DocumentCreatedEvent;
30    import org.xwiki.bridge.event.DocumentDeletedEvent;
31    import org.xwiki.bridge.event.DocumentUpdatedEvent;
32    import org.xwiki.cache.Cache;
33    import org.xwiki.cache.CacheException;
34    import org.xwiki.cache.CacheManager;
35    import org.xwiki.cache.config.CacheConfiguration;
36    import org.xwiki.component.annotation.Component;
37    import org.xwiki.component.annotation.InstantiationStrategy;
38    import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
39    import org.xwiki.model.reference.DocumentReference;
40    import org.xwiki.model.reference.EntityReferenceSerializer;
41    import org.xwiki.observation.EventListener;
42    import org.xwiki.observation.ObservationManager;
43    import org.xwiki.observation.event.Event;
44   
45    import com.xpn.xwiki.doc.XWikiDocument;
46   
47    /**
48    * Specialized cache component related to documents. It automatically clean the cache when the document is related.
49    * <p>
50    * TODO: add support for dependencies
51    *
52    * @param <C> the type of the data stored in the cache
53    * @version $Id: 190e6e3ccae9e145abe26c525a9250f1abbf487f $
54    * @since 2.4M1
55    */
56    @Component
57    @InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
 
58    public class DefaultDocumentCache<C> implements DocumentCache<C>
59    {
60    /**
61    * Event listened by the component.
62    */
63    private static final List<Event> EVENTS = Arrays.<Event>asList(new DocumentCreatedEvent(),
64    new DocumentUpdatedEvent(), new DocumentDeletedEvent());
65   
66    /**
67    * Used to listen to document modification events.
68    *
69    * @version $Id: 190e6e3ccae9e145abe26c525a9250f1abbf487f $
70    */
 
71    protected class Listener implements EventListener
72    {
 
73  24 toggle @Override
74    public String getName()
75    {
76  24 return DefaultDocumentCache.this.name;
77    }
78   
 
79  3 toggle @Override
80    public List<Event> getEvents()
81    {
82  3 return EVENTS;
83    }
84   
 
85  2 toggle @Override
86    public void onEvent(Event event, Object source, Object data)
87    {
88  2 XWikiDocument doc = (XWikiDocument) source;
89  2 removeAll(doc.getDocumentReference());
90    }
91    }
92   
93    /**
94    * The listener used to listen to document modification events.
95    */
96    protected Listener listener = new Listener();
97   
98    /**
99    * Used to initialize the actual cache component.
100    */
101    @Inject
102    private CacheManager cacheManager;
103   
104    /**
105    * Serialize a document reference into a String.
106    */
107    @Inject
108    private EntityReferenceSerializer<String> serializer;
109   
110    /**
111    * Used to register as event listener to invalidate the cache.
112    */
113    @Inject
114    private ObservationManager observationManager;
115   
116    /**
117    * The actual cache object.
118    */
119    private Cache<C> cache;
120   
121    /**
122    * The cache used to follow multiple cache entries related to the same document.
123    */
124    private Cache<Collection<String>> mappingCache;
125   
126    /**
127    * The identifier of the cache and event listener.
128    */
129    private String name;
130   
 
131  3 toggle @Override
132    public void create(CacheConfiguration cacheConfiguration) throws CacheException
133    {
134  3 this.name = cacheConfiguration.getConfigurationId();
135   
136  3 this.cache = this.cacheManager.createNewCache(cacheConfiguration);
137   
138  3 CacheConfiguration mappingCacheConfiguration = (CacheConfiguration) cacheConfiguration.clone();
139  3 mappingCacheConfiguration.setConfigurationId(cacheConfiguration.getConfigurationId() + ".mapping");
140   
141  3 this.mappingCache = this.cacheManager.createNewCache(mappingCacheConfiguration);
142   
143  3 this.observationManager.addListener(this.listener);
144    }
145   
146    // cache
147   
 
148  8 toggle @Override
149    public C get(DocumentReference documentReference, Object... extensions)
150    {
151  8 return this.cache.get(getKey(documentReference, extensions));
152    }
153   
 
154  5 toggle @Override
155    public void set(C data, DocumentReference documentReference, Object... extensions)
156    {
157  5 String key = getKey(documentReference, extensions);
158  5 this.cache.set(key, data);
159   
160  5 String documentReferenceString = this.serializer.serialize(documentReference);
161   
162  5 Collection<String> keys = this.mappingCache.get(documentReferenceString);
163   
164  5 if (keys == null) {
165  3 keys = new HashSet<String>();
166  3 this.mappingCache.set(documentReferenceString, keys);
167    }
168   
169  5 keys.add(key);
170    }
171   
172    /**
173    * Generate a key based on the provided document reference and extensions.
174    *
175    * @param documentReference the reference of the document
176    * @param extensions the extensions to the document reference
177    * @return the value
178    */
 
179  13 toggle protected String getKey(DocumentReference documentReference, Object... extensions)
180    {
181  13 StringBuilder buffer = new StringBuilder();
182   
183  13 if (extensions.length > 0) {
184  9 buffer.append(escape(this.serializer.serialize(documentReference)));
185  9 for (Object extension : extensions) {
186  28 buffer.append(':');
187  28 buffer.append(escape(extension != null ? extension.toString() : ""));
188    }
189    } else {
190  4 buffer.append(this.serializer.serialize(documentReference));
191    }
192   
193  13 return buffer.toString();
194    }
195   
196    /**
197    * Escape each element of the key.
198    *
199    * @param str the element of the key to escape
200    * @return the escaped key element
201    */
 
202  37 toggle private String escape(String str)
203    {
204  37 return str.replace("\\", "\\\\").replace(":", "\\:");
205    }
206   
 
207  0 toggle @Override
208    public void remove(C data, DocumentReference documentReference, Object... extensions)
209    {
210  0 String key = getKey(documentReference, extensions);
211  0 this.cache.remove(key);
212   
213  0 String documentReferenceString = this.serializer.serialize(documentReference);
214   
215  0 Collection<String> keys = this.mappingCache.get(documentReferenceString);
216   
217  0 if (keys != null) {
218  0 keys.remove(key);
219    }
220    }
221   
 
222  0 toggle @Override
223    public void removeAll()
224    {
225  0 if (this.cache != null) {
226  0 this.cache.removeAll();
227    }
228  0 if (this.mappingCache != null) {
229  0 this.mappingCache.removeAll();
230    }
231    }
232   
 
233  2 toggle @Override
234    public void removeAll(DocumentReference documentReference)
235    {
236  2 String documentReferenceString = this.serializer.serialize(documentReference);
237   
238  2 Collection<String> keys = this.mappingCache.get(documentReferenceString);
239   
240  2 if (keys != null) {
241  2 for (String key : keys) {
242  3 this.cache.remove(key);
243    }
244   
245  2 this.mappingCache.remove(documentReferenceString);
246    }
247    }
248   
 
249  2 toggle @Override
250    public void dispose()
251    {
252  2 this.cache.dispose();
253  2 this.mappingCache.dispose();
254    }
255    }