1. Project Clover database Sat Feb 2 2019 06:45:20 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
135
31
1
539
318
66
0.49
4.35
31
2.13

Classes

Class Line # Actions
DefaultInstalledExtension 42 135 0% 66 5
0.9786324597.9%
 

Contributing tests

This file is covered by 115 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: af1b00aa6f72b084caf47c8da4b61b679115536f $
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  2995 toggle public DefaultInstalledExtension(LocalExtension localExtension, InstalledExtensionRepository repository)
75    {
76  2995 super(repository, localExtension);
77   
78  2995 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  19673 toggle public static boolean isInstalled(Extension extension)
87    {
88  19673 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  9592 toggle public static boolean isInstalled(Extension extension, String namespace)
98    {
99  9592 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  3881 toggle public static boolean isDependency(Extension extension, String namespace)
113    {
114  3881 boolean isDependency = false;
115   
116  3881 if (namespace == null) {
117  1717 isDependency = extension.getProperty(PKEY_DEPENDENCY, false);
118    } else {
119  2164 Object namespacesObject = extension.getProperty(PKEY_NAMESPACES);
120   
121    // RETRO-COMPATIBILITY: used to be a String collection with just the actual namespaces
122  2164 if (namespacesObject instanceof Map) {
123  1476 Map<String, Object> installedNamespace =
124    ((Map<String, Map<String, Object>>) namespacesObject).get(namespace);
125   
126  1476 isDependency =
127  1476 installedNamespace != null ? (installedNamespace.get(PKEY_NAMESPACES_DEPENDENCY) == Boolean.TRUE)
128    : isDependency(extension, null);
129    } else {
130  688 isDependency = isDependency(extension, null);
131    }
132    }
133   
134  3881 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  26681 toggle public static Collection<String> getNamespaces(Extension extension)
142    {
143  26681 Collection<String> namespaces;
144   
145  26681 Object namespacesObject = extension.getProperty(PKEY_NAMESPACES);
146   
147    // RETRO-COMPATIBILITY: used to be a String collection with just the actual namespaces
148  26681 if (namespacesObject == null) {
149  4989 namespaces = null;
150  21692 } else if (namespacesObject instanceof Collection) {
151  4537 namespaces = (Collection<String>) namespacesObject;
152    } else {
153  17155 namespaces = ((Map<String, Map<String, Object>>) namespacesObject).keySet();
154    }
155   
156  26681 return namespaces;
157    }
158   
159    // Extension
160   
 
161  859 toggle @Override
162    public ExtensionRepository getRepository()
163    {
164  859 return this.repository;
165    }
166   
167    // InstalledExtension
168   
 
169  2907 toggle @Override
170    public LocalExtension getLocalExtension()
171    {
172  2907 return this.localExtension;
173    }
174   
 
175  24096 toggle @Override
176    public Collection<String> getNamespaces()
177    {
178  24096 if (this.namespacesCache == null) {
179  6224 Map<String, Map<String, Object>> installedNamespaces = getInstalledNamespaces();
180   
181  6224 if (installedNamespaces != null) {
182  1969 this.namespacesCache = Collections.unmodifiableSet(installedNamespaces.keySet());
183    }
184    }
185   
186  24096 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  1760 toggle public void setNamespaces(Collection<String> namespaces)
195    {
196  1760 try {
197  1760 this.propertiesLock.lock();
198   
199  1760 if (namespaces == null) {
200  1268 putProperty(PKEY_ROOT_NAMESPACE, isInstalled() ? new HashMap<String, Object>() : null);
201  1268 putProperty(PKEY_NAMESPACES, null);
202    } else {
203  492 putProperty(PKEY_ROOT_NAMESPACE, null);
204  492 Map<String, Map<String, Object>> installedNamespaces =
205    new ConcurrentHashMap<String, Map<String, Object>>();
206  492 putProperty(PKEY_NAMESPACES, installedNamespaces);
207  492 for (String namespace : namespaces) {
208  666 Map<String, Object> namespaceData = new HashMap<String, Object>();
209  666 namespaceData.put(PKEY_NAMESPACES_NAMESPACE, namespace);
210  666 installedNamespaces.put(namespace, namespaceData);
211    }
212    }
213    } finally {
214  1760 this.propertiesLock.unlock();
215    }
216   
217  1760 this.namespacesCache = null;
218    }
219   
220    /**
221    * @param namespace the namespace
222    * @see #getNamespaces()
223    */
 
224  2299 toggle public void addNamespace(String namespace)
225    {
226  2299 getInstalledNamespace(namespace, true);
227    }
228   
 
229  2572 toggle @Override
230    public boolean isInstalled()
231    {
232  2572 return isInstalled(this);
233    }
234   
 
235  6382 toggle @Override
236    public boolean isInstalled(String namespace)
237    {
238  6382 return isInstalled(this, namespace);
239    }
240   
241    /**
242    * @param installed indicate if the extension is installed
243    * @see #isInstalled()
244    */
 
245  3570 toggle public void setInstalled(boolean installed)
246    {
247  3570 putProperty(PKEY_INSTALLED, installed);
248    }
249   
250    /**
251    * @param installed indicate if the extension is installed
252    * @param namespace the namespace to look at, if null it means the extension is installed for all the namespaces
253    * @see #isInstalled(String)
254    */
 
255  3579 toggle public void setInstalled(boolean installed, String namespace)
256    {
257  3579 try {
258  3579 this.propertiesLock.lock();
259   
260  3579 if (namespace == null) {
261  1105 if (installed && !isInstalled()) {
262  100 setValid(namespace, true);
263    }
264   
265  1105 setInstalled(installed);
266  1105 setNamespaces(null);
267    } else {
268  2474 if (installed) {
269  2299 if (!isInstalled(namespace)) {
270  712 setValid(namespace, true);
271    }
272   
273  2299 setInstalled(true);
274  2299 addNamespace(namespace);
275    } else {
276  175 Map<String, Map<String, Object>> installedNamespaces = getInstalledNamespaces();
277  175 if (installedNamespaces != null) {
278  175 installedNamespaces.remove(namespace);
279   
280  175 if (getNamespaces().isEmpty()) {
281  163 setInstalled(false);
282  163 setNamespaces(null);
283    }
284    }
285    }
286    }
287    } finally {
288  3579 this.propertiesLock.unlock();
289    }
290   
291  3579 if (!installed) {
292  226 removeValid(namespace);
293    }
294    }
295   
 
296  226 toggle private void removeValid(String namespace)
297    {
298  226 if (this.valid != null) {
299  226 this.valid.remove(namespace);
300    }
301    }
302   
303    /**
304    * @param namespace the namespace
305    * @return true if the extension has been explicitly indicated as valid or invalid
306    * @since 8.2.1
307    * @since 8.3M1
308    */
 
309  4637 toggle public boolean isValidated(String namespace)
310    {
311  4637 if (this.valid == null) {
312  2 return false;
313    }
314   
315  4635 return this.valid.get(namespace) != null;
316    }
317   
 
318  45289 toggle @Override
319    public boolean isValid(String namespace)
320    {
321  45289 Boolean isvalid = this.valid != null ? this.valid.get(namespace) : null;
322   
323  45289 return isvalid != null ? isvalid : true;
324    }
325   
326    /**
327    * @param valid indicate of the installed extension is valid
328    * @param namespace the namespace to look at, if null it means the extension is installed for all the namespaces
329    */
 
330  4153 toggle public void setValid(String namespace, boolean valid)
331    {
332  4153 Map<String, Boolean> validMap =
333  4153 this.valid != null ? new HashMap<String, Boolean>(this.valid) : new HashMap<String, Boolean>();
334  4153 validMap.put(namespace, valid);
335   
336  4153 this.valid = validMap;
337    }
338   
339    /**
340    * @return the installed namespaces
341    */
 
342  10357 toggle private Map<String, Map<String, Object>> getInstalledNamespaces()
343    {
344  10357 Object namespacesObject = getProperty(PKEY_NAMESPACES);
345   
346  10357 Map<String, Map<String, Object>> installedNamespaces = null;
347    // RETRO-COMPATIBILITY: used to be a String collection with just the actual namespaces
348  10357 if (namespacesObject instanceof Collection) {
349  491 Collection<String> namespaces = (Collection<String>) namespacesObject;
350  491 setNamespaces(namespaces);
351    } else {
352  9866 installedNamespaces = (Map<String, Map<String, Object>>) namespacesObject;
353   
354    }
355   
356  10357 return installedNamespaces;
357    }
358   
359    /**
360    * @param namespace the namespace
361    * @param create indicate if the {@link InstalledNamespace} should be create if it does not exists
362    * @return the corresponding {@link InstalledNamespace}
363    */
 
364  3958 toggle private Map<String, Object> getInstalledNamespace(String namespace, boolean create)
365    {
366  3958 Map<String, Map<String, Object>> namespaces = getInstalledNamespaces();
367   
368  3958 if (namespaces != null) {
369  2932 Map<String, Object> installedNamespace = namespaces.get(namespace);
370   
371  2932 if (installedNamespace != null) {
372  2736 return installedNamespace;
373    }
374    }
375   
376  1222 return create ? maybeCreateInstalledNamespace(namespaces, namespace) : null;
377    }
378   
 
379  1214 toggle private Map<String, Object> maybeCreateInstalledNamespace(Map<String, Map<String, Object>> namespaces,
380    String namespace)
381    {
382  1214 try {
383  1214 this.propertiesLock.lock();
384   
385    // Can't use ConcurrentHashMap because we have null key (root namespace)
386  1214 Map<String, Map<String, Object>> newNamespaces;
387  1214 if (namespaces != null) {
388  195 newNamespaces = new HashMap<>(namespaces);
389    } else {
390  1019 newNamespaces = new HashMap<>();
391    }
392   
393    // Create the map for the namespace
394  1214 Map<String, Object> installedNamespace = new ConcurrentHashMap<String, Object>();
395  1214 newNamespaces.put(namespace, installedNamespace);
396   
397    // Set the new map of properties
398  1214 putProperty(PKEY_NAMESPACES, newNamespaces);
399   
400    // Reset the cache
401  1214 this.namespacesCache = null;
402   
403  1214 return installedNamespace;
404    } finally {
405  1214 this.propertiesLock.unlock();
406    }
407    }
408   
 
409  3 toggle @Override
410    @Deprecated
411    public boolean isDependency()
412    {
413  3 return isDependency(null);
414    }
415   
 
416  642 toggle @Override
417    public boolean isDependency(String namespace)
418    {
419  642 return isDependency(this, namespace);
420    }
421   
422    /**
423    * @param dependency indicate if the extension has been installed as a dependency of another one
424    * @see #isDependency()
425    * @deprecated
426    */
 
427  0 toggle @Deprecated
428    public void setDependency(boolean dependency)
429    {
430  0 putProperty(PKEY_DEPENDENCY, dependency);
431    }
432   
433    /**
434    * @param dependency indicate if the extension has been installed as a dependency of another one
435    * @param namespace the namespace
436    * @see #isDependency(String)
437    */
 
438  632 toggle public void setDependency(boolean dependency, String namespace)
439    {
440  632 try {
441  632 this.propertiesLock.lock();
442   
443  632 if (namespace == null) {
444  95 putProperty(PKEY_DEPENDENCY, dependency);
445    } else {
446  537 Map<String, Object> installedNamespace = getInstalledNamespace(namespace, false);
447   
448  537 if (installedNamespace != null) {
449  536 installedNamespace.put(PKEY_NAMESPACES_DEPENDENCY, dependency);
450    }
451    }
452    } finally {
453  632 this.propertiesLock.unlock();
454    }
455    }
456   
 
457  35 toggle @Override
458    public Date getInstallDate(String namespace)
459    {
460  35 return (Date) getNamespaceProperty(PKEY_DATE, namespace);
461    }
462   
463    /**
464    * Sets the date when this extension has been installed on the specified namespace.
465    *
466    * @param date the install date
467    * @param namespace the namespace for which to set the install date
468    * @since 7.0M2
469    */
 
470  631 toggle public void setInstallDate(Date date, String namespace)
471    {
472  631 setNamespaceProperty(PKEY_DATE, date, namespace);
473    }
474   
 
475  58 toggle @Override
476    public Object getNamespaceProperty(String key, String namespace)
477    {
478  58 Object value = null;
479  58 if (namespace != null) {
480  53 Map<String, Object> installedNamespace = getInstalledNamespace(namespace, false);
481  53 if (installedNamespace != null) {
482  47 value = installedNamespace.get(key);
483    }
484    }
485  58 if (value == null) {
486    // Fallback on the root namespace.
487    // Note that we don't pass an empty map as default value because the value mapped to the key can be null.
488  11 Map<String, Object> rootNamespace = getProperty(PKEY_ROOT_NAMESPACE, (Map<String, Object>) null);
489  11 if (rootNamespace != null) {
490  4 value = rootNamespace.get(key);
491    }
492    }
493  58 return value;
494    }
495   
496    /**
497    * Sets the value of the specified extension property on the given namespace.
498    *
499    * @param key the extension property to set
500    * @param value the property value
501    * @param namespace the namespace to associate the property with, {@code null} for the root namespace
502    * @since 7.0M2
503    */
 
504  631 toggle public void setNamespaceProperty(String key, Object value, String namespace)
505    {
506  631 try {
507  631 this.propertiesLock.lock();
508   
509  631 Map<String, Object> namespaceProperties = getNamespaceProperties(namespace);
510  631 if (namespaceProperties != null) {
511  629 namespaceProperties.put(key, value);
512    }
513    } finally {
514  631 this.propertiesLock.unlock();
515    }
516    }
517   
518    /**
519    * @param namespace the namespace to look for
520    * @return the custom extension properties associated with the specified namespace
521    * @since 7.0M2
522    */
 
523  1256 toggle public Map<String, Object> getNamespaceProperties(String namespace)
524    {
525  1256 if (namespace == null) {
526  187 return getProperty(PKEY_ROOT_NAMESPACE, (Map<String, Object>) null);
527    } else {
528  1069 return getInstalledNamespace(namespace, false);
529    }
530    }
531   
532    // LocalExtension
533   
 
534  2057 toggle @Override
535    public LocalExtensionFile getFile()
536    {
537  2057 return getLocalExtension().getFile();
538    }
539    }