| 1 18 19 package org.apache.tools.ant.types; 20 21 import java.lang.reflect.Method ; 22 23 import java.io.File ; 24 import java.io.FileInputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.net.MalformedURLException ; 28 import java.net.URL ; 29 import java.util.Enumeration ; 30 import java.util.Vector ; 31 import javax.xml.parsers.ParserConfigurationException ; 32 import javax.xml.parsers.SAXParserFactory ; 33 import javax.xml.transform.Source ; 34 import javax.xml.transform.TransformerException ; 35 import javax.xml.transform.URIResolver ; 36 import javax.xml.transform.sax.SAXSource ; 37 import org.apache.tools.ant.AntClassLoader; 38 import org.apache.tools.ant.BuildException; 39 import org.apache.tools.ant.Project; 40 import org.apache.tools.ant.util.FileUtils; 41 import org.apache.tools.ant.util.JAXPUtils; 42 import org.xml.sax.EntityResolver ; 43 import org.xml.sax.InputSource ; 44 import org.xml.sax.SAXException ; 45 import org.xml.sax.XMLReader ; 46 47 48 49 119 public class XMLCatalog extends DataType 120 implements Cloneable , EntityResolver , URIResolver { 121 122 123 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 124 125 127 128 private Vector elements = new Vector (); 129 130 133 private Path classpath; 134 135 138 private Path catalogPath; 139 140 145 public static final String APACHE_RESOLVER 146 = "org.apache.tools.ant.types.resolver.ApacheCatalogResolver"; 147 148 151 public static final String CATALOG_RESOLVER 152 = "org.apache.xml.resolver.tools.CatalogResolver"; 153 154 156 159 public XMLCatalog() { 160 setChecked(false); 161 } 162 163 168 private Vector getElements() { 169 return getRef().elements; 170 } 171 172 177 private Path getClasspath() { 178 return getRef().classpath; 179 } 180 181 189 public Path createClasspath() { 190 if (isReference()) { 191 throw noChildrenAllowed(); 192 } 193 if (this.classpath == null) { 194 this.classpath = new Path(getProject()); 195 } 196 setChecked(false); 197 return this.classpath.createPath(); 198 } 199 200 208 public void setClasspath(Path classpath) { 209 if (isReference()) { 210 throw tooManyAttributes(); 211 } 212 if (this.classpath == null) { 213 this.classpath = classpath; 214 } else { 215 this.classpath.append(classpath); 216 } 217 setChecked(false); 218 } 219 220 228 public void setClasspathRef(Reference r) { 229 if (isReference()) { 230 throw tooManyAttributes(); 231 } 232 createClasspath().setRefid(r); 233 setChecked(false); 234 } 235 236 245 public Path createCatalogPath() { 246 if (isReference()) { 247 throw noChildrenAllowed(); 248 } 249 if (this.catalogPath == null) { 250 this.catalogPath = new Path(getProject()); 251 } 252 setChecked(false); 253 return this.catalogPath.createPath(); 254 } 255 256 265 public void setCatalogPathRef(Reference r) { 266 if (isReference()) { 267 throw tooManyAttributes(); 268 } 269 createCatalogPath().setRefid(r); 270 setChecked(false); 271 } 272 273 274 279 public Path getCatalogPath() { 280 return getRef().catalogPath; 281 } 282 283 284 295 public void addDTD(ResourceLocation dtd) throws BuildException { 296 if (isReference()) { 297 throw noChildrenAllowed(); 298 } 299 300 getElements().addElement(dtd); 301 setChecked(false); 302 } 303 304 315 public void addEntity(ResourceLocation entity) throws BuildException { 316 addDTD(entity); 317 } 318 319 327 public void addConfiguredXMLCatalog(XMLCatalog catalog) { 328 if (isReference()) { 329 throw noChildrenAllowed(); 330 } 331 332 Vector newElements = catalog.getElements(); 334 Vector ourElements = getElements(); 335 Enumeration e = newElements.elements(); 336 while (e.hasMoreElements()) { 337 ourElements.addElement(e.nextElement()); 338 } 339 340 Path nestedClasspath = catalog.getClasspath(); 342 createClasspath().append(nestedClasspath); 343 344 Path nestedCatalogPath = catalog.getCatalogPath(); 346 createCatalogPath().append(nestedCatalogPath); 347 setChecked(false); 348 } 349 350 362 public void setRefid(Reference r) throws BuildException { 363 if (!elements.isEmpty()) { 364 throw tooManyAttributes(); 365 } 366 super.setRefid(r); 367 } 368 369 378 public InputSource resolveEntity(String publicId, String systemId) 379 throws SAXException , IOException { 380 381 if (isReference()) { 382 return getRef().resolveEntity(publicId, systemId); 383 } 384 385 dieOnCircularReference(); 386 387 log("resolveEntity: '" + publicId + "': '" + systemId + "'", 388 Project.MSG_DEBUG); 389 390 InputSource inputSource = 391 getCatalogResolver().resolveEntity(publicId, systemId); 392 393 if (inputSource == null) { 394 log("No matching catalog entry found, parser will use: '" 395 + systemId + "'", Project.MSG_DEBUG); 396 } 397 398 return inputSource; 399 } 400 401 409 public Source resolve(String href, String base) 410 throws TransformerException { 411 412 if (isReference()) { 413 return getRef().resolve(href, base); 414 } 415 416 dieOnCircularReference(); 417 418 SAXSource source = null; 419 420 String uri = removeFragment(href); 421 422 log("resolve: '" + uri + "' with base: '" + base + "'", Project.MSG_DEBUG); 423 424 source = (SAXSource ) getCatalogResolver().resolve(uri, base); 425 426 if (source == null) { 427 log("No matching catalog entry found, parser will use: '" 428 + href + "'", Project.MSG_DEBUG); 429 source = new SAXSource (); 434 URL baseURL = null; 435 try { 436 if (base == null) { 437 baseURL = FILE_UTILS.getFileURL(getProject().getBaseDir()); 438 } else { 439 baseURL = new URL (base); 440 } 441 URL url = (uri.length() == 0 ? baseURL : new URL (baseURL, uri)); 442 source.setInputSource(new InputSource (url.toString())); 443 } catch (MalformedURLException ex) { 444 source.setInputSource(new InputSource (uri)); 447 } 448 } 449 450 setEntityResolver(source); 451 return source; 452 } 453 454 457 private XMLCatalog getRef() { 458 if (!isReference()) { 459 return this; 460 } 461 return (XMLCatalog) getCheckedRef(XMLCatalog.class, "xmlcatalog"); 462 } 463 464 467 private CatalogResolver catalogResolver = null; 468 469 479 private CatalogResolver getCatalogResolver() { 480 481 if (catalogResolver == null) { 482 483 AntClassLoader loader = null; 484 485 loader = getProject().createClassLoader(Path.systemClasspath); 486 487 try { 488 Class clazz = Class.forName(APACHE_RESOLVER, true, loader); 489 490 ClassLoader apacheResolverLoader = clazz.getClassLoader(); 494 495 Class baseResolverClass 497 = Class.forName(CATALOG_RESOLVER, true, apacheResolverLoader); 498 499 ClassLoader baseResolverLoader 501 = baseResolverClass.getClassLoader(); 502 503 clazz = Class.forName(APACHE_RESOLVER, true, baseResolverLoader); 508 509 Object obj = clazz.newInstance(); 510 catalogResolver = new ExternalResolver(clazz, obj); 515 } catch (Throwable ex) { 516 catalogResolver = new InternalResolver(); 521 if (getCatalogPath() != null 522 && getCatalogPath().list().length != 0) { 523 log("Warning: XML resolver not found; external catalogs" 524 + " will be ignored", Project.MSG_WARN); 525 } 526 log("Failed to load Apache resolver: " + ex, Project.MSG_DEBUG); 527 } 528 } 529 return catalogResolver; 530 } 531 532 551 private void setEntityResolver(SAXSource source) throws TransformerException { 552 553 XMLReader reader = source.getXMLReader(); 554 if (reader == null) { 555 SAXParserFactory spFactory = SAXParserFactory.newInstance(); 556 spFactory.setNamespaceAware(true); 557 try { 558 reader = spFactory.newSAXParser().getXMLReader(); 559 } catch (ParserConfigurationException ex) { 560 throw new TransformerException (ex); 561 } catch (SAXException ex) { 562 throw new TransformerException (ex); 563 } 564 } 565 reader.setEntityResolver(this); 566 source.setXMLReader(reader); 567 } 568 569 577 private ResourceLocation findMatchingEntry(String publicId) { 578 Enumeration e = getElements().elements(); 579 ResourceLocation element = null; 580 while (e.hasMoreElements()) { 581 Object o = e.nextElement(); 582 if (o instanceof ResourceLocation) { 583 element = (ResourceLocation) o; 584 if (element.getPublicId().equals(publicId)) { 585 return element; 586 } 587 } 588 } 589 return null; 590 } 591 592 602 private String removeFragment(String uri) { 603 String result = uri; 604 int hashPos = uri.indexOf("#"); 605 if (hashPos >= 0) { 606 result = uri.substring(0, hashPos); 607 } 608 return result; 609 } 610 611 617 private InputSource filesystemLookup(ResourceLocation matchingEntry) { 618 619 String uri = matchingEntry.getLocation(); 620 uri = uri.replace(File.separatorChar, '/'); 622 URL baseURL = null; 623 624 if (matchingEntry.getBase() != null) { 630 baseURL = matchingEntry.getBase(); 631 } else { 632 try { 633 baseURL = FILE_UTILS.getFileURL(getProject().getBaseDir()); 634 } catch (MalformedURLException ex) { 635 throw new BuildException("Project basedir cannot be converted to a URL"); 636 } 637 } 638 639 InputSource source = null; 640 URL url = null; 641 try { 642 url = new URL (baseURL, uri); 643 } catch (MalformedURLException ex) { 644 File testFile = new File (uri); 648 if (testFile.exists() && testFile.canRead()) { 649 log("uri : '" 650 + uri + "' matches a readable file", Project.MSG_DEBUG); 651 try { 652 url = FILE_UTILS.getFileURL(testFile); 653 } catch (MalformedURLException ex1) { 654 throw new BuildException( 655 "could not find an URL for :" + testFile.getAbsolutePath()); 656 } 657 } else { 658 log("uri : '" 659 + uri + "' does not match a readable file", Project.MSG_DEBUG); 660 661 } 662 } 663 664 if (url != null && url.getProtocol().equals("file")) { 665 String fileName = FILE_UTILS.fromURI(url.toString()); 666 if (fileName != null) { 667 log("fileName " + fileName, Project.MSG_DEBUG); 668 File resFile = new File (fileName); 669 if (resFile.exists() && resFile.canRead()) { 670 try { 671 source = new InputSource (new FileInputStream (resFile)); 672 String sysid = JAXPUtils.getSystemId(resFile); 673 source.setSystemId(sysid); 674 log("catalog entry matched a readable file: '" 675 + sysid + "'", Project.MSG_DEBUG); 676 } catch (IOException ex) { 677 } 679 } 680 } 681 } 682 return source; 683 } 684 685 691 private InputSource classpathLookup(ResourceLocation matchingEntry) { 692 693 InputSource source = null; 694 695 AntClassLoader loader = null; 696 Path cp = classpath; 697 if (cp != null) { 698 cp = classpath.concatSystemClasspath("ignore"); 699 } else { 700 cp = (new Path(getProject())).concatSystemClasspath("last"); 701 } 702 loader = getProject().createClassLoader(cp); 703 704 InputStream is 708 = loader.getResourceAsStream(matchingEntry.getLocation()); 709 710 if (is != null) { 711 source = new InputSource (is); 712 URL entryURL = loader.getResource(matchingEntry.getLocation()); 713 String sysid = entryURL.toExternalForm(); 714 source.setSystemId(sysid); 715 log("catalog entry matched a resource in the classpath: '" 716 + sysid + "'", Project.MSG_DEBUG); 717 } 718 719 return source; 720 } 721 722 728 private InputSource urlLookup(ResourceLocation matchingEntry) { 729 730 String uri = matchingEntry.getLocation(); 731 URL baseURL = null; 732 733 if (matchingEntry.getBase() != null) { 739 baseURL = matchingEntry.getBase(); 740 } else { 741 try { 742 baseURL = FILE_UTILS.getFileURL(getProject().getBaseDir()); 743 } catch (MalformedURLException ex) { 744 throw new BuildException("Project basedir cannot be converted to a URL"); 745 } 746 } 747 748 InputSource source = null; 749 URL url = null; 750 751 try { 752 url = new URL (baseURL, uri); 753 } catch (MalformedURLException ex) { 754 } 756 757 if (url != null) { 758 try { 759 InputStream is = url.openStream(); 760 if (is != null) { 761 source = new InputSource (is); 762 String sysid = url.toExternalForm(); 763 source.setSystemId(sysid); 764 log("catalog entry matched as a URL: '" 765 + sysid + "'", Project.MSG_DEBUG); 766 } 767 } catch (IOException ex) { 768 } 770 } 771 772 return source; 773 774 } 775 776 780 private interface CatalogResolver extends URIResolver , EntityResolver { 781 782 InputSource resolveEntity(String publicId, String systemId); 783 784 Source resolve(String href, String base) throws TransformerException ; 785 } 786 787 794 private class InternalResolver implements CatalogResolver { 795 796 public InternalResolver() { 797 log("Apache resolver library not found, internal resolver will be used", 798 Project.MSG_VERBOSE); 799 } 800 801 public InputSource resolveEntity(String publicId, 802 String systemId) { 803 InputSource result = null; 804 ResourceLocation matchingEntry = findMatchingEntry(publicId); 805 806 if (matchingEntry != null) { 807 808 log("Matching catalog entry found for publicId: '" 809 + matchingEntry.getPublicId() + "' location: '" 810 + matchingEntry.getLocation() + "'", 811 Project.MSG_DEBUG); 812 813 result = filesystemLookup(matchingEntry); 814 815 if (result == null) { 816 result = classpathLookup(matchingEntry); 817 } 818 819 if (result == null) { 820 result = urlLookup(matchingEntry); 821 } 822 } 823 return result; 824 } 825 826 public Source resolve(String href, String base) 827
|