1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.webapp;
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.net.JarURLConnection;
25 import java.net.URI;
26 import java.net.URL;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Enumeration;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.jar.JarEntry;
36 import java.util.jar.JarFile;
37
38 import org.eclipse.jetty.util.log.Log;
39 import org.eclipse.jetty.util.log.Logger;
40 import org.eclipse.jetty.util.resource.EmptyResource;
41 import org.eclipse.jetty.util.resource.Resource;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class MetaInfConfiguration extends AbstractConfiguration
61 {
62 private static final Logger LOG = Log.getLogger(MetaInfConfiguration.class);
63
64 public static final String USE_CONTAINER_METAINF_CACHE = "org.eclipse.jetty.metainf.useCache";
65 public static final boolean DEFAULT_USE_CONTAINER_METAINF_CACHE = true;
66 public static final String CACHED_CONTAINER_TLDS = "org.eclipse.jetty.tlds.cache";
67 public static final String CACHED_CONTAINER_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES+".cache";
68 public static final String CACHED_CONTAINER_RESOURCES = WebInfConfiguration.RESOURCE_DIRS+".cache";
69 public static final String METAINF_TLDS = "org.eclipse.jetty.tlds";
70 public static final String METAINF_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES;
71 public static final String METAINF_RESOURCES = WebInfConfiguration.RESOURCE_DIRS;
72
73 @Override
74 public void preConfigure(final WebAppContext context) throws Exception
75 {
76 boolean useContainerCache = DEFAULT_USE_CONTAINER_METAINF_CACHE;
77 Boolean attr = (Boolean)context.getServer().getAttribute(USE_CONTAINER_METAINF_CACHE);
78 if (attr != null)
79 useContainerCache = attr.booleanValue();
80
81 if (LOG.isDebugEnabled()) LOG.debug("{} = {}", USE_CONTAINER_METAINF_CACHE, useContainerCache);
82
83
84
85
86 if (context.getAttribute(METAINF_TLDS) == null)
87 context.setAttribute(METAINF_TLDS, new HashSet<URL>());
88 if (context.getAttribute(METAINF_RESOURCES) == null)
89 context.setAttribute(METAINF_RESOURCES, new HashSet<Resource>());
90 if (context.getAttribute(METAINF_FRAGMENTS) == null)
91 context.setAttribute(METAINF_FRAGMENTS, new HashMap<Resource, Resource>());
92
93 scanJars(context, context.getMetaData().getContainerResources(), useContainerCache);
94 scanJars(context, context.getMetaData().getWebInfJars(), false);
95 }
96
97
98
99
100
101
102
103
104
105
106
107 public void scanJars (final WebAppContext context, Collection<Resource> jars, boolean useCaches)
108 throws Exception
109 {
110 ConcurrentHashMap<Resource, Resource> metaInfResourceCache = null;
111 ConcurrentHashMap<Resource, Resource> metaInfFragmentCache = null;
112 ConcurrentHashMap<Resource, Collection<URL>> metaInfTldCache = null;
113 if (useCaches)
114 {
115 metaInfResourceCache = (ConcurrentHashMap<Resource, Resource>)context.getServer().getAttribute(CACHED_CONTAINER_RESOURCES);
116 if (metaInfResourceCache == null)
117 {
118 metaInfResourceCache = new ConcurrentHashMap<Resource,Resource>();
119 context.getServer().setAttribute(CACHED_CONTAINER_RESOURCES, metaInfResourceCache);
120 }
121 metaInfFragmentCache = (ConcurrentHashMap<Resource, Resource>)context.getServer().getAttribute(CACHED_CONTAINER_FRAGMENTS);
122 if (metaInfFragmentCache == null)
123 {
124 metaInfFragmentCache = new ConcurrentHashMap<Resource,Resource>();
125 context.getServer().setAttribute(CACHED_CONTAINER_FRAGMENTS, metaInfFragmentCache);
126 }
127 metaInfTldCache = (ConcurrentHashMap<Resource, Collection<URL>>)context.getServer().getAttribute(CACHED_CONTAINER_TLDS);
128 if (metaInfTldCache == null)
129 {
130 metaInfTldCache = new ConcurrentHashMap<Resource,Collection<URL>>();
131 context.getServer().setAttribute(CACHED_CONTAINER_TLDS, metaInfTldCache);
132 }
133 }
134
135
136 if (jars != null)
137 {
138 for (Resource r : jars)
139 {
140
141 scanForResources(context, r, metaInfResourceCache);
142 scanForFragment(context, r, metaInfFragmentCache);
143 scanForTlds(context, r, metaInfTldCache);
144 }
145 }
146 }
147
148
149
150
151
152
153
154
155
156 public void scanForResources (WebAppContext context, Resource target, ConcurrentHashMap<Resource,Resource> cache)
157 throws Exception
158 {
159 Resource resourcesDir = null;
160 if (cache != null && cache.containsKey(target))
161 {
162 resourcesDir = cache.get(target);
163 if (resourcesDir == EmptyResource.INSTANCE)
164 {
165 if (LOG.isDebugEnabled()) LOG.debug(target+" cached as containing no META-INF/resources");
166 return;
167 }
168 else
169 if (LOG.isDebugEnabled()) LOG.debug(target+" META-INF/resources found in cache ");
170 }
171 else
172 {
173
174 if (LOG.isDebugEnabled()) LOG.debug(target+" META-INF/resources checked");
175 if (target.isDirectory())
176 {
177
178 resourcesDir = target.addPath("/META-INF/resources");
179 }
180 else
181 {
182
183 URI uri = target.getURI();
184 resourcesDir = Resource.newResource("jar:"+uri+"!/META-INF/resources");
185 }
186
187 if (!resourcesDir.exists() || !resourcesDir.isDirectory())
188 {
189 resourcesDir.close();
190 resourcesDir = EmptyResource.INSTANCE;
191 }
192
193 if (cache != null)
194 {
195 Resource old = cache.putIfAbsent(target, resourcesDir);
196 if (old != null)
197 resourcesDir = old;
198 else
199 if (LOG.isDebugEnabled()) LOG.debug(target+" META-INF/resources cache updated");
200 }
201
202 if (resourcesDir == EmptyResource.INSTANCE)
203 {
204 return;
205 }
206 }
207
208
209 Set<Resource> dirs = (Set<Resource>)context.getAttribute(METAINF_RESOURCES);
210 if (dirs == null)
211 {
212 dirs = new HashSet<Resource>();
213 context.setAttribute(METAINF_RESOURCES, dirs);
214 }
215 if (LOG.isDebugEnabled()) LOG.debug(resourcesDir+" added to context");
216
217 dirs.add(resourcesDir);
218 }
219
220
221
222
223
224
225
226
227
228 public void scanForFragment (WebAppContext context, Resource jar, ConcurrentHashMap<Resource,Resource> cache)
229 throws Exception
230 {
231 Resource webFrag = null;
232 if (cache != null && cache.containsKey(jar))
233 {
234 webFrag = cache.get(jar);
235 if (webFrag == EmptyResource.INSTANCE)
236 {
237 if (LOG.isDebugEnabled()) LOG.debug(jar+" cached as containing no META-INF/web-fragment.xml");
238 return;
239 }
240 else
241 if (LOG.isDebugEnabled()) LOG.debug(jar+" META-INF/web-fragment.xml found in cache ");
242 }
243 else
244 {
245
246 if (LOG.isDebugEnabled()) LOG.debug(jar+" META-INF/web-fragment.xml checked");
247 if (jar.isDirectory())
248 {
249
250 webFrag = jar.addPath("/META-INF/web-fragment.xml");
251 }
252 else
253 {
254 URI uri = jar.getURI();
255 webFrag = Resource.newResource("jar:"+uri+"!/META-INF/web-fragment.xml");
256 }
257 if (!webFrag.exists() || webFrag.isDirectory())
258 {
259 webFrag.close();
260 webFrag = EmptyResource.INSTANCE;
261 }
262
263 if (cache != null)
264 {
265
266 Resource old = cache.putIfAbsent(jar, webFrag);
267 if (old != null)
268 webFrag = old;
269 else
270 if (LOG.isDebugEnabled()) LOG.debug(jar+" META-INF/web-fragment.xml cache updated");
271 }
272
273 if (webFrag == EmptyResource.INSTANCE)
274 return;
275 }
276
277 Map<Resource, Resource> fragments = (Map<Resource,Resource>)context.getAttribute(METAINF_FRAGMENTS);
278 if (fragments == null)
279 {
280 fragments = new HashMap<Resource, Resource>();
281 context.setAttribute(METAINF_FRAGMENTS, fragments);
282 }
283 fragments.put(jar, webFrag);
284 if (LOG.isDebugEnabled()) LOG.debug(webFrag+" added to context");
285 }
286
287
288
289
290
291
292
293
294
295
296 public void scanForTlds (WebAppContext context, Resource jar, ConcurrentHashMap<Resource, Collection<URL>> cache)
297 throws Exception
298 {
299 Collection<URL> tlds = null;
300
301 if (cache != null && cache.containsKey(jar))
302 {
303 Collection<URL> tmp = cache.get(jar);
304 if (tmp.isEmpty())
305 {
306 if (LOG.isDebugEnabled()) LOG.debug(jar+" cached as containing no tlds");
307 return;
308 }
309 else
310 {
311 tlds = tmp;
312 if (LOG.isDebugEnabled()) LOG.debug(jar+" tlds found in cache ");
313 }
314 }
315 else
316 {
317
318 tlds = new HashSet<URL>();
319 if (jar.isDirectory())
320 {
321 tlds.addAll(getTlds(jar.getFile()));
322 }
323 else
324 {
325 URI uri = jar.getURI();
326 tlds.addAll(getTlds(uri));
327 }
328
329 if (cache != null)
330 {
331 if (LOG.isDebugEnabled()) LOG.debug(jar+" tld cache updated");
332 Collection<URL> old = (Collection<URL>)cache.putIfAbsent(jar, tlds);
333 if (old != null)
334 tlds = old;
335 }
336
337 if (tlds.isEmpty())
338 return;
339 }
340
341 Collection<URL> metaInfTlds = (Collection<URL>)context.getAttribute(METAINF_TLDS);
342 if (metaInfTlds == null)
343 {
344 metaInfTlds = new HashSet<URL>();
345 context.setAttribute(METAINF_TLDS, metaInfTlds);
346 }
347 metaInfTlds.addAll(tlds);
348 if (LOG.isDebugEnabled()) LOG.debug("tlds added to context");
349 }
350
351
352 @Override
353 public void postConfigure(WebAppContext context) throws Exception
354 {
355 context.setAttribute(METAINF_RESOURCES, null);
356
357 context.setAttribute(METAINF_FRAGMENTS, null);
358
359 context.setAttribute(METAINF_TLDS, null);
360 }
361
362
363
364
365
366
367
368
369 public Collection<URL> getTlds (File dir) throws IOException
370 {
371 if (dir == null || !dir.isDirectory())
372 return Collections.emptySet();
373
374 HashSet<URL> tlds = new HashSet<URL>();
375
376 File[] files = dir.listFiles();
377 if (files != null)
378 {
379 for (File f:files)
380 {
381 if (f.isDirectory())
382 tlds.addAll(getTlds(f));
383 else
384 {
385 String name = f.getCanonicalPath();
386 if (name.contains("META-INF") && name.endsWith(".tld"))
387 tlds.add(f.toURI().toURL());
388 }
389 }
390 }
391 return tlds;
392 }
393
394
395
396
397
398
399
400
401 public Collection<URL> getTlds (URI uri) throws IOException
402 {
403 HashSet<URL> tlds = new HashSet<URL>();
404
405 URL url = new URL("jar:"+uri+"!/");
406 JarURLConnection jarConn = (JarURLConnection) url.openConnection();
407 jarConn.setUseCaches(Resource.getDefaultUseCaches());
408 JarFile jarFile = jarConn.getJarFile();
409 Enumeration<JarEntry> entries = jarFile.entries();
410 while (entries.hasMoreElements())
411 {
412 JarEntry e = entries.nextElement();
413 String name = e.getName();
414 if (name.startsWith("META-INF") && name.endsWith(".tld"))
415 {
416 tlds.add(new URL("jar:"+uri+"!/"+name));
417 }
418 }
419 if (!Resource.getDefaultUseCaches())
420 jarFile.close();
421 return tlds;
422 }
423 }