View Javadoc

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