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 OriginInfo(String n, Descriptor d)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 OriginInfo(String n)90 public OriginInfo (String n) 91 { 92 name = n; 93 origin = Origin.Annotation; 94 } 95 OriginInfo(String n, Origin o)96 public OriginInfo(String n, Origin o) 97 { 98 name = n; 99 origin = o; 100 } 101 getName()102 public String getName() 103 { 104 return name; 105 } 106 getOriginType()107 public Origin getOriginType() 108 { 109 return origin; 110 } 111 getDescriptor()112 public Descriptor getDescriptor() 113 { 114 return descriptor; 115 } 116 } 117 MetaData()118 public MetaData () 119 { 120 } 121 122 /** 123 * Empty ready for reuse 124 */ clear()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 setDefaults(Resource webDefaults)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 setWebXml(Resource webXml)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 addOverride(Resource override)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 */ addFragment(Resource jarResource, Resource xmlResource)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 */ addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)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 addDiscoveredAnnotation(Resource resource, DiscoveredAnnotation annotation)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 addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)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 addDescriptorProcessor(DescriptorProcessor p)312 public void addDescriptorProcessor(DescriptorProcessor p) 313 { 314 _descriptorProcessors.add(p); 315 } 316 orderFragments()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 */ resolve(WebAppContext context)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 isDistributable()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 getWebXml()428 public WebDescriptor getWebXml () 429 { 430 return _webXmlRoot; 431 } 432 getOverrideWebs()433 public List<WebDescriptor> getOverrideWebs () 434 { 435 return _webOverrideRoots; 436 } 437 getWebDefault()438 public WebDescriptor getWebDefault () 439 { 440 return _webDefaultsRoot; 441 } 442 getFragments()443 public List<FragmentDescriptor> getFragments () 444 { 445 return _webFragmentRoots; 446 } 447 getOrderedWebInfJars()448 public List<Resource> getOrderedWebInfJars() 449 { 450 return _orderedWebInfJars == null? new ArrayList<Resource>(): _orderedWebInfJars; 451 } 452 getOrderedFragments()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 getOrdering()468 public Ordering getOrdering() 469 { 470 return _ordering; 471 } 472 setOrdering(Ordering o)473 public void setOrdering (Ordering o) 474 { 475 _ordering = o; 476 } 477 getFragment(Resource jar)478 public FragmentDescriptor getFragment (Resource jar) 479 { 480 return _webFragmentResourceMap.get(jar); 481 } 482 getFragment(String name)483 public FragmentDescriptor getFragment(String name) 484 { 485 return _webFragmentNameMap.get(name); 486 } 487 getJarForFragment(String name)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 getNamedFragments()503 public Map<String,FragmentDescriptor> getNamedFragments () 504 { 505 return Collections.unmodifiableMap(_webFragmentNameMap); 506 } 507 508 getOrigin(String name)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 getOriginDescriptor(String name)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 setOrigin(String name, Descriptor d)527 public void setOrigin (String name, Descriptor d) 528 { 529 OriginInfo x = new OriginInfo (name, d); 530 _origins.put(name, x); 531 } 532 setOrigin(String name)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 setOrigin(String name, Origin origin)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 isMetaDataComplete()551 public boolean isMetaDataComplete() 552 { 553 return _metaDataComplete; 554 } 555 556 addWebInfJar(Resource newResource)557 public void addWebInfJar(Resource newResource) 558 { 559 _webInfJars.add(newResource); 560 } 561 getWebInfJars()562 public List<Resource> getWebInfJars() 563 { 564 return Collections.unmodifiableList(_webInfJars); 565 } 566 getOrderedContainerJars()567 public List<Resource> getOrderedContainerJars() 568 { 569 return _orderedContainerJars; 570 } 571 addContainerJar(Resource jar)572 public void addContainerJar(Resource jar) 573 { 574 _orderedContainerJars.add(jar); 575 } isAllowDuplicateFragmentNames()576 public boolean isAllowDuplicateFragmentNames() 577 { 578 return allowDuplicateFragmentNames; 579 } 580 setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)581 public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames) 582 { 583 this.allowDuplicateFragmentNames = allowDuplicateFragmentNames; 584 } 585 } 586