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