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