View Javadoc

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