1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.maven;
25
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import java.net.URLClassLoader;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.locks.Lock;
38 import java.util.concurrent.locks.ReadWriteLock;
39 import java.util.concurrent.locks.ReentrantLock;
40 import java.util.concurrent.locks.ReentrantReadWriteLock;
41 import org.modeshape.common.SystemFailureException;
42
43
44
45
46
47
48
49
50
51
52
53 private final MavenRepository repository;
54 private final Lock lock = new ReentrantLock();
55
56
57
58
59
60
61
62
63
64
65 private final Map<MavenId, ProjectClassLoader> projectClassLoaders = new HashMap<MavenId, ProjectClassLoader>();
66
67
68
69
70
71
72
73
74 this.repository = repository;
75 }
76
77 protected ProjectClassLoader getProjectClassLoader( MavenId mavenId ) {
78 ProjectClassLoader result = null;
79 try {
80 this.lock.lock();
81 result = this.projectClassLoaders.get(mavenId);
82 if (result == null) {
83
84 URL jarFileUrl = this.repository.getUrl(mavenId, ArtifactType.JAR, null);
85 URLClassLoader jarFileLoader = new URLClassLoader(new URL[] {jarFileUrl}, null);
86
87 List<MavenDependency> dependencies = this.repository.getDependencies(mavenId);
88 result = new ProjectClassLoader(mavenId, jarFileLoader);
89 result.setDependencies(dependencies);
90 this.projectClassLoaders.put(mavenId, result);
91 }
92 } catch (MalformedURLException e) {
93
94 throw new SystemFailureException(MavenI18n.errorGettingUrlForMavenProject.text(mavenId), e);
95 } finally {
96 this.lock.unlock();
97 }
98 return result;
99 }
100
101 public ProjectClassLoader getClassLoader( ClassLoader parent,
102 MavenId... mavenIds ) {
103 if (parent == null) parent = Thread.currentThread().getContextClassLoader();
104 if (parent == null) parent = this.getClass().getClassLoader();
105 ProjectClassLoader result = new ProjectClassLoader(parent);
106
107 List<MavenDependency> dependencies = new ArrayList<MavenDependency>();
108 for (MavenId mavenId : mavenIds) {
109 if (!dependencies.contains(mavenId)) {
110 MavenDependency dependency = new MavenDependency(mavenId);
111 dependencies.add(dependency);
112 }
113 }
114 result.setDependencies(dependencies);
115 return result;
116 }
117
118 public void notifyChangeInDependencies( MavenId mavenId ) {
119 List<MavenDependency> dependencies = this.repository.getDependencies(mavenId);
120 try {
121 this.lock.lock();
122 ProjectClassLoader existingLoader = this.projectClassLoaders.get(mavenId);
123 if (existingLoader != null) {
124 existingLoader.setDependencies(dependencies);
125 }
126 } finally {
127 this.lock.unlock();
128 }
129 }
130
131
132
133
134
135
136
137 protected class ProjectClassLoader extends ClassLoader {
138
139 private final MavenId mavenId;
140 private final URLClassLoader jarFileClassLoader;
141 private final Map<MavenId, ProjectClassLoader> dependencies = new LinkedHashMap<MavenId, ProjectClassLoader>();
142 private final Map<MavenId, Set<MavenId>> exclusions = new HashMap<MavenId, Set<MavenId>>();
143 private final ReadWriteLock dependencyLock = new ReentrantReadWriteLock();
144
145
146
147
148
149
150
151
152 protected ProjectClassLoader( MavenId mavenId,
153 URLClassLoader jarFileClassLoader ) {
154 super(null);
155 this.mavenId = mavenId;
156 this.jarFileClassLoader = jarFileClassLoader;
157 }
158
159
160
161
162
163
164
165 protected ProjectClassLoader( ClassLoader parent ) {
166 super(parent);
167 this.mavenId = null;
168 this.jarFileClassLoader = null;
169 }
170
171 protected void setDependencies( List<MavenDependency> dependencies ) {
172 try {
173 this.dependencyLock.writeLock().lock();
174 this.dependencies.clear();
175 if (dependencies != null) {
176
177 for (MavenDependency dependency : dependencies) {
178 ProjectClassLoader dependencyClassLoader = MavenClassLoaders.this.getProjectClassLoader(dependency.getId());
179 if (dependencyClassLoader != null) {
180 MavenId dependencyId = dependency.getId();
181 this.dependencies.put(dependencyId, dependencyClassLoader);
182 this.exclusions.put(dependencyId, Collections.unmodifiableSet(dependency.getExclusions()));
183 }
184 }
185 }
186 } finally {
187 this.dependencyLock.writeLock().unlock();
188 }
189 }
190
191
192
193
194
195
196
197
198
199 @Override
200 protected URL findResource( String name ) {
201
202 return findResource(name, null);
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221 protected URL findResource( String name,
222 List<MavenId> debugSearchPath ) {
223 Set<MavenId> processed = new HashSet<MavenId>();
224
225
226 URL result = null;
227 if (this.jarFileClassLoader != null) {
228 result = this.jarFileClassLoader.getResource(name);
229 processed.add(this.mavenId);
230 }
231 if (debugSearchPath != null && this.mavenId != null) debugSearchPath.add(this.mavenId);
232
233 if (result == null) {
234
235 result = findResource(name, processed, null, debugSearchPath);
236 }
237 return result;
238 }
239
240 protected URL findResource( String name,
241 Set<MavenId> processed,
242 Set<MavenId> exclusions,
243 List<MavenId> debugSearchPath ) {
244
245 if (exclusions != null && exclusions.contains(this.mavenId)) return null;
246
247
248 URL result = null;
249 try {
250 this.dependencyLock.readLock().lock();
251
252 for (Map.Entry<MavenId, ProjectClassLoader> entry : this.dependencies.entrySet()) {
253 ProjectClassLoader loader = entry.getValue();
254 MavenId id = loader.mavenId;
255 if (processed.contains(id)) continue;
256 if (exclusions != null && exclusions.contains(id)) continue;
257 result = loader.jarFileClassLoader.findResource(name);
258 processed.add(id);
259 if (debugSearchPath != null && id != null) debugSearchPath.add(id);
260 if (result != null) break;
261 }
262 if (result == null) {
263
264 for (Map.Entry<MavenId, ProjectClassLoader> entry : this.dependencies.entrySet()) {
265 MavenId dependency = entry.getKey();
266 ProjectClassLoader loader = entry.getValue();
267
268 Set<MavenId> dependencyExclusions = this.exclusions.get(dependency);
269 if (!dependencyExclusions.isEmpty()) {
270
271 if (exclusions == null) {
272 exclusions = new HashSet<MavenId>();
273 } else {
274 exclusions = new HashSet<MavenId>(exclusions);
275 }
276
277 exclusions.addAll(dependencyExclusions);
278 }
279 result = loader.findResource(name, processed, exclusions, debugSearchPath);
280 if (result != null) break;
281 }
282 }
283 } finally {
284 this.dependencyLock.readLock().unlock();
285 }
286 return super.findResource(name);
287 }
288 }
289 }