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

File AbstractExtensionPlanJob.java

 

Coverage histogram

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

Code metrics

20
64
8
1
301
169
22
0.34
8
8
2.75

Classes

Class Line # Actions
AbstractExtensionPlanJob 51 64 0% 22 6
0.934782693.5%
 

Contributing tests

This file is covered by 110 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.Collections;
25    import java.util.List;
26    import java.util.Map;
27   
28    import org.xwiki.component.manager.ComponentLookupException;
29    import org.xwiki.extension.InstalledExtension;
30    import org.xwiki.extension.ResolveException;
31    import org.xwiki.extension.UninstallException;
32    import org.xwiki.extension.handler.ExtensionHandler;
33    import org.xwiki.extension.job.ExtensionRequest;
34    import org.xwiki.extension.job.plan.ExtensionPlanAction.Action;
35    import org.xwiki.extension.job.plan.ExtensionPlanNode;
36    import org.xwiki.extension.job.plan.internal.DefaultExtensionPlan;
37    import org.xwiki.extension.job.plan.internal.DefaultExtensionPlanAction;
38    import org.xwiki.extension.job.plan.internal.DefaultExtensionPlanNode;
39    import org.xwiki.extension.job.plan.internal.DefaultExtensionPlanTree;
40    import org.xwiki.job.Job;
41    import org.xwiki.job.event.status.JobStatus;
42    import org.xwiki.logging.marker.TranslationMarker;
43   
44    /**
45    * Base class for plan calculation jobs.
46    *
47    * @param <R> the type of the request
48    * @version $Id: 29e49661803893e5bdbe458ca5eeab3adfac62fa $
49    * @since 5.4RC1
50    */
 
