Home | History | Annotate | Download | only in webapp
      1 //
      2 //  ========================================================================
      3 //  Copyright (c) 1995-2014 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 }
    586