1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
|
|
21 |
|
package org.xwiki.extension.jar.internal.handler; |
22 |
|
|
23 |
|
import java.util.Arrays; |
24 |
|
import java.util.Collection; |
25 |
|
import java.util.HashMap; |
26 |
|
import java.util.HashSet; |
27 |
|
import java.util.List; |
28 |
|
import java.util.Map; |
29 |
|
import java.util.Set; |
30 |
|
import java.util.Stack; |
31 |
|
|
32 |
|
import javax.inject.Inject; |
33 |
|
import javax.inject.Named; |
34 |
|
import javax.inject.Singleton; |
35 |
|
|
36 |
|
import org.slf4j.Logger; |
37 |
|
import org.xwiki.classloader.ClassLoaderManager; |
38 |
|
import org.xwiki.component.annotation.Component; |
39 |
|
import org.xwiki.context.Execution; |
40 |
|
import org.xwiki.context.ExecutionContext; |
41 |
|
import org.xwiki.extension.ExtensionId; |
42 |
|
import org.xwiki.extension.InstalledExtension; |
43 |
|
import org.xwiki.extension.ResolveException; |
44 |
|
import org.xwiki.extension.UninstallException; |
45 |
|
import org.xwiki.extension.event.ExtensionEvent; |
46 |
|
import org.xwiki.extension.event.ExtensionUninstalledEvent; |
47 |
|
import org.xwiki.extension.event.ExtensionUpgradedEvent; |
48 |
|
import org.xwiki.extension.handler.ExtensionHandler; |
49 |
|
import org.xwiki.extension.handler.ExtensionInitializer; |
50 |
|
import org.xwiki.extension.repository.InstalledExtensionRepository; |
51 |
|
import org.xwiki.job.event.JobFinishingEvent; |
52 |
|
import org.xwiki.job.event.JobStartedEvent; |
53 |
|
import org.xwiki.observation.EventListener; |
54 |
|
import org.xwiki.observation.event.Event; |
55 |
|
|
56 |
|
|
57 |
|
|
58 |
|
|
59 |
|
@version |
60 |
|
@since |
61 |
|
|
62 |
|
@Component |
63 |
|
@Singleton |
64 |
|
@Named("JarExtensionJobFinishingListener") |
|
|
| 87.4% |
Uncovered Elements: 20 (159) |
Complexity: 44 |
Complexity Density: 0.45 |
|
65 |
|
public class JarExtensionJobFinishingListener implements EventListener |
66 |
|
{ |
|
|
| 100% |
Uncovered Elements: 0 (13) |
Complexity: 4 |
Complexity Density: 0.67 |
|
67 |
|
private static final class UninstalledExtensionCollection |
68 |
|
{ |
69 |
|
private boolean rootNamespace; |
70 |
|
|
71 |
|
private Set<String> namespaces; |
72 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (12) |
Complexity: 4 |
Complexity Density: 0.67 |
|
73 |
39 |
private void add(String namespace)... |
74 |
|
{ |
75 |
39 |
if (!this.rootNamespace) { |
76 |
38 |
if (namespace != null) { |
77 |
29 |
if (this.namespaces == null) { |
78 |
21 |
this.namespaces = new HashSet<String>(); |
79 |
|
} |
80 |
29 |
this.namespaces.add(namespace); |
81 |
|
} else { |
82 |
9 |
this.rootNamespace = true; |
83 |
|
} |
84 |
|
} |
85 |
|
} |
86 |
|
} |
87 |
|
|
88 |
|
|
89 |
|
private static final List<Event> EVENTS = Arrays.asList(new ExtensionUninstalledEvent(), |
90 |
|
new ExtensionUpgradedEvent(), new JobStartedEvent(), new JobFinishingEvent()); |
91 |
|
|
92 |
|
|
93 |
|
|
94 |
|
|
95 |
|
@Inject |
96 |
|
private ClassLoaderManager jarExtensionClassLoader; |
97 |
|
|
98 |
|
|
99 |
|
|
100 |
|
|
101 |
|
@Inject |
102 |
|
private ExtensionInitializer extensionInitializer; |
103 |
|
|
104 |
|
|
105 |
|
|
106 |
|
|
107 |
|
@Inject |
108 |
|
private InstalledExtensionRepository installedExtensionRepository; |
109 |
|
|
110 |
|
@Inject |
111 |
|
@Named(JarExtensionHandler.JAR) |
112 |
|
private ExtensionHandler jarHandler; |
113 |
|
|
114 |
|
@Inject |
115 |
|
private Execution execution; |
116 |
|
|
117 |
|
|
118 |
|
|
119 |
|
|
120 |
|
@Inject |
121 |
|
private Logger logger; |
122 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
123 |
157 |
@Override... |
124 |
|
public String getName() |
125 |
|
{ |
126 |
157 |
return "JarExtensionJobFinishedListener"; |
127 |
|
} |
128 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
129 |
25 |
@Override... |
130 |
|
public List<Event> getEvents() |
131 |
|
{ |
132 |
25 |
return EVENTS; |
133 |
|
} |
134 |
|
|
|
|
| 83.3% |
Uncovered Elements: 1 (6) |
Complexity: 2 |
Complexity Density: 0.5 |
|
135 |
194 |
private void pushUninstallLevel()... |
136 |
|
{ |
137 |
194 |
ExecutionContext context = this.execution.getContext(); |
138 |
|
|
139 |
194 |
if (context != null) { |
140 |
194 |
Stack<UninstalledExtensionCollection> extensions = getUninstalledExtensionCollectionStack(true); |
141 |
|
|
142 |
194 |
extensions.push(null); |
143 |
|
} |
144 |
|
} |
145 |
|
|
|
|
| 77.8% |
Uncovered Elements: 2 (9) |
Complexity: 3 |
Complexity Density: 0.6 |
|
146 |
194 |
private void popUninstallLevel()... |
147 |
|
{ |
148 |
194 |
ExecutionContext context = this.execution.getContext(); |
149 |
|
|
150 |
194 |
if (context != null) { |
151 |
194 |
Stack<UninstalledExtensionCollection> extensions = getUninstalledExtensionCollectionStack(false); |
152 |
|
|
153 |
194 |
if (extensions != null) { |
154 |
194 |
extensions.pop(); |
155 |
|
} |
156 |
|
} |
157 |
|
} |
158 |
|
|
|
|
| 84.6% |
Uncovered Elements: 2 (13) |
Complexity: 4 |
Complexity Density: 0.44 |
|
159 |
621 |
private Stack<UninstalledExtensionCollection> getUninstalledExtensionCollectionStack(boolean create)... |
160 |
|
{ |
161 |
621 |
ExecutionContext context = this.execution.getContext(); |
162 |
621 |
final String contextKey = "extension.jar.uninstalledExtensions"; |
163 |
|
|
164 |
621 |
if (context != null) { |
165 |
621 |
@SuppressWarnings("unchecked") |
166 |
|
Stack<UninstalledExtensionCollection> extensions = |
167 |
|
(Stack<UninstalledExtensionCollection>) context.getProperty(contextKey); |
168 |
|
|
169 |
621 |
if (extensions == null && create) { |
170 |
104 |
extensions = new Stack<UninstalledExtensionCollection>(); |
171 |
104 |
context.setProperty(contextKey, extensions); |
172 |
|
} |
173 |
|
|
174 |
621 |
return extensions; |
175 |
|
} |
176 |
|
|
177 |
0 |
return null; |
178 |
|
} |
179 |
|
|
|
|
| 81.2% |
Uncovered Elements: 3 (16) |
Complexity: 5 |
Complexity Density: 0.5 |
|
180 |
233 |
private UninstalledExtensionCollection getCurrentJobUninstalledExtensions(boolean create)... |
181 |
|
{ |
182 |
233 |
ExecutionContext context = this.execution.getContext(); |
183 |
|
|
184 |
233 |
if (context != null) { |
185 |
233 |
Stack<UninstalledExtensionCollection> extensions = getUninstalledExtensionCollectionStack(false); |
186 |
|
|
187 |
233 |
if (extensions != null) { |
188 |
233 |
UninstalledExtensionCollection collection = extensions.peek(); |
189 |
|
|
190 |
233 |
if (collection == null && create) { |
191 |
28 |
collection = new UninstalledExtensionCollection(); |
192 |
28 |
extensions.set(extensions.size() - 1, collection); |
193 |
|
} |
194 |
|
|
195 |
233 |
return collection; |
196 |
|
} |
197 |
|
} |
198 |
|
|
199 |
0 |
return null; |
200 |
|
} |
201 |
|
|
|
|
| 80% |
Uncovered Elements: 1 (5) |
Complexity: 2 |
Complexity Density: 0.67 |
|
202 |
39 |
private void addUninstalledExtension(ExtensionId id, String namespace)... |
203 |
|
{ |
204 |
39 |
UninstalledExtensionCollection collection = getCurrentJobUninstalledExtensions(true); |
205 |
|
|
206 |
39 |
if (collection != null) { |
207 |
39 |
collection.add(namespace); |
208 |
|
} |
209 |
|
} |
210 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (14) |
Complexity: 4 |
Complexity Density: 0.5 |
|
211 |
441 |
@Override... |
212 |
|
public void onEvent(Event event, Object source, Object data) |
213 |
|
{ |
214 |
441 |
if (event instanceof ExtensionUninstalledEvent) { |
215 |
48 |
onExtensionRemovedEvent((ExtensionUninstalledEvent) event, (InstalledExtension) source); |
216 |
393 |
} else if (event instanceof ExtensionUpgradedEvent) { |
217 |
5 |
for (InstalledExtension previous : (Collection<InstalledExtension>) data) { |
218 |
5 |
onExtensionRemovedEvent((ExtensionUpgradedEvent) event, previous); |
219 |
|
} |
220 |
388 |
} else if (event instanceof JobStartedEvent) { |
221 |
194 |
onJobStartedEvent(); |
222 |
|
} else { |
223 |
194 |
onJobFinishedEvent(); |
224 |
|
} |
225 |
|
} |
226 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (4) |
Complexity: 2 |
Complexity Density: 1 |
|
227 |
53 |
private void onExtensionRemovedEvent(ExtensionEvent event, InstalledExtension extension)... |
228 |
|
{ |
229 |
53 |
if (JarExtensionHandler.isSupported(extension.getType())) { |
230 |
39 |
addUninstalledExtension(event.getExtensionId(), event.getNamespace()); |
231 |
|
} |
232 |
|
} |
233 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
234 |
194 |
private void onJobStartedEvent()... |
235 |
|
{ |
236 |
194 |
pushUninstallLevel(); |
237 |
|
} |
238 |
|
|
|
|
| 95% |
Uncovered Elements: 1 (20) |
Complexity: 4 |
Complexity Density: 0.29 |
|
239 |
194 |
private void onJobFinishedEvent()... |
240 |
|
{ |
241 |
194 |
UninstalledExtensionCollection collection = getCurrentJobUninstalledExtensions(false); |
242 |
|
|
243 |
194 |
popUninstallLevel(); |
244 |
|
|
245 |
194 |
if (collection != null) { |
246 |
28 |
if (collection.rootNamespace) { |
247 |
|
|
248 |
9 |
unloadJARsFromNamespace(null, null); |
249 |
|
|
250 |
|
|
251 |
9 |
this.jarExtensionClassLoader.dropURLClassLoaders(); |
252 |
|
|
253 |
|
|
254 |
9 |
this.extensionInitializer.initialize(null, JarExtensionHandler.JAR); |
255 |
|
|
256 |
9 |
this.extensionInitializer.initialize(null, JarExtensionHandler.WEBJAR); |
257 |
19 |
} else if (collection.namespaces != null) { |
258 |
19 |
for (String namespace : collection.namespaces) { |
259 |
|
|
260 |
21 |
unloadJARsFromNamespace(namespace, null); |
261 |
|
|
262 |
|
|
263 |
21 |
this.jarExtensionClassLoader.dropURLClassLoader(namespace); |
264 |
|
|
265 |
|
|
266 |
21 |
this.extensionInitializer.initialize(namespace, JarExtensionHandler.JAR); |
267 |
|
|
268 |
21 |
this.extensionInitializer.initialize(namespace, JarExtensionHandler.WEBJAR); |
269 |
|
} |
270 |
|
} |
271 |
|
} |
272 |
|
} |
273 |
|
|
|
|
| 85.7% |
Uncovered Elements: 3 (21) |
Complexity: 7 |
Complexity Density: 0.54 |
|
274 |
30 |
private void unloadJARsFromNamespace(String namespace, Map<String, Set<InstalledExtension>> unloadedExtensions)... |
275 |
|
{ |
276 |
30 |
Map<String, Set<InstalledExtension>> unloadedExtensionsMap = unloadedExtensions; |
277 |
30 |
if (unloadedExtensionsMap == null) { |
278 |
30 |
unloadedExtensionsMap = new HashMap<>(); |
279 |
|
} |
280 |
|
|
281 |
|
|
282 |
30 |
Collection<InstalledExtension> installedExtensions; |
283 |
30 |
if (namespace != null) { |
284 |
21 |
installedExtensions = this.installedExtensionRepository.getInstalledExtensions(namespace); |
285 |
|
} else { |
286 |
9 |
installedExtensions = this.installedExtensionRepository.getInstalledExtensions(); |
287 |
|
} |
288 |
|
|
289 |
30 |
for (InstalledExtension installedExtension : installedExtensions) { |
290 |
95 |
if (JarExtensionHandler.isSupported(installedExtension.getType())) { |
291 |
95 |
if (namespace == null || !installedExtension.isInstalled(null)) { |
292 |
50 |
try { |
293 |
50 |
unloadJAR(installedExtension, namespace, unloadedExtensionsMap); |
294 |
|
} catch (Exception e) { |
295 |
0 |
this.logger.error("Failed to unload installed extension [{}]", installedExtension, e); |
296 |
|
} |
297 |
|
} |
298 |
|
} |
299 |
|
} |
300 |
|
} |
301 |
|
|
|
|
| 81.5% |
Uncovered Elements: 5 (27) |
Complexity: 6 |
Complexity Density: 0.32 |
|
302 |
68 |
private void unloadJAR(InstalledExtension installedExtension, String namespace,... |
303 |
|
Map<String, Set<InstalledExtension>> unloadedExtensions) throws UninstallException |
304 |
|
{ |
305 |
68 |
Set<InstalledExtension> unloadedExtensionsInNamespace = unloadedExtensions.get(namespace); |
306 |
|
|
307 |
68 |
if (unloadedExtensionsInNamespace == null) { |
308 |
39 |
unloadedExtensionsInNamespace = new HashSet<InstalledExtension>(); |
309 |
39 |
unloadedExtensions.put(namespace, unloadedExtensionsInNamespace); |
310 |
|
} |
311 |
|
|
312 |
68 |
if (unloadedExtensionsInNamespace.contains(installedExtension)) { |
313 |
0 |
return; |
314 |
|
} |
315 |
68 |
if (namespace == null) { |
316 |
35 |
if (installedExtension.isInstalled(null)) { |
317 |
17 |
try { |
318 |
17 |
Map<String, Collection<InstalledExtension>> bDependencies = |
319 |
|
this.installedExtensionRepository.getBackwardDependencies(installedExtension.getId()); |
320 |
|
|
321 |
17 |
for (Map.Entry<String, Collection<InstalledExtension>> entry : bDependencies.entrySet()) { |
322 |
0 |
for (InstalledExtension bDependency : entry.getValue()) { |
323 |
0 |
unloadJAR(bDependency, entry.getKey(), unloadedExtensions); |
324 |
|
} |
325 |
|
} |
326 |
|
} catch (ResolveException e) { |
327 |
0 |
this.logger.error("Failed to get backward dependencies for installed extension [{}]", |
328 |
|
installedExtension, e); |
329 |
|
} |
330 |
|
|
331 |
17 |
this.jarHandler.uninstall(installedExtension, null, null); |
332 |
17 |
unloadedExtensionsInNamespace.add(installedExtension); |
333 |
|
} else { |
334 |
18 |
for (String namespace2 : installedExtension.getNamespaces()) { |
335 |
18 |
unloadJAR(installedExtension, namespace2, unloadedExtensions); |
336 |
|
} |
337 |
|
} |
338 |
|
} else { |
339 |
33 |
unloadJARFromNamespace(installedExtension, namespace, unloadedExtensions, unloadedExtensionsInNamespace); |
340 |
|
} |
341 |
|
} |
342 |
|
|
|
|
| 71.4% |
Uncovered Elements: 2 (7) |
Complexity: 2 |
Complexity Density: 0.29 |
|
343 |
33 |
private void unloadJARFromNamespace(InstalledExtension installedExtension, String namespace,... |
344 |
|
Map<String, Set<InstalledExtension>> unloadedExtensions, Set<InstalledExtension> unloadedExtensionsInNamespace) |
345 |
|
throws UninstallException |
346 |
|
{ |
347 |
33 |
try { |
348 |
33 |
Collection<InstalledExtension> bDependencies = this.installedExtensionRepository |
349 |
|
.getBackwardDependencies(installedExtension.getId().getId(), namespace); |
350 |
|
|
351 |
33 |
for (InstalledExtension bDependency : bDependencies) { |
352 |
0 |
unloadJAR(bDependency, namespace, unloadedExtensions); |
353 |
|
} |
354 |
|
} catch (ResolveException e) { |
355 |
0 |
this.logger.error("Failed to get backward dependencies for installed extension [{}] on namespace [{}]", |
356 |
|
installedExtension, namespace, e); |
357 |
|
} |
358 |
|
|
359 |
33 |
this.jarHandler.uninstall(installedExtension, namespace, null); |
360 |
33 |
unloadedExtensionsInNamespace.add(installedExtension); |
361 |
|
} |
362 |
|
} |