1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.extension.job.internal

File UpgradePlanJob.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart9.png
41% of files have more coverage

Code metrics

36
108
12
1
334
225
39
0.36
9
12
3.25

Classes

Class Line # Actions
UpgradePlanJob 48 108 0% 39 16
0.897435989.7%
 

Contributing tests

This file is covered by 5 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.job.internal;
21   
22    import java.util.ArrayList;
23    import java.util.Collection;
24    import java.util.NavigableSet;
25    import java.util.TreeSet;
26   
27    import javax.inject.Named;
28   
29    import org.xwiki.component.annotation.Component;
30    import org.xwiki.extension.ExtensionId;
31    import org.xwiki.extension.InstallException;
32    import org.xwiki.extension.InstalledExtension;
33    import org.xwiki.extension.ResolveException;
34    import org.xwiki.extension.job.InstallRequest;
35    import org.xwiki.extension.job.plan.internal.DefaultExtensionPlanTree;
36    import org.xwiki.extension.repository.result.IterableResult;
37    import org.xwiki.extension.version.Version;
38    import org.xwiki.job.Request;
39   
40    /**
41    * Create an Extension upgrade plan.
42    *
43    * @version $Id: 77448bfed5dd6fa20644b941f0d50ca881877f35 $
44    * @since 4.1M1
45    */
46    @Component
47    @Named(UpgradePlanJob.JOBTYPE)
 
