1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18 
19 package org.eclipse.jetty.webapp;
20 
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 
27 import javax.servlet.ServletContext;
28 
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.util.resource.Resource;
32 
33 
34 
35 
36 /**
37  * MetaData
38  *
39  * All data associated with the configuration and deployment of a web application.
40  */
41 public class MetaData
42 {
43     private static final Logger LOG = Log.getLogger(MetaData.class);
44 
45     public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs";
46 
47     protected Map<String, OriginInfo> _origins  =new HashMap<String,OriginInfo>();
48     protected WebDescriptor _webDefaultsRoot;
49     protected WebDescriptor _webXmlRoot;
50     protected final List<WebDescriptor> _webOverrideRoots=new ArrayList<WebDescriptor>();
51     protected boolean _metaDataComplete;
52     protected final List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>();
53     protected final List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>();
54     protected final List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>();
55     protected final Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>();
56     protected final Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>();
57     protected final Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>();
58     protected final List<Resource> _webInfJars = new ArrayList<Resource>();
59     protected final List<Resource> _orderedWebInfJars = new ArrayList<Resource>();
60     protected final List<Resource> _orderedContainerJars = new ArrayList<Resource>();
61     protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml
62     protected boolean allowDuplicateFragmentNames = false;
63 
64 
65 
66 
67 
68     public static class OriginInfo
69     {
70         protected String name;
71         protected Origin origin;
72         protected Descriptor descriptor;
73 
OriginInfo(String n, Descriptor d)74         public OriginInfo (String n, Descriptor d)
75         {
76             name = n;
77             descriptor = d;
78             if (d == null)
79                 throw new IllegalArgumentException("No descriptor");
80             if (d instanceof FragmentDescriptor)
81                 origin = Origin.WebFragment;
82             else if (d instanceof OverrideDescriptor)
83                 origin =  Origin.WebOverride;
84             else if (d instanceof DefaultsDescriptor)
85                 origin =  Origin.WebDefaults;
86             else
87                 origin = Origin.WebXml;
88         }
89 
OriginInfo(String n)90         public OriginInfo (String n)
91         {
92             name = n;
93             origin = Origin.Annotation;
94         }
95 
OriginInfo(String n, Origin o)96         public OriginInfo(String n, Origin o)
97         {
98             name = n;
99             origin = o;
100         }
101 
getName()102         public String getName()
103         {
104             return name;
105         }
106 
getOriginType()107         public Origin getOriginType()
108         {
109             return origin;
110         }
111 
getDescriptor()112         public Descriptor getDescriptor()
113         {
114             return descriptor;
115         }
116     }
117 
MetaData()118     public MetaData ()
119     {
120     }
121 
122     /**
123      * Empty ready for reuse
124      */
clear()125     public void clear ()
126     {
127         _webDefaultsRoot = null;
128         _origins.clear();
129         _webXmlRoot = null;
130         _webOverrideRoots.clear();
131         _metaDataComplete = false;
132         _annotations.clear();
133         _descriptorProcessors.clear();
134         _webFragmentRoots.clear();
135         _webFragmentNameMap.clear();
136         _webFragmentResourceMap.clear();
137         _webFragmentAnnotations.clear();
138         _webInfJars.clear();
139         _orderedWebInfJars.clear();
140         _orderedContainerJars.clear();
141         _ordering = null;
142         allowDuplicateFragmentNames = false;
143     }
144 
setDefaults(Resource webDefaults)145     public void setDefaults (Resource webDefaults)
146     throws Exception
147     {
148         _webDefaultsRoot =  new DefaultsDescriptor(webDefaults);
149         _webDefaultsRoot.parse();
150         if (_webDefaultsRoot.isOrdered())
151         {
152             if (_ordering == null)
153                 _ordering = new Ordering.AbsoluteOrdering(this);
154 
155             List<String> order = _webDefaultsRoot.getOrdering();
156             for (String s:order)
157             {
158                 if (s.equalsIgnoreCase("others"))
159                     ((Ordering.AbsoluteOrdering)_ordering).addOthers();
160                 else
161                     ((Ordering.AbsoluteOrdering)_ordering).add(s);
162             }
163         }
164     }
165 
setWebXml(Resource webXml)166     public void setWebXml (Resource webXml)
167     throws Exception
168     {
169         _webXmlRoot = new WebDescriptor(webXml);
170         _webXmlRoot.parse();
171         _metaDataComplete=_webXmlRoot.getMetaDataComplete() == MetaDataComplete.True;
172 
173 
174 
175         if (_webXmlRoot.isOrdered())
176         {
177             if (_ordering == null)
178                 _ordering = new Ordering.AbsoluteOrdering(this);
179 
180             List<String> order = _webXmlRoot.getOrdering();
181             for (String s:order)
182             {
183                 if (s.equalsIgnoreCase("others"))
184                     ((Ordering.AbsoluteOrdering)_ordering).addOthers();
185                 else
186                     ((Ordering.AbsoluteOrdering)_ordering).add(s);
187             }
188         }
189     }
190 
addOverride(Resource override)191     public void addOverride (Resource override)
192     throws Exception
193     {
194         OverrideDescriptor webOverrideRoot = new OverrideDescriptor(override);
195         webOverrideRoot.setValidating(false);
196         webOverrideRoot.parse();
197 
198         switch(webOverrideRoot.getMetaDataComplete())
199         {
200             case True:
201                 _metaDataComplete=true;
202                 break;
203             case False:
204                 _metaDataComplete=false;
205                 break;
206             case NotSet:
207                 break;
208         }
209 
210         if (webOverrideRoot.isOrdered())
211         {
212             if (_ordering == null)
213                 _ordering = new Ordering.AbsoluteOrdering(this);
214 
215             List<String> order = webOverrideRoot.getOrdering();
216             for (String s:order)
217             {
218                 if (s.equalsIgnoreCase("others"))
219                     ((Ordering.AbsoluteOrdering)_ordering).addOthers();
220                 else
221                     ((Ordering.AbsoluteOrdering)_ordering).add(s);
222             }
223         }
224         _webOverrideRoots.add(webOverrideRoot);
225     }
226 
227 
228     /**
229      * Add a web-fragment.xml
230      *
231      * @param jarResource the jar the fragment is contained in
232      * @param xmlResource the resource representing the xml file
233      * @throws Exception
234      */
addFragment(Resource jarResource, Resource xmlResource)235     public void addFragment (Resource jarResource, Resource xmlResource)
236     throws Exception
237     {
238         if (_metaDataComplete)
239             return; //do not process anything else if web.xml/web-override.xml set metadata-complete
240 
241         //Metadata-complete is not set, or there is no web.xml
242         FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource);
243         _webFragmentResourceMap.put(jarResource, descriptor);
244         _webFragmentRoots.add(descriptor);
245 
246         descriptor.parse();
247 
248         if (descriptor.getName() != null)
249         {
250             Descriptor existing = _webFragmentNameMap.get(descriptor.getName());
251             if (existing != null && !isAllowDuplicateFragmentNames())
252             {
253                 throw new IllegalStateException("Duplicate fragment name: "+descriptor.getName()+" for "+existing.getResource()+" and "+descriptor.getResource());
254             }
255             else
256                 _webFragmentNameMap.put(descriptor.getName(), descriptor);
257         }
258 
259         //If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment
260         if (_ordering != null && _ordering.isAbsolute())
261             return;
262 
263         if (_ordering == null && descriptor.isOrdered())
264             _ordering = new Ordering.RelativeOrdering(this);
265     }
266 
267     /**
268      * Annotations not associated with a WEB-INF/lib fragment jar.
269      * These are from WEB-INF/classes or the ??container path??
270      * @param annotations
271      */
addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)272     public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)
273     {
274         if (annotations == null)
275             return;
276         for (DiscoveredAnnotation a:annotations)
277         {
278             Resource r = a.getResource();
279             if (r == null || !_webInfJars.contains(r))
280                 _annotations.add(a);
281             else
282                 addDiscoveredAnnotation(a.getResource(), a);
283 
284         }
285     }
286 
287 
addDiscoveredAnnotation(Resource resource, DiscoveredAnnotation annotation)288     public void addDiscoveredAnnotation(Resource resource, DiscoveredAnnotation annotation)
289     {
290         List<DiscoveredAnnotation> list = _webFragmentAnnotations.get(resource);
291         if (list == null)
292         {
293             list = new ArrayList<DiscoveredAnnotation>();
294             _webFragmentAnnotations.put(resource, list);
295         }
296         list.add(annotation);
297     }
298 
299 
addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)300     public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)
301     {
302         List<DiscoveredAnnotation> list = _webFragmentAnnotations.get(resource);
303         if (list == null)
304         {
305             list = new ArrayList<DiscoveredAnnotation>();
306             _webFragmentAnnotations.put(resource, list);
307         }
308 
309         list.addAll(annotations);
310     }
311 
addDescriptorProcessor(DescriptorProcessor p)312     public void addDescriptorProcessor(DescriptorProcessor p)
313     {
314         _descriptorProcessors.add(p);
315     }
316 
orderFragments()317     public void orderFragments ()
318     {
319         //if we have already ordered them don't do it again
320         if (_orderedWebInfJars.size()==_webInfJars.size())
321             return;
322 
323         if (_ordering != null)
324             _orderedWebInfJars.addAll(_ordering.order(_webInfJars));
325         else
326             _orderedWebInfJars.addAll(_webInfJars);
327     }
328 
329 
330     /**
331      * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations.
332      *
333      */
resolve(WebAppContext context)334     public void resolve (WebAppContext context)
335     throws Exception
336     {
337         LOG.debug("metadata resolve {}",context);
338 
339         //Ensure origins is fresh
340         _origins.clear();
341 
342         // Set the ordered lib attribute
343         if (_ordering != null)
344         {
345             List<String> orderedLibs = new ArrayList<String>();
346             for (Resource webInfJar:_orderedWebInfJars)
347             {
348                 //get just the name of the jar file
349                 String fullname = webInfJar.getName();
350                 int i = fullname.indexOf(".jar");
351                 int j = fullname.lastIndexOf("/", i);
352                 orderedLibs.add(fullname.substring(j+1,i+4));
353             }
354             context.setAttribute(ServletContext.ORDERED_LIBS, orderedLibs);
355         }
356 
357         // set the webxml version
358         if (_webXmlRoot != null)
359         {
360             context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion());
361             context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion());
362         }
363 
364         for (DescriptorProcessor p:_descriptorProcessors)
365         {
366             p.process(context,getWebDefault());
367             p.process(context,getWebXml());
368             for (WebDescriptor wd : getOverrideWebs())
369             {
370                 LOG.debug("process {} {}",context,wd);
371                 p.process(context,wd);
372             }
373         }
374 
375         for (DiscoveredAnnotation a:_annotations)
376         {
377             LOG.debug("apply {}",a);
378             a.apply();
379         }
380 
381 
382         List<Resource> resources = getOrderedWebInfJars();
383         for (Resource r:resources)
384         {
385             FragmentDescriptor fd = _webFragmentResourceMap.get(r);
386             if (fd != null)
387             {
388                 for (DescriptorProcessor p:_descriptorProcessors)
389                 {
390                     LOG.debug("process {} {}",context,fd);
391                     p.process(context,fd);
392                 }
393             }
394 
395             List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r);
396             if (fragAnnotations != null)
397             {
398                 for (DiscoveredAnnotation a:fragAnnotations)
399                 {
400                     LOG.debug("apply {}",a);
401                     a.apply();
402                 }
403             }
404         }
405 
406     }
407 
isDistributable()408     public boolean isDistributable ()
409     {
410         boolean distributable = (
411                 (_webDefaultsRoot != null && _webDefaultsRoot.isDistributable())
412                 || (_webXmlRoot != null && _webXmlRoot.isDistributable()));
413 
414         for (WebDescriptor d : _webOverrideRoots)
415             distributable&=d.isDistributable();
416 
417         List<Resource> orderedResources = getOrderedWebInfJars();
418         for (Resource r: orderedResources)
419         {
420             FragmentDescriptor d = _webFragmentResourceMap.get(r);
421             if (d!=null)
422                 distributable = distributable && d.isDistributable();
423         }
424         return distributable;
425     }
426 
427 
getWebXml()428     public WebDescriptor getWebXml ()
429     {
430         return _webXmlRoot;
431     }
432 
getOverrideWebs()433     public List<WebDescriptor> getOverrideWebs ()
434     {
435         return _webOverrideRoots;
436     }
437 
getWebDefault()438     public WebDescriptor getWebDefault ()
439     {
440         return _webDefaultsRoot;
441     }
442 
getFragments()443     public List<FragmentDescriptor> getFragments ()
444     {
445         return _webFragmentRoots;
446     }
447 
getOrderedWebInfJars()448     public List<Resource> getOrderedWebInfJars()
449     {
450         return _orderedWebInfJars == null? new ArrayList<Resource>(): _orderedWebInfJars;
451     }
452 
getOrderedFragments()453     public List<FragmentDescriptor> getOrderedFragments ()
454     {
455         List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>();
456         if (_orderedWebInfJars == null)
457             return list;
458 
459         for (Resource r:_orderedWebInfJars)
460         {
461             FragmentDescriptor fd = _webFragmentResourceMap.get(r);
462             if (fd != null)
463                 list.add(fd);
464         }
465         return list;
466     }
467 
getOrdering()468     public Ordering getOrdering()
469     {
470         return _ordering;
471     }
472 
setOrdering(Ordering o)473     public void setOrdering (Ordering o)
474     {
475         _ordering = o;
476     }
477 
getFragment(Resource jar)478     public FragmentDescriptor getFragment (Resource jar)
479     {
480         return _webFragmentResourceMap.get(jar);
481     }
482 
getFragment(String name)483     public FragmentDescriptor getFragment(String name)
484     {
485         return _webFragmentNameMap.get(name);
486     }
487 
getJarForFragment(String name)488     public Resource getJarForFragment (String name)
489     {
490         FragmentDescriptor f = getFragment(name);
491         if (f == null)
492             return null;
493 
494         Resource jar = null;
495         for (Resource r: _webFragmentResourceMap.keySet())
496         {
497             if (_webFragmentResourceMap.get(r).equals(f))
498                 jar = r;
499         }
500         return jar;
501     }
502 
getNamedFragments()503     public Map<String,FragmentDescriptor> getNamedFragments ()
504     {
505         return Collections.unmodifiableMap(_webFragmentNameMap);
506     }
507 
508 
getOrigin(String name)509     public Origin getOrigin (String name)
510     {
511         OriginInfo x =  _origins.get(name);
512         if (x == null)
513             return Origin.NotSet;
514 
515         return x.getOriginType();
516     }
517 
518 
getOriginDescriptor(String name)519     public Descriptor getOriginDescriptor (String name)
520     {
521         OriginInfo o = _origins.get(name);
522         if (o == null)
523             return null;
524         return o.getDescriptor();
525     }
526 
setOrigin(String name, Descriptor d)527     public void setOrigin (String name, Descriptor d)
528     {
529         OriginInfo x = new OriginInfo (name, d);
530         _origins.put(name, x);
531     }
532 
setOrigin(String name)533     public void setOrigin (String name)
534     {
535         if (name == null)
536             return;
537 
538         OriginInfo x = new OriginInfo (name, Origin.Annotation);
539         _origins.put(name, x);
540     }
541 
setOrigin(String name, Origin origin)542     public void setOrigin(String name, Origin origin)
543     {
544         if (name == null)
545             return;
546 
547         OriginInfo x = new OriginInfo (name, origin);
548         _origins.put(name, x);
549     }
550 
isMetaDataComplete()551     public boolean isMetaDataComplete()
552     {
553         return _metaDataComplete;
554     }
555 
556 
addWebInfJar(Resource newResource)557     public void addWebInfJar(Resource newResource)
558     {
559         _webInfJars.add(newResource);
560     }
561 
getWebInfJars()562     public List<Resource> getWebInfJars()
563     {
564         return Collections.unmodifiableList(_webInfJars);
565     }
566 
getOrderedContainerJars()567     public List<Resource> getOrderedContainerJars()
568     {
569         return _orderedContainerJars;
570     }
571 
addContainerJar(Resource jar)572     public void addContainerJar(Resource jar)
573     {
574         _orderedContainerJars.add(jar);
575     }
isAllowDuplicateFragmentNames()576     public boolean isAllowDuplicateFragmentNames()
577     {
578         return allowDuplicateFragmentNames;
579     }
580 
setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)581     public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)
582     {
583         this.allowDuplicateFragmentNames = allowDuplicateFragmentNames;
584     }
585 }
586