1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.extension.repository.internal.installed

File DefaultInstalledExtension.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

68
125
31
1
519
303
66
0.53
4.03
31
2.13

Classes

Class Line # Actions
DefaultInstalledExtension 42 125 0% 66 7
0.9687596.9%
 

Contributing tests

This file is covered by 112 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 org.xwiki.extension.repository.internal.installed;
21   
22    import java.util.Collection;
23    import java.util.Collections;
24    import java.util.Date;
25    import java.util.HashMap;
26    import java.util.Map;
27    import java.util.concurrent.ConcurrentHashMap;
28   
29    import org.xwiki.extension.AbstractExtension;
30    import org.xwiki.extension.Extension;
31    import org.xwiki.extension.InstalledExtension;
32    import org.xwiki.extension.LocalExtension;
33    import org.xwiki.extension.LocalExtensionFile;
34    import org.xwiki.extension.repository.ExtensionRepository;
35    import org.xwiki.extension.repository.InstalledExtensionRepository;
36   
37    /**
38    * Default implementation of {@link LocalExtension}.
39    *
40    * @version $Id: 33f298e05a8cb32082ccfffee9dfeac526bfc3f5 $
41    */
 
42    public class DefaultInstalledExtension extends AbstractExtension implements InstalledExtension
43    {
44    /**
45    * Custom property key containing the properties associated with the root namespace (when the extension is installed
46    * on all namespaces).
47    */
48    private static final String PKEY_ROOT_NAMESPACE = PKEY_PREFIX + "root";
49   
50    /**
51    * Custom property key containing {@link #getInstallDate(String)}.
52    */
53    private static final String PKEY_DATE = "date";
54   
55    /**
56    * @see #getLocalExtension()
57    */
58    private LocalExtension localExtension;
59   
60    /**
61    * @see #isValid(String)
62    */
63    private Map<String, Boolean> valid;
64   
65    /**
66    * Cache namespaces since they are used a lot.
67    */
68    private Collection<String> namespacesCache;
69   
70    /**
71    * @param localExtension the wrapped local extension
72    * @param repository the repository
73    */
 
74  1530 toggle public DefaultInstalledExtension(LocalExtension localExtension, InstalledExtensionRepository repository)
75    {
76  1530 super(repository, localExtension);
77   
78  1530 this.localExtension = localExtension;
79    }
80   
81    /**
82    * @param extension the extension
83    * @return true if the extension is installed
84    * @see InstalledExtension#isInstalled()
85    */
 
86  9613 toggle public static boolean isInstalled(Extension extension)
87    {
88  9613 return extension.getProperty(PKEY_INSTALLED, false);
89    }
90   
91    /**
92    * @param extension the extension
93    * @param namespace the namespace to look at, if null it means the extension is installed for all the namespaces
94    * @return true if the extension is installed in the provided namespace
95    * @see InstalledExtension#isInstalled(String)
96    */
 
97  3582 toggle public static boolean isInstalled(Extension extension, String namespace)
98    {
99  3582 return isInstalled(extension)
100    && (getNamespaces(extension) == null || getNamespaces(extension).contains(namespace));
101    }
102   
103    /**
104    * Indicate if the extension as been installed as a dependency of another one.
105    *
106    * @param extension the extension
107    * @param namespace the namespace to look at, null indicate the root namespace
108    * @return true if the the extension has been installed only because it was a dependency of another extension
109    * @see InstalledExtension#isDependency(String)
110    * @since 8.2RC1
111    */
 
112  2323 toggle public static boolean isDependency(Extension extension, String namespace)
113    {
114  2323 boolean isDependency = false;
115   
116  2323 if (namespace == null) {
117  1491 isDependency = extension.getProperty(PKEY_DEPENDENCY, false);
118    } else {
119  832 Object namespacesObject = extension.getProperty(PKEY_NAMESPACES);
120   
121    // RETRO-COMPATIBILITY: used to be a String collection with just the actual namespaces
122  832 if (namespacesObject instanceof Map) {
123  200 Map<String, Object> installedNamespace =
124    ((Map<String, Map<String, Object>>) namespacesObject).get(namespace);
125   
126  200 isDependency =
127  200 installedNamespace != null ? (installedNamespace.get(PKEY_NAMESPACES_DEPENDENCY) == Boolean.TRUE)
128    : isDependency(extension, null);
129    } else {
130  632 isDependency = isDependency(extension, null);
131    }
132    }
133   
134  2323 return isDependency;
135    }
136   
137    /**
138    * @param extension the extension
139    * @return the namespaces in which this extension is enabled. Null means root namespace (i.e all namespaces).
140    */
 
141  10940 toggle public static Collection<String> getNamespaces(Extension extension)
142    {
143  10940 Collection<String> namespaces;
144   
145  10940 Object namespacesObject = extension.getProperty(PKEY_NAMESPACES);
146   
147    // RETRO-COMPATIBILITY: used to be a String collection with just the actual namespaces
148  10940 if (namespacesObject == null) {
149  4031 namespaces = null;
150  6909 } else if (namespacesObject instanceof Collection) {
151  4208 namespaces = (Collection<String>) namespacesObject;
152    } else {
153  2701 namespaces = ((Map<String, Map<String, Object>>) namespacesObject).keySet();
154    }
155   
156  10940 return namespaces;
157    }
158   
159    // Extension
160   
 
161  55 toggle @Override
162    public ExtensionRepository getRepository()
163    {
164  55 return this.repository;
165    }
166   
167    // InstalledExtension
168   
 
169  779 toggle @Override
170    public LocalExtension getLocalExtension()
171    {
172  779 return this.localExtension;
173    }
174   
 
175  6416 toggle @Override
176    public Collection<String> getNamespaces()
177    {
178  6416 if (this.namespacesCache == null) {
179  3555 Map<String, Map<String, Object>> installedNamespaces = getInstalledNamespaces();
180   
181  3555 if (installedNamespaces != null) {
182  671 this.namespacesCache = Collections.unmodifiableSet(installedNamespaces.keySet());
183    }
184    }
185   
186  6416 return this.namespacesCache;
187    }
188   
189    /**
190    * @param namespaces the namespaces in which this extension is enabled. Null means root namespace (i.e all
191    * namespaces).
192    * @see #getNamespaces()
193    */
 
194  1448 toggle public void setNamespaces(Collection<String> namespaces)
195    {
196  1448 synchronized (this.propertiesLock) {
197  1448 if (namespaces == null) {
198  991 putProperty(PKEY_ROOT_NAMESPACE, isInstalled() ? new HashMap<String, Object>() : null);
199  991 putProperty(PKEY_NAMESPACES, null);
200    } else {
201  457 putProperty(PKEY_ROOT_NAMESPACE, null);
202  457 Map<String, Map<String, Object>> installedNamespaces =
203    new ConcurrentHashMap<String, Map<String, Object>>();
204  457 putProperty(PKEY_NAMESPACES, installedNamespaces);
205  457 for (String namespace : namespaces) {
206  617 Map<String, Object> namespaceData = new HashMap<String, Object>();
207  617 namespaceData.put(PKEY_NAMESPACES_NAMESPACE, namespace);
208  617 installedNamespaces.put(namespace, namespaceData);
209    }
210    }
211    }
212   
213  1448 this.namespacesCache = null;
214    }
215   
216    /**
217    * @param namespace the namespace
218    * @see #getNamespaces()
219    */
 
220  833 toggle public void addNamespace(String namespace)
221    {
222  833 getInstalledNamespace(namespace, true);
223    }
224   
 
225  2017 toggle @Override
226    public boolean isInstalled()
227    {
228  2017 return isInstalled(this);
229    }
230   
 
231  1859 toggle @Override
232    public boolean isInstalled(String namespace)
233    {
234  1859 return isInstalled(this, namespace);
235    }
236   
237    /**
238    * @param installed indicate if the extension is installed
239    * @see #isInstalled()
240    */
 
241  1827 toggle public void setInstalled(boolean installed)
242    {
243  1827 putProperty(PKEY_INSTALLED, installed);
244    }
245   
246    /**
247    * @param installed indicate if the extension is installed
248    * @param namespace the namespace to look at, if null it means the extension is installed for all the namespaces
249    * @see #isInstalled(String)
250    */
 
251  1840 toggle public void setInstalled(boolean installed, String namespace)
252    {
253  1840 synchronized (this.propertiesLock) {
254  1840 if (namespace == null) {
255  928 if (installed && !isInstalled()) {
256  82 setValid(namespace, true);
257    }
258   
259  928 setInstalled(installed);
260  928 setNamespaces(null);
261    } else {
262  912 if (installed) {
263  833 if (!isInstalled(namespace)) {
264  295 setValid(namespace, true);
265    }
266   
267  833 setInstalled(true);
268  833 addNamespace(namespace);
269    } else {
270  79 Map<String, Map<String, Object>> installedNamespaces = getInstalledNamespaces();
271  79 if (installedNamespaces != null) {
272  79 installedNamespaces.remove(namespace);
273   
274  79 if (getNamespaces().isEmpty()) {
275  63 setInstalled(false);
276  63 setNamespaces(null);
277    }
278    }
279    }
280    }
281    }
282   
283  1840 if (!installed) {
284  122 removeValid(namespace);
285    }
286    }
287   
 
288  122 toggle private void removeValid(String namespace)
289    {
290  122 if (this.valid != null) {
291  122 this.valid.remove(namespace);
292    }
293    }
294   
295    /**
296    * @param namespace the namespace
297    * @return true if the extension has been explicitly indicated as valid or invalid
298    * @since 8.2.1
299    * @since 8.3M1
300    */
 
301  2307 toggle public boolean isValidated(String namespace)
302    {
303  2307 if (this.valid == null) {
304  0 return false;
305    }
306   
307  2307 return this.valid.get(namespace) != null;
308    }
309   
 
310  11705 toggle @Override
311    public boolean isValid(String namespace)
312    {
313  11705 Boolean isvalid = this.valid != null ? this.valid.get(namespace) : null;
314   
315  11705 return isvalid != null ? isvalid : true;
316    }
317   
318    /**
319    * @param valid indicate of the installed extension is valid
320    * @param namespace the namespace to look at, if null it means the extension is installed for all the namespaces
321    */
 
322  2080 toggle public void setValid(String namespace, boolean valid)
323    {
324  2080 Map<String, Boolean> validMap =
325  2080 this.valid != null ? new HashMap<String, Boolean>(this.valid) : new HashMap<String, Boolean>();
326  2080 validMap.put(namespace, valid);
327   
328  2080 this.valid = validMap;
329    }
330   
331    /**
332    * @return the installed namespaces
333    */
 
334  4906 toggle private Map<String, Map<String, Object>> getInstalledNamespaces()
335    {
336  4906 Object namespacesObject = getProperty(PKEY_NAMESPACES);
337   
338  4906 Map<String, Map<String, Object>> installedNamespaces = null;
339    // RETRO-COMPATIBILITY: used to be a String collection with just the actual namespaces
340  4906 if (namespacesObject instanceof Collection) {
341  456 Collection<String> namespaces = (Collection<String>) namespacesObject;
342  456 setNamespaces(namespaces);
343    } else {
344  4450 installedNamespaces = (Map<String, Map<String, Object>>) namespacesObject;
345   
346    }
347   
348  4906 return installedNamespaces;
349    }
350   
351    /**
352    * @param namespace the namespace
353    * @param create indicate if the {@link InstalledNamespace} should be create if it does not exists
354    * @return the corresponding {@link InstalledNamespace}
355    */
 
356  1272 toggle private Map<String, Object> getInstalledNamespace(String namespace, boolean create)
357    {
358  1272 Map<String, Map<String, Object>> namespaces = getInstalledNamespaces();
359   
360  1272 if (namespaces != null) {
361  697 Map<String, Object> installedNamespace = namespaces.get(namespace);
362   
363  697 if (installedNamespace != null) {
364  511 return installedNamespace;
365    }
366    }
367   
368  761 return create ? maybeCreateInstalledNamespace(namespaces, namespace) : null;
369    }
370   
 
371  753 toggle private Map<String, Object> maybeCreateInstalledNamespace(Map<String, Map<String, Object>> namespaces,
372    String namespace)
373    {
374  753 synchronized (this.propertiesLock) {
375    // Can't use ConcurrentHashMap because we have null key (root namespace)
376  753 Map<String, Map<String, Object>> newNamespaces;
377  753 if (namespaces != null) {
378  185 newNamespaces = new HashMap<>(namespaces);
379    } else {
380  568 newNamespaces = new HashMap<>();
381    }
382   
383    // Create the map for the namespace
384  753 Map<String, Object> installedNamespace = new ConcurrentHashMap<String, Object>();
385  753 newNamespaces.put(namespace, installedNamespace);
386   
387    // Set the new map of properties
388  753 putProperty(PKEY_NAMESPACES, newNamespaces);
389   
390    // Reset the cache
391  753 this.namespacesCache = null;
392   
393  753 return installedNamespace;
394    }
395    }
396   
 
397  3 toggle @Override
398    @Deprecated
399    public boolean isDependency()
400    {
401  3 return isDependency(null);
402    }
403   
 
404  194 toggle @Override
405    public boolean isDependency(String namespace)
406    {
407  194 return isDependency(this, namespace);
408    }
409   
410    /**
411    * @param dependency indicate if the extension has been installed as a dependency of another one
412    * @see #isDependency()
413    * @deprecated
414    */
 
415  0 toggle @Deprecated
416    public void setDependency(boolean dependency)
417    {
418  0 putProperty(PKEY_DEPENDENCY, dependency);
419    }
420   
421    /**
422    * @param dependency indicate if the extension has been installed as a dependency of another one
423    * @param namespace the namespace
424    * @see #isDependency(String)
425    */
 
426  211 toggle public void setDependency(boolean dependency, String namespace)
427    {
428  211 synchronized (this.propertiesLock) {
429  211 if (namespace == null) {
430  76 putProperty(PKEY_DEPENDENCY, dependency);
431    } else {
432  135 Map<String, Object> installedNamespace = getInstalledNamespace(namespace, false);
433   
434  135 if (installedNamespace != null) {
435  134 installedNamespace.put(PKEY_NAMESPACES_DEPENDENCY, dependency);
436    }
437    }
438    }
439    }
440   
 
441  28 toggle @Override
442    public Date getInstallDate(String namespace)
443    {
444  28 return (Date) getNamespaceProperty(PKEY_DATE, namespace);
445    }
446   
447    /**
448    * Sets the date when this extension has been installed on the specified namespace.
449    *
450    * @param date the install date
451    * @param namespace the namespace for which to set the install date
452    * @since 7.0M2
453    */
 
454  211 toggle public void setInstallDate(Date date, String namespace)
455    {
456  211 setNamespaceProperty(PKEY_DATE, date, namespace);
457    }
458   
 
459  44 toggle @Override
460    public Object getNamespaceProperty(String key, String namespace)
461    {
462  44 Object value = null;
463  44 if (namespace != null) {
464  39 Map<String, Object> installedNamespace = getInstalledNamespace(namespace, false);
465  39 if (installedNamespace != null) {
466  33 value = installedNamespace.get(key);
467    }
468    }
469  44 if (value == null) {
470    // Fallback on the root namespace.
471    // Note that we don't pass an empty map as default value because the value mapped to the key can be null.
472  11 Map<String, Object> rootNamespace = getProperty(PKEY_ROOT_NAMESPACE, (Map<String, Object>) null);
473  11 if (rootNamespace != null) {
474  4 value = rootNamespace.get(key);
475    }
476    }
477  44 return value;
478    }
479   
480    /**
481    * Sets the value of the specified extension property on the given namespace.
482    *
483    * @param key the extension property to set
484    * @param value the property value
485    * @param namespace the namespace to associate the property with, {@code null} for the root namespace
486    * @since 7.0M2
487    */
 
488  211 toggle public void setNamespaceProperty(String key, Object value, String namespace)
489    {
490  211 synchronized (this.propertiesLock) {
491  211 Map<String, Object> namespaceProperties = getNamespaceProperties(namespace);
492  211 if (namespaceProperties != null) {
493  209 namespaceProperties.put(key, value);
494    }
495    }
496    }
497   
498    /**
499    * @param namespace the namespace to look for
500    * @return the custom extension properties associated with the specified namespace
501    * @since 7.0M2
502    */
 
503  416 toggle public Map<String, Object> getNamespaceProperties(String namespace)
504    {
505  416 if (namespace == null) {
506  151 return getProperty(PKEY_ROOT_NAMESPACE, (Map<String, Object>) null);
507    } else {
508  265 return getInstalledNamespace(namespace, false);
509    }
510    }
511   
512    // LocalExtension
513   
 
514  453 toggle @Override
515    public LocalExtensionFile getFile()
516    {
517  453 return getLocalExtension().getFile();
518    }
519    }