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