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

File AbstractExtensionPlanJob.java

 

Coverage histogram

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

Code metrics

18
58
8
1
286
161
21
0.36
7.25
8
2.62

Classes

Class Line # Actions
AbstractExtensionPlanJob 51 58 0% 21 7
0.916666791.7%
 

Contributing tests

This file is covered by 103 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: f9d8e7fed2271f3902cfe9274ce99462d21dd669 $
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  236 toggle @Override
81    protected DefaultExtensionPlan<R> createNewStatus(R request)
82    {
83  236 Job currentJob = this.jobContext.getCurrentJob();
84  236 JobStatus currentJobStatus = currentJob != null ? currentJob.getStatus() : null;
85  236 return new DefaultExtensionPlan<R>(request, this.observationManager, this.loggerManager, this.extensionTree,
86    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    } finally {
108  16 this.progressManager.popLevelProgress(this);
109    }
110    }
111   
112    /**
113    * @param extensionId the identifier of the extension to uninstall
114    * @param namespace the namespace from where to uninstall the extension
115    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
116    * @param withBackWard uninstall also the backward dependencies
117    * @throws UninstallException error when trying to uninstall provided extension
118    */
 
119  18 toggle protected void uninstallExtension(String extensionId, String namespace, Collection<ExtensionPlanNode> parentBranch,
120    boolean withBackWard) throws UninstallException
121    {
122  18 InstalledExtension installedExtension =
123    this.installedExtensionRepository.getInstalledExtension(extensionId, namespace);
124   
125  18 if (installedExtension == null) {
126  0 throw new UninstallException(String.format(EXCEPTION_NOTINSTALLED, extensionId));
127    }
128   
129  18 try {
130  18 uninstallExtension(installedExtension, namespace, parentBranch, withBackWard);
131    } catch (Exception e) {
132  2 throw new UninstallException("Failed to uninstall extension", e);
133    }
134    }
135   
136    /**
137    * @param installedExtension the extension to uninstall
138    * @param namespaces the namespaces from where to uninstall the extension
139    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
140    * @param withBackWard uninstall also the backward dependencies
141    * @throws UninstallException error when trying to uninstall provided extension
142    */
 
