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