source: josm/trunk/src/org/openstreetmap/josm/plugins/PluginClassLoader.java@ 14253

Last change on this file since 14253 was 14234, checked in by Don-vip, 6 years ago

see #16047, see #16682 - make PluginClassLoader extend DynamicURLClassLoader so that plugins can add URLs to it

  • Property svn:eol-style set to native
File size: 3.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins;
3
4import java.net.URL;
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.Collection;
8import java.util.Objects;
9
10import org.openstreetmap.josm.tools.Logging;
11
12/**
13 * Class loader for JOSM plugins.
14 * <p>
15 * In addition to the classes in the plugin jar file, it loads classes of required
16 * plugins. The JOSM core classes should be provided by the parent class loader.
17 * @since 12322
18 */
19public class PluginClassLoader extends DynamicURLClassLoader {
20
21 private final Collection<PluginClassLoader> dependencies;
22
23 static {
24 ClassLoader.registerAsParallelCapable();
25 }
26
27 /**
28 * Create a new PluginClassLoader.
29 * @param urls URLs of the plugin jar file (and extra libraries)
30 * @param parent the parent class loader (for JOSM core classes)
31 * @param dependencies class loaders of required plugin; can be null
32 */
33 public PluginClassLoader(URL[] urls, ClassLoader parent, Collection<PluginClassLoader> dependencies) {
34 super(urls, parent);
35 this.dependencies = dependencies == null ? new ArrayList<>() : new ArrayList<>(dependencies);
36 }
37
38 /**
39 * Add class loader of a required plugin.
40 * This plugin will have access to the classes of the dependent plugin
41 * @param dependency the class loader of the required plugin
42 * @return {@code true} if the collection of dependencies changed as a result of the call
43 * @since 12867
44 */
45 public boolean addDependency(PluginClassLoader dependency) {
46 // Add dependency only if not already present (directly or transitively through another one)
47 boolean result = !dependencies.contains(Objects.requireNonNull(dependency, "dependency"))
48 && dependencies.stream().noneMatch(pcl -> pcl.dependencies.contains(dependency))
49 && dependencies.add(dependency);
50 if (result) {
51 // Now, remove top-level single dependencies, which would be children of the added one
52 dependencies.removeIf(pcl -> pcl.dependencies.isEmpty() && dependency.dependencies.contains(pcl));
53 }
54 return result;
55 }
56
57 @Override
58 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
59 Class<?> result = findLoadedClass(name);
60 if (result == null) {
61 for (PluginClassLoader dep : dependencies) {
62 try {
63 result = dep.loadClass(name, resolve);
64 if (result != null) {
65 return result;
66 }
67 } catch (ClassNotFoundException e) {
68 // do nothing
69 Logging.trace("Plugin class not found in {0}: {1}", dep, e.getMessage());
70 Logging.trace(e);
71 }
72 }
73 result = super.loadClass(name, resolve);
74 }
75 if (result != null) {
76 return result;
77 }
78 throw new ClassNotFoundException(name);
79 }
80
81 @Override
82 public URL findResource(String name) {
83 URL resource = super.findResource(name);
84 if (resource == null) {
85 for (PluginClassLoader dep : dependencies) {
86 resource = dep.findResource(name);
87 if (resource != null) {
88 break;
89 }
90 }
91 }
92 return resource;
93 }
94
95 @Override
96 public String toString() {
97 return "PluginClassLoader [urls=" + Arrays.toString(getURLs()) +
98 (dependencies.isEmpty() ? "" : ", dependencies=" + dependencies) + ']';
99 }
100}
Note: See TracBrowser for help on using the repository browser.