143  21 toggle protected void uninstallExtension(InstalledExtension installedExtension, Collection<String> namespaces,
144    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
145    {
146  21 this.progressManager.pushLevelProgress(namespaces.size(), this);
147   
148  21 try {
149  21 for (String namespace : namespaces) {
150  24 this.progressManager.startStep(this);
151   
152  24 uninstallExtension(installedExtension, namespace, parentBranch, withBackWard);
153    }
154    } finally {
155  21 this.progressManager.popLevelProgress(this);
156    }
157    }
158   
159    /**
160    * @param extensions the installed extensions to uninstall
161    * @param namespace the namespaces from where to uninstall the extensions
162    * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode}
163    * @param withBackWard uninstall also the backward dependencies
164    * @throws UninstallException error when trying to uninstall provided extensions
165    */
 
166  28 toggle protected void uninstallExtensions(Collection<InstalledExtension> extensions, String namespace,
167    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
168    {
169  28 this.progressManager.pushLevelProgress(extensions.size(), this);
170   
171  28 try {
172  28 for (InstalledExtension backardDependency : extensions) {
173  28 this.progressManager.startStep(this);
174   
175  28 uninstallExtension(backardDependency, namespace, parentBranch, withBackWard);
176    }
177    } finally {
178  28 this.progressManager.popLevelProgress(this);
179    }
180    }
181   
182    /**
183    * @param installedExtension the extension to uninstall
184    * @param namespace the namespace from where to uninstall the extension
185    * @param parentBranch the children of the parent {@link ExtensionPlanNode}
186    * @param withBackWard uninstall also the backward dependencies
187    * @throws UninstallException error when trying to uninstall provided extension
188    */
 
189  104 toggle protected void uninstallExtension(InstalledExtension installedExtension, String namespace,
190    Collection<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
191    {
192  104 if (namespace != null) {
193  69 if (installedExtension.getNamespaces() == null || !installedExtension.getNamespaces().contains(namespace)) {
194  0 throw new UninstallException(
195    String.format(EXCEPTION_NOTINSTALLEDNAMESPACE, installedExtension, namespace));
196    }
197    }
198   
199  104 ExtensionHandler extensionHandler;
200   
201    // Is type supported ?
202  104 try {
203  104 extensionHandler = this.componentManager.getInstance(ExtensionHandler.class, installedExtension.getType());
204    } catch (ComponentLookupException e) {
205  0 throw new UninstallException(String.format("Unsupported type [%s]", installedExtension.getType()), e);
206    }
207   
208    // Is uninstalling the extension allowed ?
209  104 extensionHandler.checkUninstall(installedExtension, namespace, getRequest());
210   
211    // Log progression
212  100 if (getRequest().isVerbose()) {
213  100 if (namespace != null) {
214  67 this.logger.info(LOG_RESOLVE_NAMESPACE, "Resolving extension [{}] from namespace [{}]",
215    installedExtension.getId(), namespace);
216    } else {
217  33 this.logger.info(LOG_RESOLVE, "Resolving extension [{}]", installedExtension.getId());
218    }
219    }
220   
221  100 List<ExtensionPlanNode> children = new ArrayList<ExtensionPlanNode>();
222   
223    // Uninstall backward dependencies
224  100 if (withBackWard) {
225  84 uninstallBackwardDependencies(installedExtension, namespace, children, withBackWard);
226    }
227   
228    // Uninstall the extension
229  100 DefaultExtensionPlanAction action = new DefaultExtensionPlanAction(installedExtension, installedExtension,
230    Collections.singleton(installedExtension), Action.UNINSTALL, namespace, false);
231  100 parentBranch.add(new DefaultExtensionPlanNode(action, children, null));
232    }
233   
234    /**
235    * @param installedExtension the extension to uninstall
236    * @param namespace the namespace from where to uninstall the extension
237    * @param parentBranch the children of the parent {@link ExtensionPlanNode}
238    * @param withBackWard uninstall also the backward dependencies
239    * @throws UninstallException error when trying to uninstall backward dependencies
240    * @throws ResolveException error when trying to resolve backward dependencies
241    */
 
242  84 toggle protected void uninstallBackwardDependencies(InstalledExtension installedExtension, String namespace,
243    List<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException
244    {
245  84 try {
246  84 if (namespace != null) {
247  55 Collection<InstalledExtension> installedExtensions = this.installedExtensionRepository
248    .getBackwardDependencies(installedExtension.getId().getId(), namespace);
249  55 if (!installedExtensions.isEmpty()) {
250  8 uninstallExtensions(installedExtensions, namespace, parentBranch, withBackWard);
251    }
252    } else {
253  29 uninstallBackwardDependencies(installedExtension, parentBranch, withBackWard);
254    }
255    } catch (ResolveException e) {
256  0 throw new UninstallException(
257    "Failed to resolve backward dependencies of extension [" + installedExtension + "]", e);
258    }
259    }
260   
261    /**
262    * @param installedExtension the extension to uninstall
263    * @param parentBranch the children of the parent {@link ExtensionPlanNode}
264    * @param withBackWard uninstall also the backward dependencies
265    * @throws UninstallException error when trying to uninstall backward dependencies
266    * @throws ResolveException error when trying to resolve backward dependencies
267    */
 
268  29 toggle protected void uninstallBackwardDependencies(InstalledExtension installedExtension,
269    List<ExtensionPlanNode> parentBranch, boolean withBackWard) throws UninstallException, ResolveException
270    {
271  29 Map<String, Collection<InstalledExtension>> backwardDependencies =
272    this.installedExtensionRepository.getBackwardDependencies(installedExtension.getId());
273   
274  29 this.progressManager.pushLevelProgress(backwardDependencies.size(), this);
275   
276  29 try {
277  29 for (Map.Entry<String, Collection<InstalledExtension>> entry : backwardDependencies.entrySet()) {
278  20 this.progressManager.startStep(this);
279   
280  20 uninstallExtensions(entry.getValue(), entry.getKey(), parentBranch, withBackWard);
281    }
282    } finally {
283  29 this.progressManager.popLevelProgress(this);
284    }
285    }
286    }