51    public abstract class AbstractExtensionPlanJob<R extends ExtensionRequest>
52    extends AbstractExtensionJob<R, DefaultExtensionPlan<R>>
53    {
54    protected static final TranslationMarker LOG_RESOLVE = new TranslationMarker("extension.log.job.plan.resolve");
55   
56    protected static final TranslationMarker LOG_RESOLVE_NAMESPACE =
57    new TranslationMarker("extension.log.job.plan.resolve.namespace");
58   
59    protected static final TranslationMarker LOG_RESOLVEDEPENDENCY =
60    new TranslationMarker("extension.log.job.plan.resolvedependency");
61   
62    protected static final TranslationMarker LOG_RESOLVEDEPENDENCY_NAMESPACE =
63    new TranslationMarker("extension.log.job.plan.resolvedependency.namespace");
64   
65    /**
66    * Error message used in exception throw when trying to uninstall an extension which is not installed.
67    */
68    private static final String EXCEPTION_NOTINSTALLED = "Extension [%s] is not installed";
69   
70    /**
71    * Error message used in exception throw when trying to uninstall an extension which is not installed.
72    */
73    private static final String EXCEPTION_NOTINSTALLEDNAMESPACE = EXCEPTION_NOTINSTALLED + " on namespace [%s]";
74   
75    /**
76    * The install plan.
77    */
78    protected DefaultExtensionPlanTree extensionTree = new DefaultExtensionPlanTree();
79   
 
80  257 toggle @Override
81    protected DefaultExtensionPlan<R> createNewStatus(R request)
82    {
83  257 Job currentJob = this.jobContext.getCurrentJob();
84  257 JobStatus currentJobStatus = currentJob != null ? currentJob.getStatus() : null;
85  257 return new DefaultExtensionPlan<>(getType(), request, this.observationManager, this.loggerManager,
86    this.extensionTree, currentJobStatus);
87    }
88   
89    /**
90    * @param extensionId the identifier of the extension to uninstall
91    * @param namespaces the namespaces from where to uninstall the extension
92    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
93    * @param withBackWard uninstall also the backward dependencies
94    * @throws UninstallException error when trying to uninstall provided extensions
95    */
 
96  16 toggle protected void uninstallExtension(String extensionId, Collection<String> namespaces,
97    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
98    {
99  16 this.progressManager.pushLevelProgress(namespaces.size(), this);
100   
101  16 try {
102  16 for (String namespace : namespaces) {
103  16 this.progressManager.startStep(this);
104   
105  16 uninstallExtension(extensionId, namespace, parentBranch, withBackWard);
106   
107  15 this.progressManager.endStep(this);
108    }
109    } finally {
110  16 this.progressManager.popLevelProgress(this);
111    }
112    }
113   
114    /**
115    * @param extensionId the identifier of the extension to uninstall
116    * @param namespace the namespace from where to uninstall the extension
117    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
118    * @param withBackWard uninstall also the backward dependencies
119    * @throws UninstallException error when trying to uninstall provided extension
120    */
 
121  18 toggle protected void uninstallExtension(String extensionId, String namespace, Collection<ExtensionPlanNode> parentBranch,
122    boolean withBackWard) throws UninstallException
123    {
124  18 InstalledExtension installedExtension =
125    this.installedExtensionRepository.getInstalledExtension(extensionId, namespace);
126   
127  18 if (installedExtension == null) {
128  0 throw new UninstallException(String.format(EXCEPTION_NOTINSTALLED, extensionId));
129    }
130   
131  18 try {
132  18 uninstallExtension(installedExtension, namespace, parentBranch, withBackWard);
133    } catch (Exception e) {
134  2 throw new UninstallException("Failed to uninstall extension", e);
135    }
136    }
137   
138    /**
139    * @param installedExtension the extension to uninstall
140    * @param namespaces the namespaces from where to uninstall the extension
141    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
142    * @param withBackWard uninstall also the backward dependencies
143    * @throws UninstallException error when trying to uninstall provided extension
144    */
 
145  21 toggle protected void uninstallExtension(InstalledExtension installedExtension, Collection<String> namespaces,
146    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
147    {
148  21 this.progressManager.pushLevelProgress(namespaces.size(), this);
149   
150  21 try {
151  21 for (String namespace : namespaces) {
152  24 this.progressManager.startStep(this);
153   
154  24 uninstallExtension(installedExtension, namespace, parentBranch, withBackWard);
155   
156  23 this.progressManager.endStep(this);
157    }
158    } finally {
159  21 this.progressManager.popLevelProgress(this);
160    }
161    }
162   
163    /**
164    * @param extensions the installed extensions to uninstall
165    * @param namespace the namespaces from where to uninstall the extensions
166    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
167    * @param withBackWard uninstall also the backward dependencies
168    * @throws UninstallException error when trying to uninstall provided extensions
169    */
 
170  28 toggle protected void uninstallExtensions(Collection<InstalledExtension> extensions, String namespace,
171    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
172    {
173  28 this.progressManager.pushLevelProgress(extensions.size(), this);
174   
175  28 try {
176  28 for (InstalledExtension backardDependency : extensions) {
177  28 this.progressManager.startStep(this);
178   
179  28 uninstallExtension(backardDependency, namespace, parentBranch, withBackWard);
180   
181  28 this.progressManager.endStep(this);
182    }
183    } finally {
184  28 this.progressManager.popLevelProgress(this);
185    }
186    }
187   
188    /**
189    * @param installedExtension the extension to uninstall
190    * @param namespace the namespace from where to uninstall the extension
191    * @param parentBranch the children of the parent {@link ExtensionPlanNode}
192    * @param withBackWard uninstall also the backward dependencies
193    * @throws UninstallException error when trying to uninstall provided extension
194    */
 
195  119 toggle protected void uninstallExtension(InstalledExtension installedExtension, String namespace,
196    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
197    {
198  119 if (namespace != null) {
199    // Make sure the extension is installed
200  81 if (installedExtension.getNamespaces() == null || !installedExtension.getNamespaces().contains(namespace)) {
201  0 throw new UninstallException(
202    String.format(EXCEPTION_NOTINSTALLEDNAMESPACE, installedExtension, namespace));
203    }
204    }
205   
206    // Make sure it's allowed to uninstall extensions
207  119 if (!getRequest().isUninstallAllowed()) {
208  1 throw new UninstallException(
209    "Uninstalling extension [" + installedExtension.getId() + "] is not allowed in this job");
210    }
211   
212  118 ExtensionHandler extensionHandler;
213   
214    // Is type supported ?
215  118 try {
216  118 extensionHandler = this.componentManager.getInstance(ExtensionHandler.class, installedExtension.getType());
217    } catch (ComponentLookupException e) {
218  0 throw new UninstallException(String.format("Unsupported type [%s]", installedExtension.getType()), e);
219    }
220   
221    // Is uninstalling the extension allowed ?
222  118 extensionHandler.checkUninstall(installedExtension, namespace, getRequest());
223   
224    // Log progression
225  114 if (getRequest().isVerbose()) {
226  101 if (namespace != null) {
227  70 this.logger.info(LOG_RESOLVE_NAMESPACE, "Resolving extension [{}] from namespace [{}]",
228    installedExtension.getId(), namespace);
229    } else {
230  31 this.logger.info(LOG_RESOLVE, "Resolving extension [{}]", installedExtension.getId());
231    }
232    }
233   
234  114 List<ExtensionPlanNode> children = new ArrayList<>();
235   
236    // Uninstall backward dependencies
237  114 if (withBackWard) {
238  86 uninstallBackwardDependencies(installedExtension, namespace, children, withBackWard);
239    }
240   
241    // Uninstall the extension
242  114 DefaultExtensionPlanAction action = new DefaultExtensionPlanAction(installedExtension, installedExtension,
243    Collections.singleton(installedExtension), Action.UNINSTALL, namespace, false);
244  114 parentBranch.add(new DefaultExtensionPlanNode(action, children, null));
245    }
246   
247    /**
248    * @param installedExtension the extension to uninstall
249    * @param namespace the namespace from where to uninstall the extension
250    * @param parentBranch the children of the parent {@link ExtensionPlanNode}
251    * @param withBackWard uninstall also the backward dependencies
252    * @throws UninstallException error when trying to uninstall backward dependencies
253    * @throws ResolveException error when trying to resolve backward dependencies
254    */
 
255  86 toggle protected void uninstallBackwardDependencies(InstalledExtension installedExtension, String namespace,
256    List<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
257    {
258  86 try {
259  86 if (namespace != null) {
260  55 Collection<InstalledExtension> installedExtensions = this.installedExtensionRepository
261    .getBackwardDependencies(installedExtension.getId().getId(), namespace);
262  55 if (!installedExtensions.isEmpty()) {
263  8 uninstallExtensions(installedExtensions, namespace, parentBranch, withBackWard);
264    }
265    } else {
266  31 uninstallBackwardDependencies(installedExtension, parentBranch, withBackWard);
267    }
268    } catch (ResolveException e) {
269  0 throw new UninstallException(
270    "Failed to resolve backward dependencies of extension [" + installedExtension + "]", e);
271    }
272    }
273   
274    /**
275    * @param installedExtension the extension to uninstall
276    * @param parentBranch the children of the parent {@link ExtensionPlanNode}
277    * @param withBackWard uninstall also the backward dependencies
278    * @throws UninstallException error when trying to uninstall backward dependencies
279    * @throws ResolveException error when trying to resolve backward dependencies
280    */
 
281  31 toggle protected void uninstallBackwardDependencies(InstalledExtension installedExtension,
282    List<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException, ResolveException
283    {
284  31 Map<String, Collection<InstalledExtension>> backwardDependencies =
285    this.installedExtensionRepository.getBackwardDependencies(installedExtension.getId());
286   
287  31 this.progressManager.pushLevelProgress(backwardDependencies.size(), this);
288   
289  31 try {
290  31 for (Map.Entry<String, Collection<InstalledExtension>> entry : backwardDependencies.entrySet()) {
291  20 this.progressManager.startStep(this);
292   
293  20 uninstallExtensions(entry.getValue(), entry.getKey(), parentBranch, withBackWard);
294   
295  20 this.progressManager.endStep(this);
296    }
297    } finally {
298  31 this.progressManager.popLevelProgress(this);
299    }
300    }
301    }