48    public class UpgradePlanJob extends AbstractInstallPlanJob<InstallRequest>
49    {
50    /**
51    * The id of the job.
52    */
53    public static final String JOBTYPE = "upgradeplan";
54   
55    private static final String FAILED_INSTALL_MESSAGE = "Can't install extension [{}] on namespace [{}].";
56   
 
57  62 toggle @Override
58    public String getType()
59    {
60  62 return JOBTYPE;
61    }
62   
 
63  10 toggle @Override
64    protected InstallRequest castRequest(Request request)
65    {
66  10 InstallRequest installRequest;
67  10 if (request instanceof InstallRequest) {
68  10 installRequest = (InstallRequest) request;
69    } else {
70  0 installRequest = new InstallRequest(request);
71    }
72   
73  10 return installRequest;
74    }
75   
 
76  234 toggle private boolean isSkipped(InstalledExtension extension, String namespace)
77    {
78    // Explicitly skipped extensions
79   
80  234 if (getRequest().getExcludedExtensions().contains(extension.getId())) {
81  3 return true;
82    }
83   
84    // Extensions with no backward dependencies
85   
86  231 Collection<ExtensionId> requestExtensions = getRequest().getExtensions();
87  231 boolean filterDependencies = requestExtensions == null || requestExtensions.isEmpty();
88   
89  231 if (filterDependencies) {
90    // Don't skip if the extension has not been installed as dependency
91  230 if (!extension.isDependency(namespace)) {
92  83 return false;
93    }
94   
95    // Don't skip if the extension "lost" its backward dependencies
96  147 try {
97  147 boolean hasBackwardDependencies;
98  147 if (extension.getNamespaces() == null) {
99  32 hasBackwardDependencies =
100    !this.installedExtensionRepository.getBackwardDependencies(extension.getId()).isEmpty();
101    } else {
102  115 hasBackwardDependencies = !this.installedExtensionRepository
103    .getBackwardDependencies(extension.getId().getId(), namespace).isEmpty();
104    }
105   
106  147 return hasBackwardDependencies;
107    } catch (ResolveException e) {
108    // Should never happen
109  0 this.logger.error("Failed to gather backward dependencies for extension [{}]", extension.getId(), e);
110    }
111    }
112   
113  1 return false;
114    }
115   
116    /**
117    * @param extension the extension currently installed
118    * @param namespace the namespace where the extension is installed
119    */
 
120  234 toggle protected void upgradeExtension(InstalledExtension extension, String namespace)
121    {
122  234 if (!isSkipped(extension, namespace)) {
123  127 NavigableSet<Version> versions = getVersions(extension, namespace);
124   
125    // Useless to continue if the extension does not have any available version
126  127 if (!versions.isEmpty()) {
127  127 upgradeExtension(extension, namespace, versions.descendingSet());
128    }
129    }
130    }
131   
 
132  127 toggle private NavigableSet<Version> getVersions(InstalledExtension extension, String namespace)
133    {
134  127 NavigableSet<Version> versionList = new TreeSet<>();
135   
136    // Search local versions
137  127 try {
138  127 IterableResult<Version> versions =
139    this.localExtensionRepository.resolveVersions(extension.getId().getId(), 0, -1);
140  127 for (Version version : versions) {
141  154 versionList.add(version);
142    }
143    } catch (ResolveException e) {
144  0 this.logger.debug("Failed to resolve local versions for extension id [{}]", extension.getId().getId(), e);
145    }
146   
147    // Search remote versions
148  127 try {
149  127 IterableResult<Version> versions = this.repositoryManager.resolveVersions(extension.getId().getId(), 0, -1);
150   
151  5 for (Version version : versions) {
152  10 versionList.add(version);
153    }
154    } catch (ResolveException e) {
155  122 this.logger.debug("Failed to resolve remote versions for extension id [{}]", extension.getId().getId(), e);
156    }
157   
158    // Make sure the current version is included if the extension is invalid (it's possible this version does
159    // not exist on any repository)
160  127 if (!extension.isValid(namespace)) {
161  12 versionList.add(extension.getId().getVersion());
162    }
163   
164  127 return versionList;
165    }
166   
 
167  127 toggle protected void upgradeExtension(InstalledExtension extension, String namespace, Collection<Version> versionList)
168    {
169  127 for (Version version : versionList) {
170    // Don't try to upgrade for lower versions but try to repair same version of the extension is invalid
171  127 int compare = extension.getId().getVersion().compareTo(version);
172  127 if (compare > 0 || (compare == 0 && extension.isValid(namespace))) {
173  110 break;
174    }
175   
176    // Only upgrade beta if the current is beta etc.
177  17 if (extension.getId().getVersion().getType().ordinal() <= version.getType().ordinal()) {
178  17 if (tryInstallExtension(new ExtensionId(extension.getId().getId(), version), namespace)) {
179  9 break;
180    }
181    }
182    }
183    }
184   
185    /**
186    * Try to install the provided extension and update the plan if it's working.
187    *
188    * @param extensionId the extension version to install
189    * @param namespace the namespace where to install the extension
190    * @return true if the installation would succeed, false otherwise
191    */
 
192  17 toggle protected boolean tryInstallExtension(ExtensionId extensionId, String namespace)
193    {
194  17 DefaultExtensionPlanTree currentTree = this.extensionTree.clone();
195   
196  17 try {
197  17 installExtension(extensionId, namespace, currentTree);
198   
199  9 setExtensionTree(currentTree);
200   
201  9 return true;
202    } catch (InstallException e) {
203  8 if (getRequest().isVerbose()) {
204  8 this.logger.info(FAILED_INSTALL_MESSAGE, extensionId, namespace, e);
205    } else {
206  0 this.logger.debug(FAILED_INSTALL_MESSAGE, extensionId, namespace, e);
207    }
208    }
209   
210  8 return false;
211    }
212   
 
213  6 toggle protected void upgrade(String namespace, Collection<InstalledExtension> installedExtensions)
214    {
215  6 this.progressManager.pushLevelProgress(installedExtensions.size(), this);
216   
217  6 try {
218  6 for (InstalledExtension installedExtension : installedExtensions) {
219  175 this.progressManager.startStep(this);
220   
221  175 if (namespace == null || !installedExtension.isInstalled(null)) {
222  142 upgradeExtension(installedExtension, namespace);
223    }
224   
225  175 this.progressManager.endStep(this);
226    }
227    } finally {
228  6 this.progressManager.popLevelProgress(this);
229    }
230    }
231   
 
232  6 toggle protected void upgrade(Collection<InstalledExtension> installedExtensions)
233    {
234  6 this.progressManager.pushLevelProgress(installedExtensions.size(), this);
235   
236  6 try {
237  6 for (InstalledExtension installedExtension : installedExtensions) {
238  82 this.progressManager.startStep(this);
239   
240  82 if (installedExtension.getNamespaces() == null) {
241  52 upgradeExtension(installedExtension, null);
242    } else {
243  30 this.progressManager.pushLevelProgress(installedExtension.getNamespaces().size(), this);
244   
245  30 try {
246  30 for (String namespace : installedExtension.getNamespaces()) {
247  40 this.progressManager.startStep(this);
248   
249  40 upgradeExtension(installedExtension, namespace);
250   
251  40 this.progressManager.endStep(this);
252    }
253    } finally {
254  30 this.progressManager.popLevelProgress(this);
255    }
256    }
257   
258  82 this.progressManager.endStep(this);
259    }
260    } finally {
261  6 this.progressManager.popLevelProgress(this);
262    }
263    }
264   
 
265  6 toggle protected Collection<InstalledExtension> getInstalledExtensions(String namespace)
266    {
267  6 Collection<ExtensionId> requestExtensions = getRequest().getExtensions();
268   
269  6 Collection<InstalledExtension> installedExtensions;
270   
271  6 if (requestExtensions != null && !requestExtensions.isEmpty()) {
272  0 installedExtensions = new ArrayList<>(requestExtensions.size());
273   
274  0 for (ExtensionId requestExtension : requestExtensions) {
275  0 InstalledExtension installedExtension =
276    this.installedExtensionRepository.getInstalledExtension(requestExtension);
277  0 if (installedExtension.isInstalled(namespace)) {
278  0 installedExtensions.add(installedExtension);
279    }
280    }
281    } else {
282  6 installedExtensions = this.installedExtensionRepository.getInstalledExtensions(namespace);
283    }
284   
285  6 return installedExtensions;
286    }
287   
 
288  6 toggle protected Collection<InstalledExtension> getInstalledExtensions()
289    {
290  6 Collection<ExtensionId> requestExtensions = getRequest().getExtensions();
291   
292  6 Collection<InstalledExtension> installedExtensions;
293   
294  6 if (requestExtensions != null && !requestExtensions.isEmpty()) {
295  1 installedExtensions = new ArrayList<>(requestExtensions.size());
296   
297  1 for (ExtensionId requestExtension : requestExtensions) {
298  1 InstalledExtension installedExtension =
299    this.installedExtensionRepository.getInstalledExtension(requestExtension);
300  1 installedExtensions.add(installedExtension);
301    }
302    } else {
303  5 installedExtensions = this.installedExtensionRepository.getInstalledExtensions();
304    }
305   
306  6 return installedExtensions;
307    }
308   
 
309  10 toggle @Override
310    protected void runInternal() throws Exception
311    {
312  10 Collection<String> namespaces = getRequest().getNamespaces();
313   
314  10 if (namespaces == null) {
315  6 Collection<InstalledExtension> installedExtensions = getInstalledExtensions();
316   
317  6 upgrade(installedExtensions);
318    } else {
319  4 this.progressManager.pushLevelProgress(namespaces.size(), this);
320   
321  4 try {
322  4 for (String namespace : namespaces) {
323  6 this.progressManager.startStep(this);
324   
325  6 upgrade(namespace, getInstalledExtensions(namespace));
326   
327  6 this.progressManager.endStep(this);
328    }
329    } finally {
330  4 this.progressManager.popLevelProgress(this);
331    }
332    }
333    }
334    }