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

File AbstractExtensionJob.java

 

Coverage histogram

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

Code metrics

24
64
8
1
293
173
23
0.36
8
8
2.88

Classes

Class Line # Actions
AbstractExtensionJob 65 64 0% 23 5
0.947916794.8%
 

Contributing tests

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