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