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

File AbstractExtensionJob.java

 

Coverage histogram

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

Code metrics

32
87
8
1
348
225
27
0.31
10.88
8
3.38

Classes

Class Line # Actions
AbstractExtensionJob 71 87 0% 27 14
0.889763889%
 

Contributing tests

This file is covered by 113 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.Arrays;
24    import java.util.Collection;
25    import java.util.Collections;
26    import java.util.List;
27    import java.util.Map;
28   
29    import javax.inject.Inject;
30   
31    import org.xwiki.extension.Extension;
32    import org.xwiki.extension.ExtensionException;
33    import org.xwiki.extension.ExtensionId;
34    import org.xwiki.extension.InstallException;
35    import org.xwiki.extension.InstalledExtension;
36    import org.xwiki.extension.LocalExtension;
37    import org.xwiki.extension.UninstallException;
38    import org.xwiki.extension.event.ExtensionInstallFailedEvent;
39    import org.xwiki.extension.event.ExtensionInstalledEvent;
40    import org.xwiki.extension.event.ExtensionInstallingEvent;
41    import org.xwiki.extension.event.ExtensionUninstallFailedEvent;
42    import org.xwiki.extension.event.ExtensionUninstalledEvent;
43    import org.xwiki.extension.event.ExtensionUninstallingEvent;
44    import org.xwiki.extension.event.ExtensionUpgradeFailedEvent;
45    import org.xwiki.extension.event.ExtensionUpgradedEvent;
46    import org.xwiki.extension.event.ExtensionUpgradingEvent;
47    import org.xwiki.extension.handler.ExtensionHandlerManager;
48    import org.xwiki.extension.job.ExtensionRequest;
49    import org.xwiki.extension.job.InstallRequest;
50    import org.xwiki.extension.job.plan.ExtensionPlanAction;
51    import org.xwiki.extension.job.plan.ExtensionPlanAction.Action;
52    import org.xwiki.extension.repository.InstalledExtensionRepository;
53    import org.xwiki.extension.repository.LocalExtensionRepository;
54    import org.xwiki.job.AbstractJob;
55    import org.xwiki.job.GroupedJob;
56    import org.xwiki.job.JobGroupPath;
57    import org.xwiki.job.Request;
58    import org.xwiki.job.event.status.JobStatus;
59    import org.xwiki.logging.marker.BeginTranslationMarker;
60    import org.xwiki.logging.marker.EndTranslationMarker;
61    import org.xwiki.logging.marker.TranslationMarker;
62   
63    /**
64    * Base class for any Job dealing with extensions.
65    *
66    * @param <R> the type of the request
67    * @param <S> the type of the {@link org.xwiki.job.event.status.JobStatus}
68    * @version $Id: 8d650a0c03d79a4d36a6795f341736ea325ad8e3 $
69    * @since 4.0M1
70    */
 
