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 import javax.inject.Named;
28 import javax.inject.Singleton;
29 import org.apache.maven.RepositoryUtils;
30 import org.apache.maven.artifact.Artifact;
31 import org.apache.maven.model.Plugin;
32 import org.apache.maven.project.MavenProject;
33 import org.codehaus.plexus.classworlds.realm.ClassRealm;
34 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
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 @Named
46 @Singleton
47 public class DefaultPluginRealmCache implements PluginRealmCache, Disposable {
48
49
50
51 protected static class CacheKey implements Key {
52
53 private final Plugin plugin;
54
55 private final WorkspaceRepository workspace;
56
57 private final LocalRepository localRepo;
58
59 private final List<RemoteRepository> repositories;
60
61 private final ClassLoader parentRealm;
62
63 private final Map<String, ClassLoader> foreignImports;
64
65 private final DependencyFilter filter;
66
67 private final int hashCode;
68
69 public CacheKey(
70 Plugin plugin,
71 ClassLoader parentRealm,
72 Map<String, ClassLoader> foreignImports,
73 DependencyFilter dependencyFilter,
74 List<RemoteRepository> repositories,
75 RepositorySystemSession session) {
76 this.plugin = plugin.clone();
77 this.workspace = RepositoryUtils.getWorkspace(session);
78 this.localRepo = session.getLocalRepository();
79 this.repositories = new ArrayList<>(repositories.size());
80 for (RemoteRepository repository : repositories) {
81 if (repository.isRepositoryManager()) {
82 this.repositories.addAll(repository.getMirroredRepositories());
83 } else {
84 this.repositories.add(repository);
85 }
86 }
87 this.parentRealm = parentRealm;
88 this.foreignImports = (foreignImports != null) ? foreignImports : Collections.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 }