View Javadoc

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