71    public abstract class AbstractExtensionJob<R extends ExtensionRequest, S extends JobStatus> extends AbstractJob<R, S>
72    implements GroupedJob
73    {
74    /**
75    * The key to use to access the context extension plan.
76    */
77    public static final String CONTEXTKEY_PLAN = "job.extension.plan";
78   
79    /**
80    * The root group of all extension related jobs.
81    */
82    public static final JobGroupPath ROOT_GROUP = new JobGroupPath(Arrays.asList("extension"));
83   
84    /**
85    * Used to manipulate local extension repository.
86    */
87    @Inject
88    protected LocalExtensionRepository localExtensionRepository;
89   
90    /**
91    * Used to install the extension itself depending of its type.
92    */
93    @Inject
94    protected ExtensionHandlerManager extensionHandlerManager;
95   
96    /**
97    * Used to manipulate installed extension repository.
98    */
99    @Inject
100    protected InstalledExtensionRepository installedExtensionRepository;
101   
102    protected JobGroupPath groupPath;
103   
 
104  475 toggle @Override
105    public void initialize(Request request)
106    {
107  475 super.initialize(request);
108   
109    // Build the group path
110  475 if (getRequest().getNamespaces() != null && getRequest().getNamespaces().size() == 1) {
111  268 this.groupPath = new JobGroupPath(getRequest().getNamespaces().iterator().next(), ROOT_GROUP);
112    } else {
113  207 this.groupPath = ROOT_GROUP;
114    }
115    }
116   
 
117  257 toggle @Override
118    public JobGroupPath getGroupPath()
119    {
120  257 return this.groupPath;
121    }
122   
 
123  670 toggle private static TranslationMarker getTranslationMarker(ExtensionPlanAction action, String extension, boolean begin)
124    {
125  670 StringBuilder str = new StringBuilder("extension.log.job.");
126   
127  670 str.append(action.getAction().toString().toLowerCase());
128   
129  670 if (extension != null) {
130  335 str.append('.');
131  335 str.append(extension);
132    }
133   
134  670 str.append('.');
135  670 str.append(begin ? "begin" : "end");
136   
137  670 if (action.getNamespace() != null) {
138  550 str.append("OnNamespace");
139    }
140   
141  670 return begin ? new BeginTranslationMarker(str.toString()) : new EndTranslationMarker(str.toString());
142    }
143   
144    /**
145    * @param actions the actions to apply
146    * @throws ExtensionException failed to apply action
147    */
 
148  185 toggle protected void applyActions(Collection<ExtensionPlanAction> actions) throws ExtensionException
149    {
150  185 this.progressManager.pushLevelProgress(actions.size(), this);
151   
152  185 try {
153  185 for (ExtensionPlanAction action : actions) {
154  846 this.progressManager.startStep(this);
155   
156  846 if (action.getAction() != Action.NONE) {
157  525 applyAction(action);
158    }
159   
160  846 this.progressManager.endStep(this);
161    }
162    } finally {
163  185 this.progressManager.popLevelProgress(this);
164    }
165    }
166   
167    /**
168    * @param action the action to perform
169    * @throws ExtensionException failed to apply action
170    */
 
171  525 toggle protected void applyAction(ExtensionPlanAction action) throws ExtensionException
172    {
173  525 Collection<InstalledExtension> previousExtensions = action.getPreviousExtensions();
174   
175  525 Extension extension = action.getExtension();
176  525 String namespace = action.getNamespace();
177   
178  525 List<ExtensionId> previousExtensionsIds;
179   
180  525 if (getRequest().isVerbose()) {
181  335 previousExtensionsIds = new ArrayList<ExtensionId>(previousExtensions.size());
182  335 for (InstalledExtension previousExtension : previousExtensions) {
183  204 previousExtensionsIds.add(previousExtension.getId());
184    }
185   
186  335 this.logger.info(getTranslationMarker(action, null, true),
187    "Applying [{}] for extension [{}] on namespace [{}] from previous extension(s) [{}]",
188    action.getAction(), extension.getId(), namespace, previousExtensionsIds);
189    } else {
190  190 previousExtensionsIds = null;
191    }
192   
193  525 try {
194  525 if (action.getAction() == Action.REPAIR) {
195  1 InstalledExtension installedExtension = (InstalledExtension) action.getExtension();
196   
197    // Initialize
198  1 repairExtension(installedExtension, namespace);
199  524 } else if (action.getAction() == Action.UNINSTALL) {
200  99 InstalledExtension installedExtension = (InstalledExtension) action.getExtension();
201   
202    // Uninstall
203  99 uninstallExtension(installedExtension, namespace);
204    } else {
205    // Store extension in local repository
206  425 LocalExtension localExtension = this.localExtensionRepository.resolve(extension.getId());
207   
208    // Install
209  425 installExtension(localExtension, previousExtensions, namespace, action.isDependency());
210    }
211   
212  525 if (getRequest().isVerbose()) {
213  335 this.logger.info(getTranslationMarker(action, "success", false),
214    "Successfully applied [{}] for extension [{}] on namespace [{}] from previous extension(s) [{}]",
215    action.getAction(), extension.getId(), namespace, previousExtensionsIds);
216    }
217    } catch (ExtensionException e) {
218  0 if (getRequest().isVerbose()) {
219  0 this.logger.error(getTranslationMarker(action, "failure", false),
220    "Failed to apply [{}] for extension [{}] on namespace [{}] from previous extension(s) [{}]",
221    action.getAction(), extension.getId(), namespace, previousExtensionsIds, e);
222    }
223   
224  0 throw e;
225    }
226    }
227   
228    /**
229    * @param installedExtension the existing extension
230    * @param namespace the namespace in which to perform the action
231    * @throws ExtensionException failed to initialize extension
232    */
 
233  1 toggle private void repairExtension(InstalledExtension installedExtension, String namespace) throws ExtensionException
234    {
235  1 this.observationManager.notify(new ExtensionInstallingEvent(installedExtension.getId(), namespace),
236    installedExtension);
237   
238  1 boolean success = false;
239  1 try {
240    // Initialize extension (invalid extensions are not initialized at startup)
241  1 this.extensionHandlerManager.initialize(installedExtension, namespace);
242   
243    // Repair the extension
244  1 this.installedExtensionRepository.installExtension(installedExtension, namespace,
245    installedExtension.isDependency(namespace));
246   
247  1 success = true;
248    } finally {
249  1 if (success) {
250  1 this.observationManager.notify(new ExtensionInstalledEvent(installedExtension.getId(), namespace),
251    installedExtension);
252    } else {
253  0 this.observationManager.notify(new ExtensionInstallFailedEvent(installedExtension.getId(), namespace),
254    installedExtension);
255    }
256    }
257    }
258   
259    /**
260    * @param installedExtension the existing extension
261    * @param namespace the namespace in which to perform the action
262    * @throws UninstallException failed to uninstall extension
263    */
 
264  99 toggle private void uninstallExtension(InstalledExtension installedExtension, String namespace) throws UninstallException
265    {
266  99 this.observationManager.notify(new ExtensionUninstallingEvent(installedExtension.getId(), namespace),
267    installedExtension);
268   
269  99 boolean success = false;
270  99 try {
271    // Unload extension
272  99 this.extensionHandlerManager.uninstall(installedExtension, namespace, getRequest());
273   
274    // Uninstall from local repository
275  99 this.installedExtensionRepository.uninstallExtension(installedExtension, namespace);
276   
277  99 success = true;
278    } finally {
279  99 if (success) {
280  99 this.observationManager.notify(new ExtensionUninstalledEvent(installedExtension.getId(), namespace),
281    installedExtension);
282    } else {
283  0 this.observationManager.notify(new ExtensionUninstallFailedEvent(installedExtension.getId(), namespace),
284    installedExtension);
285    }
286    }
287    }
288   
289    /**
290    * @param extension the extension
291    * @param previousExtensions the previous extensions when upgrading
292    * @param namespace the namespace in which to perform the action
293    * @param dependency indicate if the extension has been installed as dependency
294    * @throws InstallException failed to install extension
295    */
 
296  425 toggle private void installExtension(LocalExtension extension, Collection<InstalledExtension> previousExtensions,
297    String namespace, boolean dependency) throws InstallException
298    {
299  425 Map<String, Object> properties = getRequest().getProperty(InstallRequest.PROPERTY_EXTENSION_PROPERTIES,
300    Collections.<String, Object>emptyMap());
301  425 if (previousExtensions.isEmpty()) {
302  304 this.observationManager.notify(new ExtensionInstallingEvent(extension.getId(), namespace), extension);
303   
304  304 InstalledExtension installedExtension = null;
305  304 try {
306  304 this.extensionHandlerManager.install(extension, namespace, getRequest());
307   
308  304 installedExtension =
309    this.installedExtensionRepository.installExtension(extension, namespace, dependency, properties);
310    } finally {
311  304 if (installedExtension != null) {
312  304 this.observationManager.notify(new ExtensionInstalledEvent(extension.getId(), namespace),
313    installedExtension);
314    } else {
315  0 this.observationManager.notify(new ExtensionInstallFailedEvent(extension.getId(), namespace),
316    extension);
317    }
318    }
319    } else {
320  121 this.observationManager.notify(new ExtensionUpgradingEvent(extension.getId(), namespace), extension,
321    previousExtensions);
322   
323  121 InstalledExtension installedExtension = null;
324  121 try {
325  121 this.extensionHandlerManager.upgrade(previousExtensions, extension, namespace, getRequest());
326   
327  121 for (InstalledExtension previousExtension : previousExtensions) {
328  121 try {
329  121 this.installedExtensionRepository.uninstallExtension(previousExtension, namespace);
330    } catch (UninstallException e) {
331  0 this.logger.error("Failed to uninstall extension [" + previousExtension.getId() + "]", e);
332    }
333    }
334   
335  121 installedExtension =
336    this.installedExtensionRepository.installExtension(extension, namespace, dependency, properties);
337    } finally {
338  121 if (installedExtension != null) {
339  121 this.observationManager.notify(new ExtensionUpgradedEvent(extension.getId(), namespace),
340    installedExtension, previousExtensions);
341    } else {
342  0 this.observationManager.notify(new ExtensionUpgradeFailedEvent(extension.getId(), namespace),
343    extension, previousExtensions);
344    }
345    }
346    }
347    }
348    }