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