1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.properties.api.config.domain.key;
17
18 import java.io.BufferedInputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23 import java.util.Enumeration;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.concurrent.locks.Lock;
28 import java.util.concurrent.locks.ReentrantReadWriteLock;
29 import java.util.jar.Attributes;
30 import java.util.jar.JarFile;
31 import java.util.jar.Manifest;
32
33 import javax.annotation.concurrent.ThreadSafe;
34
35 import org.apache.commons.io.IOUtils;
36
37
38
39
40 @ThreadSafe
41 public final class ApplicationIdLoader
42 {
43
44
45
46
47
48
49
50
51
52
53
54
55 private final boolean preferEarManifest;
56
57
58
59
60
61
62
63 private final Map<String, ApplicationId> cache;
64
65
66
67
68
69
70 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
71
72
73
74
75
76
77 private final Lock readLock = lock.readLock();
78
79
80
81
82
83
84 private final Lock writeLock = lock.writeLock();
85
86
87
88
89
90
91
92
93
94 public ApplicationIdLoader()
95 {
96 this(true);
97 }
98
99
100
101
102
103
104
105
106 public ApplicationIdLoader(final boolean preferEarManifest)
107 {
108 this(preferEarManifest, false);
109 }
110
111
112
113
114
115
116
117
118
119
120 public ApplicationIdLoader(final boolean preferEarManifest,
121 final boolean useCache)
122 {
123 this.preferEarManifest = preferEarManifest;
124 this.cache = (useCache ? new HashMap<String, ApplicationId>() : null);
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 public static ApplicationIdLoader createCachedJarLoader()
143 {
144 return new ApplicationIdLoader(false, true);
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public ApplicationId load() throws IllegalStateException
160 {
161 return load(Thread.currentThread().getContextClassLoader());
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public ApplicationId load(final Class<?> locator)
175 throws IllegalStateException
176 {
177 final URL selectorUrl = locator.getResource("");
178 final URL rootUrl = selectUrl(locator, selectorUrl);
179 final ApplicationId applicationId = load(rootUrl);
180 return applicationId;
181 }
182
183
184
185
186
187
188
189
190
191
192 public ApplicationId load(final URL rootUrl)
193 {
194 try
195 {
196 final URL manifestFileUrl = constructUrl(rootUrl);
197 final ApplicationId applicationId = getApplicatioIdFrom(manifestFileUrl);
198 return applicationId;
199 }
200 catch (final MalformedURLException e)
201 {
202 throw new IllegalStateException(
203 "Cannot read Manifest file from base URL: "
204 + rootUrl.toExternalForm(), e);
205 }
206 }
207
208 private URL constructUrl(final URL rootUrl) throws MalformedURLException
209 {
210 final String urlString = rootUrl.toExternalForm();
211 final int index = urlString.indexOf("/WEB-INF/classes");
212 if (index != -1)
213 {
214 final String baseUrl = urlString.substring(0, index);
215 return new URL(baseUrl + '/' + JarFile.MANIFEST_NAME);
216 }
217 return new URL(rootUrl, JarFile.MANIFEST_NAME);
218 }
219
220 private URL selectUrl(final Class<?> locator, final URL selectorUrl)
221 {
222 try
223 {
224 final String selectorUrlString = selectorUrl.toExternalForm();
225 for (final Enumeration<URL> en =
226 locator.getClassLoader().getResources(""); en.hasMoreElements();)
227 {
228 final URL rootUrl = en.nextElement();
229 if (selectorUrlString.startsWith(rootUrl.toExternalForm()))
230 {
231 return calcActualRootUrl(rootUrl);
232 }
233 }
234 }
235 catch (final IOException e)
236 {
237 throw new IllegalStateException(
238 "Cannot determine Manifest file location using selector URL: "
239 + selectorUrl.toExternalForm(), e);
240 }
241
242 return locator.getClassLoader().getResource("");
243 }
244
245 private URL calcActualRootUrl(final URL rootUrl)
246 {
247 URL actualUrl = rootUrl;
248 if (preferEarManifest)
249 {
250 final String string = rootUrl.toExternalForm();
251 final int index = string.lastIndexOf(".ear/");
252 if (index != -1)
253 {
254 try
255 {
256 actualUrl = new URL(string.substring(0, index + 5));
257 }
258 catch (final MalformedURLException e)
259 {
260
261 }
262 }
263 }
264 return actualUrl;
265 }
266
267
268
269
270
271
272
273
274
275
276 public ApplicationId load(final ClassLoader classLoader)
277 throws IllegalStateException
278 {
279 final URL url = classLoader.getResource(JarFile.MANIFEST_NAME);
280 return getApplicatioIdFrom(url);
281 }
282
283 private ApplicationId getApplicatioIdFrom(final URL url)
284 {
285 if (cache != null)
286 {
287 readLock.lock();
288 try
289 {
290 final ApplicationId applicationId = cache.get(url.toExternalForm());
291 return applicationId;
292 }
293 finally
294 {
295 readLock.unlock();
296 }
297 }
298
299 final ApplicationId applicationId = readManifestFile(url);
300
301 if (cache != null)
302 {
303
304 writeLock.lock();
305 try
306 {
307 cache.put(url.toExternalForm(), applicationId);
308 }
309 finally
310 {
311 writeLock.unlock();
312 }
313 }
314
315 return applicationId;
316 }
317
318 private ApplicationId readManifestFile(final URL url)
319 throws IllegalArgumentException, IllegalStateException
320 {
321 InputStream inputStream = null;
322 try
323 {
324 inputStream = url.openStream();
325 if (inputStream != null)
326 {
327 inputStream = new BufferedInputStream(inputStream);
328 final Manifest manifest = new Manifest(inputStream);
329
330 final ApplicationId applicationId = createApplicationId(manifest);
331
332 return applicationId;
333 }
334
335 throw new IllegalStateException(
336 "Cannot find Manifest file to determine application ID: "
337 + url.toExternalForm());
338 }
339 catch (final IOException e)
340 {
341 throw new IllegalStateException("Cannot read Manifest file: "
342 + url.toExternalForm(), e);
343 }
344 finally
345 {
346 IOUtils.closeQuietly(inputStream);
347 }
348 }
349
350 private ApplicationId createApplicationId(final Manifest manifest)
351 throws IllegalArgumentException
352 {
353 final Attributes attributes = manifest.getMainAttributes();
354 final String groupId =
355 attributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR_ID);
356 final String artifactId =
357 attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
358 final String version =
359 attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
360 final ApplicationId applicationId =
361 new ApplicationId(groupId, artifactId, version);
362 return applicationId;
363 }
364
365
366
367
368
369
370
371
372 @Override
373 public String toString()
374 {
375 final StringBuilder buffer = new StringBuilder();
376 readLock.lock();
377 try
378 {
379 for (final Entry<String, ApplicationId> entry : cache.entrySet())
380 {
381 buffer.append(entry.getKey()).append(": ").append(entry.getValue())
382 .append('\n');
383 }
384 }
385 finally
386 {
387 readLock.unlock();
388 }
389 return buffer.toString();
390 }
391 }