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         if (_webXmlRoot.isOrdered())
169         {
170             if (_ordering == null)
171                 _ordering = new Ordering.AbsoluteOrdering(this);
172 
173             List<String> order = _webXmlRoot.getOrdering();
174             for (String s:order)
175             {
176                 if (s.equalsIgnoreCase("others"))
177                     ((Ordering.AbsoluteOrdering)_ordering).addOthers();
178                 else 
179                     ((Ordering.AbsoluteOrdering)_ordering).add(s);
180             }
181         }    
182     }
183     
184     public void addOverride (Resource override)
185     throws Exception
186     {
187         OverrideDescriptor webOverrideRoot = new OverrideDescriptor(override);
188         webOverrideRoot.setValidating(false);
189         webOverrideRoot.parse();
190         
191         switch(webOverrideRoot.getMetaDataComplete())
192         {
193             case True:
194                 _metaDataComplete=true;
195                 break;
196             case False:
197                 _metaDataComplete=true;
198                 break;
199             case NotSet:
200                 break;
201         }
202         
203         if (webOverrideRoot.isOrdered())
204         {
205             if (_ordering == null)
206                 _ordering = new Ordering.AbsoluteOrdering(this);
207 
208             List<String> order = webOverrideRoot.getOrdering();
209             for (String s:order)
210             {
211                 if (s.equalsIgnoreCase("others"))
212                     ((Ordering.AbsoluteOrdering)_ordering).addOthers();
213                 else 
214                     ((Ordering.AbsoluteOrdering)_ordering).add(s);
215             }
216         }   
217         _webOverrideRoots.add(webOverrideRoot);
218     }
219     
220     
221     /**
222      * Add a web-fragment.xml
223      * 
224      * @param jarResource the jar the fragment is contained in
225      * @param xmlResource the resource representing the xml file
226      * @throws Exception
227      */
228     public void addFragment (Resource jarResource, Resource xmlResource)
229     throws Exception
230     { 
231         if (_metaDataComplete)
232             return; //do not process anything else if web.xml/web-override.xml set metadata-complete
233         
234         //Metadata-complete is not set, or there is no web.xml
235         FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource);
236         _webFragmentResourceMap.put(jarResource, descriptor);
237         _webFragmentRoots.add(descriptor);
238         
239         descriptor.parse();
240         
241         if (descriptor.getName() != null)
242         {
243             Descriptor existing = _webFragmentNameMap.get(descriptor.getName());
244             if (existing != null && !isAllowDuplicateFragmentNames())
245             {
246                 throw new IllegalStateException("Duplicate fragment name: "+descriptor.getName()+" for "+existing.getResource()+" and "+descriptor.getResource());
247             }
248             else
249                 _webFragmentNameMap.put(descriptor.getName(), descriptor);
250         }
251 
252         //If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment
253         if (_ordering != null && _ordering.isAbsolute())
254             return;
255         
256         if (_ordering == null && descriptor.isOrdered())
257             _ordering = new Ordering.RelativeOrdering(this);
258     }
259 
260     /**
261      * Annotations not associated with a WEB-INF/lib fragment jar.
262      * These are from WEB-INF/classes or the ??container path??
263      * @param annotations
264      */
265     public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)
266     {
267         _annotations.addAll(annotations);
268     }
269 
270     public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)
271     {
272         _webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations));
273     }
274     
275     public void addDescriptorProcessor(DescriptorProcessor p)
276     {
277         _descriptorProcessors.add(p);
278     }
279     
280     public void orderFragments ()
281     {
282         //if we have already ordered them don't do it again
283         if (_orderedWebInfJars.size()==_webInfJars.size())
284             return;
285         
286         if (_ordering != null)
287             _orderedWebInfJars.addAll(_ordering.order(_webInfJars));
288         else
289             _orderedWebInfJars.addAll(_webInfJars);
290     }
291     
292     
293     /**
294      * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations.
295      * 
296      */
297     public void resolve (WebAppContext context)
298     throws Exception
299     {
300         LOG.debug("metadata resolve {}",context);
301         
302         //Ensure origins is fresh
303         _origins.clear();
304         
305         // Set the ordered lib attribute
306         if (_ordering != null)
307         {
308             List<String> orderedLibs = new ArrayList<String>();
309             for (Resource webInfJar:_orderedWebInfJars)
310             {
311                 //get just the name of the jar file
312                 String fullname = webInfJar.getName();
313                 int i = fullname.indexOf(".jar");          
314                 int j = fullname.lastIndexOf("/", i);
315                 orderedLibs.add(fullname.substring(j+1,i+4));
316             }
317             context.setAttribute(ServletContext.ORDERED_LIBS, orderedLibs);
318         }
319 
320         // set the webxml version
321         if (_webXmlRoot != null)
322         {
323             context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion());
324             context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion());
325         }
326 
327         for (DescriptorProcessor p:_descriptorProcessors)
328         {
329             p.process(context,getWebDefault());
330             p.process(context,getWebXml());
331             for (WebDescriptor wd : getOverrideWebs())   
332             {
333                 LOG.debug("process {} {}",context,wd);
334                 p.process(context,wd);
335             }
336         }
337         
338         for (DiscoveredAnnotation a:_annotations)
339         {
340             LOG.debug("apply {}",a);
341             a.apply();
342         }
343     
344         
345         List<Resource> resources = getOrderedWebInfJars();
346         for (Resource r:resources)
347         {
348             FragmentDescriptor fd = _webFragmentResourceMap.get(r);
349             if (fd != null)
350             {
351                 for (DescriptorProcessor p:_descriptorProcessors)
352                 {
353                     LOG.debug("process {} {}",context,fd);
354                     p.process(context,fd);
355                 }
356             }
357             
358             List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r);
359             if (fragAnnotations != null)
360             {
361                 for (DiscoveredAnnotation a:fragAnnotations)
362                 {
363                     LOG.debug("apply {}",a);
364                     a.apply();
365                 }
366             }
367         }
368         
369     }
370     
371     public boolean isDistributable ()
372     {
373         boolean distributable = (
374                 (_webDefaultsRoot != null && _webDefaultsRoot.isDistributable()) 
375                 || (_webXmlRoot != null && _webXmlRoot.isDistributable()));
376         
377         for (WebDescriptor d : _webOverrideRoots)
378             distributable&=d.isDistributable();
379         
380         List<Resource> orderedResources = getOrderedWebInfJars();
381         for (Resource r: orderedResources)
382         {  
383             FragmentDescriptor d = _webFragmentResourceMap.get(r);
384             if (d!=null)
385                 distributable = distributable && d.isDistributable();
386         }
387         return distributable;
388     }
389    
390     
391     public WebDescriptor getWebXml ()
392     {
393         return _webXmlRoot;
394     }
395     
396     public List<WebDescriptor> getOverrideWebs ()
397     {
398         return _webOverrideRoots;
399     }
400     
401     public WebDescriptor getWebDefault ()
402     {
403         return _webDefaultsRoot;
404     }
405     
406     public List<FragmentDescriptor> getFragments ()
407     {
408         return _webFragmentRoots;
409     }
410     
411     public List<Resource> getOrderedWebInfJars()
412     {
413         return _orderedWebInfJars == null? new ArrayList<Resource>(): _orderedWebInfJars;
414     }
415     
416     public List<FragmentDescriptor> getOrderedFragments ()
417     {
418         List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>();
419         if (_orderedWebInfJars == null)
420             return list;
421 
422         for (Resource r:_orderedWebInfJars)
423         {
424             FragmentDescriptor fd = _webFragmentResourceMap.get(r);
425             if (fd != null)
426                 list.add(fd);
427         }
428         return list;
429     }
430     
431     public Ordering getOrdering()
432     {
433         return _ordering;
434     }
435     
436     public void setOrdering (Ordering o)
437     {
438         _ordering = o;
439     }
440     
441     public FragmentDescriptor getFragment (Resource jar)
442     {
443         return _webFragmentResourceMap.get(jar);
444     }
445     
446     public FragmentDescriptor getFragment(String name)
447     {
448         return _webFragmentNameMap.get(name);
449     }
450     
451     public Resource getJarForFragment (String name)
452     {
453         FragmentDescriptor f = getFragment(name);
454         if (f == null)
455             return null;
456         
457         Resource jar = null;
458         for (Resource r: _webFragmentResourceMap.keySet())
459         {
460             if (_webFragmentResourceMap.get(r).equals(f))
461                 jar = r;
462         }
463         return jar;
464     }
465     
466     public Map<String,FragmentDescriptor> getNamedFragments ()
467     {
468         return Collections.unmodifiableMap(_webFragmentNameMap);
469     }
470     
471     
472     public Origin getOrigin (String name)
473     {
474         OriginInfo x =  _origins.get(name);
475         if (x == null)
476             return Origin.NotSet;
477         
478         return x.getOriginType();
479     }
480   
481  
482     public Descriptor getOriginDescriptor (String name)
483     {
484         OriginInfo o = _origins.get(name);
485         if (o == null)
486             return null;
487         return o.getDescriptor();
488     }
489     
490     public void setOrigin (String name, Descriptor d)
491     {
492         OriginInfo x = new OriginInfo (name, d);
493         _origins.put(name, x);
494     }
495     
496     public void setOrigin (String name)
497     {
498         if (name == null)
499             return;
500        
501         OriginInfo x = new OriginInfo (name, Origin.Annotation);
502         _origins.put(name, x);
503     }
504 
505     public boolean isMetaDataComplete()
506     {
507         return _metaDataComplete;
508     }
509 
510     
511     public void addWebInfJar(Resource newResource)
512     {
513         _webInfJars.add(newResource);
514     }
515 
516     public List<Resource> getWebInfJars()
517     {
518         return Collections.unmodifiableList(_webInfJars);
519     }
520     
521     public List<Resource> getOrderedContainerJars()
522     {
523         return _orderedContainerJars;
524     }
525     
526     public void addContainerJar(Resource jar)
527     {
528         _orderedContainerJars.add(jar);
529     }
530     public boolean isAllowDuplicateFragmentNames()
531     {
532         return allowDuplicateFragmentNames;
533     }
534 
535     public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)
536     {
537         this.allowDuplicateFragmentNames = allowDuplicateFragmentNames;
538     }
539 }