1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.apache.maven.RepositoryUtils;
29 import org.apache.maven.artifact.Artifact;
30 import org.apache.maven.model.Plugin;
31 import org.apache.maven.project.MavenProject;
32 import org.codehaus.plexus.classworlds.realm.ClassRealm;
33 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
34 import org.codehaus.plexus.component.annotations.Component;
35 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
36 import org.eclipse.aether.RepositorySystemSession;
37 import org.eclipse.aether.graph.DependencyFilter;
38 import org.eclipse.aether.repository.LocalRepository;
39 import org.eclipse.aether.repository.RemoteRepository;
40 import org.eclipse.aether.repository.WorkspaceRepository;
41
42
43
44
45 @Component(role = PluginRealmCache.class)
46 public class DefaultPluginRealmCache implements PluginRealmCache, Disposable {
47
48
49
50 protected static class CacheKey implements Key {
51
52 private final Plugin plugin;
53
54 private final WorkspaceRepository workspace;
55
56 private final LocalRepository localRepo;
57
58 private final List<RemoteRepository> repositories;
59
60 private final ClassLoader parentRealm;
61
62 private final Map<String, ClassLoader> foreignImports;
63
64 private final DependencyFilter filter;
65
66 private final int hashCode;
67
68 public CacheKey(
69 Plugin plugin,
70 ClassLoader parentRealm,
71 Map<String, ClassLoader> foreignImports,
72 DependencyFilter dependencyFilter,
73 List<RemoteRepository> repositories,
74 RepositorySystemSession session) {
75 this.plugin = plugin.clone();
76 this.workspace = RepositoryUtils.getWorkspace(session);
77 this.localRepo = session.getLocalRepository();
78 this.repositories = new ArrayList<>(repositories.size());
79 for (RemoteRepository repository : repositories) {
80 if (repository.isRepositoryManager()) {
81 this.repositories.addAll(repository.getMirroredRepositories());
82 } else {
83 this.repositories.add(repository);
84 }
85 }
86 this.parentRealm = parentRealm;
87 this.foreignImports =
88 (foreignImports != null) ? foreignImports : Collections.<String, ClassLoader>emptyMap();
89 this.filter = dependencyFilter;
90
91 int hash = 17;
92 hash = hash * 31 + CacheUtils.pluginHashCode(plugin);
93 hash = hash * 31 + Objects.hashCode(workspace);
94 hash = hash * 31 + Objects.hashCode(localRepo);
95 hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
96 hash = hash * 31 + Objects.hashCode(parentRealm);
97 hash = hash * 31 + this.foreignImports.hashCode();
98 hash = hash * 31 + Objects.hashCode(dependencyFilter);
99 this.hashCode = hash;
100 }
101
102 @Override
103 public String toString() {
104 return plugin.getId();
105 }
106
107 @Override
108 public int hashCode() {
109 return hashCode;
110 }
111
112 @Override
113 public boolean equals(Object o) {
114 if (o == this) {
115 return true;
116 }
117
118 if (!(o instanceof CacheKey)) {
119 return false;
120 }
121
122 CacheKey that = (CacheKey) o;
123
124 return parentRealm == that.parentRealm
125 && CacheUtils.pluginEquals(plugin, that.plugin)
126 && Objects.equals(workspace, that.workspace)
127 && Objects.equals(localRepo, that.localRepo)
128 && RepositoryUtils.repositoriesEquals(this.repositories, that.repositories)
129 && Objects.equals(filter, that.filter)
130 && Objects.equals(foreignImports, that.foreignImports);
131 }
132 }
133
134 protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
135
136 public Key createKey(
137 Plugin plugin,
138 ClassLoader parentRealm,
139 Map<String, ClassLoader> foreignImports,
140 DependencyFilter dependencyFilter,
141 List<RemoteRepository> repositories,
142 RepositorySystemSession session) {
143 return new CacheKey(plugin, parentRealm, foreignImports, dependencyFilter, repositories, session);
144 }
145
146 public CacheRecord get(Key key) {
147 return cache.get(key);
148 }
149
150 @Override
151 public CacheRecord get(Key key, PluginRealmSupplier supplier)
152 throws PluginResolutionException, PluginContainerException {
153 try {
154 return cache.computeIfAbsent(key, k -> {
155 try {
156 return supplier.load();
157 } catch (PluginResolutionException | PluginContainerException e) {
158 throw new RuntimeException(e);
159 }
160 });
161 } catch (RuntimeException e) {
162 if (e.getCause() instanceof PluginResolutionException) {
163 throw (PluginResolutionException) e.getCause();
164 }
165 if (e.getCause() instanceof PluginContainerException) {
166 throw (PluginContainerException) e.getCause();
167 }
168 throw e;
169 }
170 }
171
172 public CacheRecord put(Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts) {
173 Objects.requireNonNull(pluginRealm, "pluginRealm cannot be null");
174 Objects.requireNonNull(pluginArtifacts, "pluginArtifacts cannot be null");
175
176 if (cache.containsKey(key)) {
177 throw new IllegalStateException("Duplicate plugin realm for plugin " + key);
178 }
179
180 CacheRecord record = new CacheRecord(pluginRealm, pluginArtifacts);
181
182 cache.put(key, record);
183
184 return record;
185 }
186
187 public void flush() {
188 for (CacheRecord record : cache.values()) {
189 ClassRealm realm = record.getRealm();
190 try {
191 realm.getWorld().disposeRealm(realm.getId());
192 } catch (NoSuchRealmException e) {
193
194 }
195 }
196 cache.clear();
197 }
198
199 protected static int pluginHashCode(Plugin plugin) {
200 return CacheUtils.pluginHashCode(plugin);
201 }
202
203 protected static boolean pluginEquals(Plugin a, Plugin b) {
204 return CacheUtils.pluginEquals(a, b);
205 }
206
207 public void register(MavenProject project, Key key, CacheRecord record) {
208
209 }
210
211 public void dispose() {
212 flush();
213 }
214 }