View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 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          
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          
90          public OriginInfo (String n)
91          {
92              name = n;
93              origin = Origin.Annotation;
94          }
95          
96          public OriginInfo(String n, Origin o)
97          {
98              name = n;
99              origin = o;
100         }
101         
102         public String getName()
103         {
104             return name;
105         }
106         
107         public Origin getOriginType()
108         {
109             return origin;
110         }
111         
112         public Descriptor getDescriptor()
113         {
114             return descriptor;
115         }
116     }
117    
118     public MetaData ()
119     {
120     }
121     
122     /**
123      * Empty ready for reuse
124      */
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     
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     
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     
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=true;
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      */
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      */
272     public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)
273     {
274         _annotations.addAll(annotations);
275     }
276 
277     public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)
278     {
279         _webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations));
280     }
281     
282     public void addDescriptorProcessor(DescriptorProcessor p)
283     {
284         _descriptorProcessors.add(p);
285     }
286     
287     public void orderFragments ()
288     {
289         //if we have already ordered them don't do it again
290         if (_orderedWebInfJars.size()==_webInfJars.size())
291             return;
292         
293         if (_ordering != null)
294             _orderedWebInfJars.addAll(_ordering.order(_webInfJars));
295         else
296             _orderedWebInfJars.addAll(_webInfJars);
297     }
298     
299     
300     /**
301      * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations.
302      * 
303      */
304     public void resolve (WebAppContext context)
305     throws Exception
306     {
307         LOG.debug("metadata resolve {}",context);
308         
309         //Ensure origins is fresh
310         _origins.clear();
311         
312         // Set the ordered lib attribute
313         if (_ordering != null)
314         {
315             List<String> orderedLibs = new ArrayList<String>();
316             for (Resource webInfJar:_orderedWebInfJars)
317             {
318                 //get just the name of the jar file
319                 String fullname = webInfJar.getName();
320                 int i = fullname.indexOf(".jar");          
321                 int j = fullname.lastIndexOf("/", i);
322                 orderedLibs.add(fullname.substring(j+1,i+4));
323             }
324             context.setAttribute(ServletContext.ORDERED_LIBS, orderedLibs);
325         }
326 
327         // set the webxml version
328         if (_webXmlRoot != null)
329         {
330             context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion());
331             context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion());
332         }
333 
334         for (DescriptorProcessor p:_descriptorProcessors)
335         {
336             p.process(context,getWebDefault());
337             p.process(context,getWebXml());
338             for (WebDescriptor wd : getOverrideWebs())   
339             {
340                 LOG.debug("process {} {}",context,wd);
341                 p.process(context,wd);
342             }
343         }
344         
345         for (DiscoveredAnnotation a:_annotations)
346         {
347             LOG.debug("apply {}",a);
348             a.apply();
349         }
350     
351         
352         List<Resource> resources = getOrderedWebInfJars();
353         for (Resource r:resources)
354         {
355             FragmentDescriptor fd = _webFragmentResourceMap.get(r);
356             if (fd != null)
357             {
358                 for (DescriptorProcessor p:_descriptorProcessors)
359                 {
360                     LOG.debug("process {} {}",context,fd);
361                     p.process(context,fd);
362                 }
363             }
364             
365             List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r);
366             if (fragAnnotations != null)
367             {
368                 for (DiscoveredAnnotation a:fragAnnotations)
369                 {
370                     LOG.debug("apply {}",a);
371                     a.apply();
372                 }
373             }
374         }
375         
376     }
377     
378     public boolean isDistributable ()
379     {
380         boolean distributable = (
381                 (_webDefaultsRoot != null && _webDefaultsRoot.isDistributable()) 
382                 || (_webXmlRoot != null && _webXmlRoot.isDistributable()));
383         
384         for (WebDescriptor d : _webOverrideRoots)
385             distributable&=d.isDistributable();
386         
387         List<Resource> orderedResources = getOrderedWebInfJars();
388         for (Resource r: orderedResources)
389         {  
390             FragmentDescriptor d = _webFragmentResourceMap.get(r);
391             if (d!=null)
392                 distributable = distributable && d.isDistributable();
393         }
394         return distributable;
395     }
396    
397     
398     public WebDescriptor getWebXml ()
399     {
400         return _webXmlRoot;
401     }
402     
403     public List<WebDescriptor> getOverrideWebs ()
404     {
405         return _webOverrideRoots;
406     }
407     
408     public WebDescriptor getWebDefault ()
409     {
410         return _webDefaultsRoot;
411     }
412     
413     public List<FragmentDescriptor> getFragments ()
414     {
415         return _webFragmentRoots;
416     }
417     
418     public List<Resource> getOrderedWebInfJars()
419     {
420         return _orderedWebInfJars == null? new ArrayList<Resource>(): _orderedWebInfJars;
421     }
422     
423     public List<FragmentDescriptor> getOrderedFragments ()
424     {
425         List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>();
426         if (_orderedWebInfJars == null)
427             return list;
428 
429         for (Resource r:_orderedWebInfJars)
430         {
431             FragmentDescriptor fd = _webFragmentResourceMap.get(r);
432             if (fd != null)
433                 list.add(fd);
434         }
435         return list;
436     }
437     
438     public Ordering getOrdering()
439     {
440         return _ordering;
441     }
442     
443     public void setOrdering (Ordering o)
444     {
445         _ordering = o;
446     }
447     
448     public FragmentDescriptor getFragment (Resource jar)
449     {
450         return _webFragmentResourceMap.get(jar);
451     }
452     
453     public FragmentDescriptor getFragment(String name)
454     {
455         return _webFragmentNameMap.get(name);
456     }
457     
458     public Resource getJarForFragment (String name)
459     {
460         FragmentDescriptor f = getFragment(name);
461         if (f == null)
462             return null;
463         
464         Resource jar = null;
465         for (Resource r: _webFragmentResourceMap.keySet())
466         {
467             if (_webFragmentResourceMap.get(r).equals(f))
468                 jar = r;
469         }
470         return jar;
471     }
472     
473     public Map<String,FragmentDescriptor> getNamedFragments ()
474     {
475         return Collections.unmodifiableMap(_webFragmentNameMap);
476     }
477     
478     
479     public Origin getOrigin (String name)
480     {
481         OriginInfo x =  _origins.get(name);
482         if (x == null)
483             return Origin.NotSet;
484         
485         return x.getOriginType();
486     }
487   
488  
489     public Descriptor getOriginDescriptor (String name)
490     {
491         OriginInfo o = _origins.get(name);
492         if (o == null)
493             return null;
494         return o.getDescriptor();
495     }
496     
497     public void setOrigin (String name, Descriptor d)
498     {
499         OriginInfo x = new OriginInfo (name, d);
500         _origins.put(name, x);
501     }
502     
503     public void setOrigin (String name)
504     {
505         if (name == null)
506             return;
507        
508         OriginInfo x = new OriginInfo (name, Origin.Annotation);
509         _origins.put(name, x);
510     }
511 
512     public boolean isMetaDataComplete()
513     {
514         return _metaDataComplete;
515     }
516 
517     
518     public void addWebInfJar(Resource newResource)
519     {
520         _webInfJars.add(newResource);
521     }
522 
523     public List<Resource> getWebInfJars()
524     {
525         return Collections.unmodifiableList(_webInfJars);
526     }
527     
528     public List<Resource> getOrderedContainerJars()
529     {
530         return _orderedContainerJars;
531     }
532     
533     public void addContainerJar(Resource jar)
534     {
535         _orderedContainerJars.add(jar);
536     }
537     public boolean isAllowDuplicateFragmentNames()
538     {
539         return allowDuplicateFragmentNames;
540     }
541 
542     public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)
543     {
544         this.allowDuplicateFragmentNames = allowDuplicateFragmentNames;
545     }
546 }