// ======================================================================== // Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.webapp; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; /** * MetaData * * All data associated with the configuration and deployment of a web application. */ public class MetaData { private static final Logger LOG = Log.getLogger(MetaData.class); public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs"; protected Map<String, OriginInfo> _origins =new HashMap<String,OriginInfo>(); protected WebDescriptor _webDefaultsRoot; protected WebDescriptor _webXmlRoot; protected final List<WebDescriptor> _webOverrideRoots=new ArrayList<WebDescriptor>(); protected boolean _metaDataComplete; protected final List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>(); protected final List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>(); protected final List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>(); protected final Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>(); protected final Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>(); protected final Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>(); protected final List<Resource> _webInfJars = new ArrayList<Resource>(); protected final List<Resource> _orderedWebInfJars = new ArrayList<Resource>(); protected final List<Resource> _orderedContainerJars = new ArrayList<Resource>(); protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml protected boolean allowDuplicateFragmentNames = false; public static class OriginInfo { protected String name; protected Origin origin; protected Descriptor descriptor; public OriginInfo (String n, Descriptor d) { name = n; descriptor = d; if (d == null) throw new IllegalArgumentException("No descriptor"); if (d instanceof FragmentDescriptor) origin = Origin.WebFragment; else if (d instanceof OverrideDescriptor) origin = Origin.WebOverride; else if (d instanceof DefaultsDescriptor) origin = Origin.WebDefaults; else origin = Origin.WebXml; } public OriginInfo (String n) { name = n; origin = Origin.Annotation; } public OriginInfo(String n, Origin o) { name = n; origin = o; } public String getName() { return name; } public Origin getOriginType() { return origin; } public Descriptor getDescriptor() { return descriptor; } } public MetaData () { } /** * Empty ready for reuse */ public void clear () { _webDefaultsRoot = null; _origins.clear(); _webXmlRoot = null; _webOverrideRoots.clear(); _metaDataComplete = false; _annotations.clear(); _descriptorProcessors.clear(); _webFragmentRoots.clear(); _webFragmentNameMap.clear(); _webFragmentResourceMap.clear(); _webFragmentAnnotations.clear(); _webInfJars.clear(); _orderedWebInfJars.clear(); _orderedContainerJars.clear(); _ordering = null; allowDuplicateFragmentNames = false; } public void setDefaults (Resource webDefaults) throws Exception { _webDefaultsRoot = new DefaultsDescriptor(webDefaults); _webDefaultsRoot.parse(); if (_webDefaultsRoot.isOrdered()) { if (_ordering == null) _ordering = new Ordering.AbsoluteOrdering(this); List<String> order = _webDefaultsRoot.getOrdering(); for (String s:order) { if (s.equalsIgnoreCase("others")) ((Ordering.AbsoluteOrdering)_ordering).addOthers(); else ((Ordering.AbsoluteOrdering)_ordering).add(s); } } } public void setWebXml (Resource webXml) throws Exception { _webXmlRoot = new WebDescriptor(webXml); _webXmlRoot.parse(); _metaDataComplete=_webXmlRoot.getMetaDataComplete() == MetaDataComplete.True; if (_webXmlRoot.isOrdered()) { if (_ordering == null) _ordering = new Ordering.AbsoluteOrdering(this); List<String> order = _webXmlRoot.getOrdering(); for (String s:order) { if (s.equalsIgnoreCase("others")) ((Ordering.AbsoluteOrdering)_ordering).addOthers(); else ((Ordering.AbsoluteOrdering)_ordering).add(s); } } } public void addOverride (Resource override) throws Exception { OverrideDescriptor webOverrideRoot = new OverrideDescriptor(override); webOverrideRoot.setValidating(false); webOverrideRoot.parse(); switch(webOverrideRoot.getMetaDataComplete()) { case True: _metaDataComplete=true; break; case False: _metaDataComplete=true; break; case NotSet: break; } if (webOverrideRoot.isOrdered()) { if (_ordering == null) _ordering = new Ordering.AbsoluteOrdering(this); List<String> order = webOverrideRoot.getOrdering(); for (String s:order) { if (s.equalsIgnoreCase("others")) ((Ordering.AbsoluteOrdering)_ordering).addOthers(); else ((Ordering.AbsoluteOrdering)_ordering).add(s); } } _webOverrideRoots.add(webOverrideRoot); } /** * Add a web-fragment.xml * * @param jarResource the jar the fragment is contained in * @param xmlResource the resource representing the xml file * @throws Exception */ public void addFragment (Resource jarResource, Resource xmlResource) throws Exception { if (_metaDataComplete) return; //do not process anything else if web.xml/web-override.xml set metadata-complete //Metadata-complete is not set, or there is no web.xml FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource); _webFragmentResourceMap.put(jarResource, descriptor); _webFragmentRoots.add(descriptor); descriptor.parse(); if (descriptor.getName() != null) { Descriptor existing = _webFragmentNameMap.get(descriptor.getName()); if (existing != null && !isAllowDuplicateFragmentNames()) { throw new IllegalStateException("Duplicate fragment name: "+descriptor.getName()+" for "+existing.getResource()+" and "+descriptor.getResource()); } else _webFragmentNameMap.put(descriptor.getName(), descriptor); } //If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment if (_ordering != null && _ordering.isAbsolute()) return; if (_ordering == null && descriptor.isOrdered()) _ordering = new Ordering.RelativeOrdering(this); } /** * Annotations not associated with a WEB-INF/lib fragment jar. * These are from WEB-INF/classes or the ??container path?? * @param annotations */ public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations) { _annotations.addAll(annotations); } public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations) { _webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations)); } public void addDescriptorProcessor(DescriptorProcessor p) { _descriptorProcessors.add(p); } public void orderFragments () { //if we have already ordered them don't do it again if (_orderedWebInfJars.size()==_webInfJars.size()) return; if (_ordering != null) _orderedWebInfJars.addAll(_ordering.order(_webInfJars)); else _orderedWebInfJars.addAll(_webInfJars); } /** * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations. * */ public void resolve (WebAppContext context) throws Exception { LOG.debug("metadata resolve {}",context); //Ensure origins is fresh _origins.clear(); // Set the ordered lib attribute if (_ordering != null) { List<String> orderedLibs = new ArrayList<String>(); for (Resource webInfJar:_orderedWebInfJars) { //get just the name of the jar file String fullname = webInfJar.getName(); int i = fullname.indexOf(".jar"); int j = fullname.lastIndexOf("/", i); orderedLibs.add(fullname.substring(j+1,i+4)); } context.setAttribute(ORDERED_LIBS, orderedLibs); } for (DescriptorProcessor p:_descriptorProcessors) { p.process(context,getWebDefault()); p.process(context,getWebXml()); for (WebDescriptor wd : getOverrideWebs()) { LOG.debug("process {} {}",context,wd); p.process(context,wd); } } for (DiscoveredAnnotation a:_annotations) { LOG.debug("apply {}",a); a.apply(); } List<Resource> resources = getOrderedWebInfJars(); for (Resource r:resources) { FragmentDescriptor fd = _webFragmentResourceMap.get(r); if (fd != null) { for (DescriptorProcessor p:_descriptorProcessors) { LOG.debug("process {} {}",context,fd); p.process(context,fd); } } List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r); if (fragAnnotations != null) { for (DiscoveredAnnotation a:fragAnnotations) { LOG.debug("apply {}",a); a.apply(); } } } } public boolean isDistributable () { boolean distributable = ( (_webDefaultsRoot != null && _webDefaultsRoot.isDistributable()) || (_webXmlRoot != null && _webXmlRoot.isDistributable())); for (WebDescriptor d : _webOverrideRoots) distributable&=d.isDistributable(); List<Resource> orderedResources = getOrderedWebInfJars(); for (Resource r: orderedResources) { FragmentDescriptor d = _webFragmentResourceMap.get(r); if (d!=null) distributable = distributable && d.isDistributable(); } return distributable; } public WebDescriptor getWebXml () { return _webXmlRoot; } public List<WebDescriptor> getOverrideWebs () { return _webOverrideRoots; } public WebDescriptor getWebDefault () { return _webDefaultsRoot; } public List<FragmentDescriptor> getFragments () { return _webFragmentRoots; } public List<Resource> getOrderedWebInfJars() { return _orderedWebInfJars == null? new ArrayList<Resource>(): _orderedWebInfJars; } public List<FragmentDescriptor> getOrderedFragments () { List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>(); if (_orderedWebInfJars == null) return list; for (Resource r:_orderedWebInfJars) { FragmentDescriptor fd = _webFragmentResourceMap.get(r); if (fd != null) list.add(fd); } return list; } public Ordering getOrdering() { return _ordering; } public void setOrdering (Ordering o) { _ordering = o; } public FragmentDescriptor getFragment (Resource jar) { return _webFragmentResourceMap.get(jar); } public FragmentDescriptor getFragment(String name) { return _webFragmentNameMap.get(name); } public Resource getJarForFragment (String name) { FragmentDescriptor f = getFragment(name); if (f == null) return null; Resource jar = null; for (Resource r: _webFragmentResourceMap.keySet()) { if (_webFragmentResourceMap.get(r).equals(f)) jar = r; } return jar; } public Map<String,FragmentDescriptor> getNamedFragments () { return Collections.unmodifiableMap(_webFragmentNameMap); } public Origin getOrigin (String name) { OriginInfo x = _origins.get(name); if (x == null) return Origin.NotSet; return x.getOriginType(); } public Descriptor getOriginDescriptor (String name) { OriginInfo o = _origins.get(name); if (o == null) return null; return o.getDescriptor(); } public void setOrigin (String name, Descriptor d) { OriginInfo x = new OriginInfo (name, d); _origins.put(name, x); } public void setOrigin (String name) { if (name == null) return; OriginInfo x = new OriginInfo (name, Origin.Annotation); _origins.put(name, x); } public boolean isMetaDataComplete() { return _metaDataComplete; } public void addWebInfJar(Resource newResource) { _webInfJars.add(newResource); } public List<Resource> getWebInfJars() { return Collections.unmodifiableList(_webInfJars); } public List<Resource> getOrderedContainerJars() { return _orderedContainerJars; } public void addContainerJar(Resource jar) { _orderedContainerJars.add(jar); } public boolean isAllowDuplicateFragmentNames() { return allowDuplicateFragmentNames; } public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames) { this.allowDuplicateFragmentNames = allowDuplicateFragmentNames; } }