View Javadoc

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