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 = new URL(rootUrl, JarFile.MANIFEST_NAME);
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 selectUrl(final Class<?> locator, final URL selectorUrl)
209 {
210 try
211 {
212 final String selectorUrlString = selectorUrl.toExternalForm();
213 for (final Enumeration<URL> en =
214 locator.getClassLoader().getResources(""); en.hasMoreElements();)
215 {
216 final URL rootUrl = en.nextElement();
217 if (selectorUrlString.startsWith(rootUrl.toExternalForm()))
218 {
219 return calcActualRootUrl(rootUrl);
220 }
221 }
222 }
223 catch (final IOException e)
224 {
225 throw new IllegalStateException(
226 "Cannot determine Manifest file location using selector URL: "
227 + selectorUrl.toExternalForm(), e);
228 }
229
230 return locator.getClassLoader().getResource("");
231 }
232
233 private URL calcActualRootUrl(final URL rootUrl)
234 {
235 URL actualUrl = rootUrl;
236 if (preferEarManifest)
237 {
238 final String string = rootUrl.toExternalForm();
239 final int index = string.lastIndexOf(".ear/");
240 if (index != -1)
241 {
242 try
243 {
244 actualUrl = new URL(string.substring(0, index + 5));
245 }
246 catch (final MalformedURLException e)
247 {
248
249 }
250 }
251 }
252 return actualUrl;
253 }
254
255
256
257
258
259
260
261
262
263
264 public ApplicationId load(final ClassLoader classLoader)
265 throws IllegalStateException
266 {
267 final URL url = classLoader.getResource(JarFile.MANIFEST_NAME);
268 return getApplicatioIdFrom(url);
269 }
270
271 private ApplicationId getApplicatioIdFrom(final URL url)
272 {
273 if (cache != null)
274 {
275 readLock.lock();
276 try
277 {
278 final ApplicationId applicationId = cache.get(url.toExternalForm());
279 return applicationId;
280 }
281 finally
282 {
283 readLock.unlock();
284 }
285 }
286
287 final ApplicationId applicationId = readManifestFile(url);
288
289 if (cache != null)
290 {
291
292 writeLock.lock();
293 try
294 {
295 cache.put(url.toExternalForm(), applicationId);
296 }
297 finally
298 {
299 writeLock.unlock();
300 }
301 }
302
303 return applicationId;
304 }
305
306 private ApplicationId readManifestFile(final URL url)
307 throws IllegalArgumentException, IllegalStateException
308 {
309 InputStream inputStream = null;
310 try
311 {
312 inputStream = url.openStream();
313 if (inputStream != null)
314 {
315 inputStream = new BufferedInputStream(inputStream);
316 final Manifest manifest = new Manifest(inputStream);
317
318 final ApplicationId applicationId = createApplicationId(manifest);
319
320 return applicationId;
321 }
322
323 throw new IllegalStateException(
324 "Cannot find Manifest file to determine application ID: "
325 + url.toExternalForm());
326 }
327 catch (final IOException e)
328 {
329 throw new IllegalStateException("Cannot read Manifest file: "
330 + url.toExternalForm(), e);
331 }
332 finally
333 {
334 IOUtils.closeQuietly(inputStream);
335 }
336 }
337
338 private ApplicationId createApplicationId(final Manifest manifest)
339 throws IllegalArgumentException
340 {
341 final Attributes attributes = manifest.getMainAttributes();
342 final String groupId =
343 attributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR_ID);
344 final String artifactId =
345 attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
346 final String version =
347 attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
348 final ApplicationId applicationId =
349 new ApplicationId(groupId, artifactId, version);
350 return applicationId;
351 }
352
353
354
355
356
357
358
359
360 @Override
361 public String toString()
362 {
363 final StringBuilder buffer = new StringBuilder();
364 readLock.lock();
365 try
366 {
367 for (final Entry<String, ApplicationId> entry : cache.entrySet())
368 {
369 buffer.append(entry.getKey()).append(": ").append(entry.getValue())
370 .append('\n');
371 }
372 }
373 finally
374 {
375 readLock.unlock();
376 }
377 return buffer.toString();
378 }
379 }