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.eclipse.aether.RepositorySystemSession;
38 import org.eclipse.aether.graph.DependencyFilter;
39 import org.eclipse.aether.repository.LocalRepository;
40 import org.eclipse.aether.repository.RemoteRepository;
41 import org.eclipse.aether.repository.WorkspaceRepository;
42 import org.eclipse.sisu.PreDestroy;
43
44
45
46
47 @Singleton
48 @Named
49 public class DefaultPluginRealmCache implements PluginRealmCache {
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 =
91 (foreignImports != null) ? foreignImports : Collections.<String, ClassLoader>emptyMap();
92 this.filter = dependencyFilter;
93
94 int hash = 17;
95 hash = hash * 31 + CacheUtils.pluginHashCode(plugin);
96 hash = hash * 31 + Objects.hashCode(workspace);
97 hash = hash * 31 + Objects.hashCode(localRepo);
98 hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
99 hash = hash * 31 + Objects.hashCode(parentRealm);
100 hash = hash * 31 + this.foreignImports.hashCode();
101 hash = hash * 31 + Objects.hashCode(dependencyFilter);
102 this.hashCode = hash;
103 }
104
105 @Override
106 public String toString() {
107 return plugin.getId();
108 }
109
110 @Override
111 public int hashCode() {
112 return hashCode;
113 }
114
115 @Override
116 public boolean equals(Object o) {
117 if (o == this) {
118 return true;
119 }
120
121 if (!(o instanceof CacheKey)) {
122 return false;
123 }
124
125 CacheKey that = (CacheKey) o;
126
127 return parentRealm == that.parentRealm
128 && CacheUtils.pluginEquals(plugin, that.plugin)
129 && Objects.equals(workspace, that.workspace)
130 && Objects.equals(localRepo, that.localRepo)
131 && RepositoryUtils.repositoriesEquals(this.repositories, that.repositories)
132 && Objects.equals(filter, that.filter)
133 && Objects.equals(foreignImports, that.foreignImports);
134 }
135 }
136
137 protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
138
139 public Key createKey(
140 Plugin plugin,
141 ClassLoader parentRealm,
142 Map<String, ClassLoader> foreignImports,
143 DependencyFilter dependencyFilter,
144 List<RemoteRepository> repositories,
145 RepositorySystemSession session) {
146 return new CacheKey(plugin, parentRealm, foreignImports, dependencyFilter, repositories, session);
147 }
148
149 public CacheRecord get(Key key) {
150 return cache.get(key);
151 }
152
153 @Override
154 public CacheRecord get(Key key, PluginRealmSupplier supplier)
155 throws PluginResolutionException, PluginContainerException {
156 try {
157 return cache.computeIfAbsent(key, k -> {
158 try {
159 return supplier.load();
160 } catch (PluginResolutionException | PluginContainerException e) {
161 throw new RuntimeException(e);
162 }
163 });
164 } catch (RuntimeException e) {
165 if (e.getCause() instanceof PluginResolutionException) {
166 throw (PluginResolutionException) e.getCause();
167 }
168 if (e.getCause() instanceof PluginContainerException) {
169 throw (PluginContainerException) e.getCause();
170 }
171 throw e;
172 }
173 }
174
175 public CacheRecord put(Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts) {
176 Objects.requireNonNull(pluginRealm, "pluginRealm cannot be null");
177 Objects.requireNonNull(pluginArtifacts, "pluginArtifacts cannot be null");
178
179 if (cache.containsKey(key)) {
180 throw new IllegalStateException("Duplicate plugin realm for plugin " + key);
181 }
182
183 CacheRecord record = new CacheRecord(pluginRealm, pluginArtifacts);
184
185 cache.put(key, record);
186
187 return record;
188 }
189
190 public void flush() {
191 for (CacheRecord record : cache.values()) {
192 ClassRealm realm = record.getRealm();
193 try {
194 realm.getWorld().disposeRealm(realm.getId());
195 } catch (NoSuchRealmException e) {
196
197 }
198 }
199 cache.clear();
200 }
201
202 protected static int pluginHashCode(Plugin plugin) {
203 return CacheUtils.pluginHashCode(plugin);
204 }
205
206 protected static boolean pluginEquals(Plugin a, Plugin b) {
207 return CacheUtils.pluginEquals(a, b);
208 }
209
210 public void register(MavenProject project, Key key, CacheRecord record) {
211
212 }
213
214 @PreDestroy
215 public void dispose() {
216 flush();
217 }
218 }