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 throws TransformerException { 828 829 SAXSource result = null; 830 InputSource source = null; 831 832 ResourceLocation matchingEntry = findMatchingEntry(href); 833 834 if (matchingEntry != null) { 835 836 log("Matching catalog entry found for uri: '" 837 + matchingEntry.getPublicId() + "' location: '" 838 + matchingEntry.getLocation() + "'", 839 Project.MSG_DEBUG); 840 841 ResourceLocation entryCopy = matchingEntry; 852 if (base != null) { 853 try { 854 URL baseURL = new URL (base); 855 entryCopy = new ResourceLocation(); 856 entryCopy.setBase(baseURL); 857 } catch (MalformedURLException ex) { 858 } 860 } 861 entryCopy.setPublicId(matchingEntry.getPublicId()); 862 entryCopy.setLocation(matchingEntry.getLocation()); 863 864 source = filesystemLookup(entryCopy); 865 866 if (source == null) { 867 source = classpathLookup(entryCopy); 868 } 869 870 if (source == null) { 871 source = urlLookup(entryCopy); 872 } 873 874 if (source != null) { 875 result = new SAXSource (source); 876 } 877 } 878 return result; 879 } 880 } 881 882 889 private class ExternalResolver implements CatalogResolver { 890 891 private Method setXMLCatalog = null; 892 private Method parseCatalog = null; 893 private Method resolveEntity = null; 894 private Method resolve = null; 895 896 897 private Object resolverImpl = null; 898 899 private boolean externalCatalogsProcessed = false; 900 901 public ExternalResolver(Class resolverImplClass, 902 Object resolverImpl) { 903 904 this.resolverImpl = resolverImpl; 905 906 try { 914 setXMLCatalog = 915 resolverImplClass.getMethod("setXMLCatalog", 916 new Class [] {XMLCatalog.class}); 917 918 parseCatalog = 919 resolverImplClass.getMethod("parseCatalog", 920 new Class [] {String .class}); 921 922 resolveEntity = 923 resolverImplClass.getMethod("resolveEntity", 924 new Class [] {String .class, String .class}); 925 926 resolve = 927 resolverImplClass.getMethod("resolve", 928 new Class [] {String .class, String .class}); 929 } catch (NoSuchMethodException ex) { 930 throw new BuildException(ex); 931 } 932 933 log("Apache resolver library found, xml-commons resolver will be used", 934 Project.MSG_VERBOSE); 935 } 936 937 public InputSource resolveEntity(String publicId, 938 String systemId) { 939 InputSource result = null; 940 941 processExternalCatalogs(); 942 943 ResourceLocation matchingEntry = findMatchingEntry(publicId); 944 945 if (matchingEntry != null) { 946 947 log("Matching catalog entry found for publicId: '" 948 + matchingEntry.getPublicId() + "' location: '" 949 + matchingEntry.getLocation() + "'", 950 Project.MSG_DEBUG); 951 952 result = filesystemLookup(matchingEntry); 953 954 if (result == null) { 955 result = classpathLookup(matchingEntry); 956 } 957 958 if (result == null) { 959 try { 960 result = 961 (InputSource ) resolveEntity.invoke(resolverImpl, 962 new Object [] {publicId, systemId}); 963 } catch (Exception ex) { 964 throw new BuildException(ex); 965 } 966 } 967 } else { 968 try { 977 result = 978 (InputSource ) resolveEntity.invoke(resolverImpl, 979 new Object [] {publicId, systemId}); 980 } catch (Exception ex) { 981 throw new BuildException(ex); 982 } 983 } 984 985 return result; 986 } 987 988 public Source resolve(String href, String base) 989 throws TransformerException { 990 991 SAXSource result = null; 992 InputSource source = null; 993 994 processExternalCatalogs(); 995 996 ResourceLocation matchingEntry = findMatchingEntry(href); 997 998 if (matchingEntry != null) { 999 1000 log("Matching catalog entry found for uri: '" 1001 + matchingEntry.getPublicId() + "' location: '" 1002 + matchingEntry.getLocation() + "'", 1003 Project.MSG_DEBUG); 1004 1005 ResourceLocation entryCopy = matchingEntry; 1018 if (base != null) { 1019 try { 1020 URL baseURL = new URL (base); 1021 entryCopy = new ResourceLocation(); 1022 entryCopy.setBase(baseURL); 1023 } catch (MalformedURLException ex) { 1024 } 1026 } 1027 entryCopy.setPublicId(matchingEntry.getPublicId()); 1028 entryCopy.setLocation(matchingEntry.getLocation()); 1029 1030 source = filesystemLookup(entryCopy); 1031 1032 if (source == null) { 1033 source = classpathLookup(entryCopy); 1034 } 1035 1036 if (source != null) { 1037 result = new SAXSource (source); 1038 } else { 1039 try { 1040 result = 1041 (SAXSource ) resolve.invoke(resolverImpl, 1042 new Object [] {href, base}); 1043 } catch (Exception ex) { 1044 throw new BuildException(ex); 1045 } 1046 } 1047 } else { 1048 try { 1057 result = 1058 (SAXSource ) resolve.invoke(resolverImpl, 1059 new Object [] {href, base}); 1060 } catch (Exception ex) { 1061 throw new BuildException(ex); 1062 } 1063 } 1064 return result; 1065 } 1066 1067 1074 private void processExternalCatalogs() { 1075 1076 if (!externalCatalogsProcessed) { 1077 1078 try { 1079 setXMLCatalog.invoke(resolverImpl, 1080 new Object [] {XMLCatalog.this}); 1081 } catch (Exception ex) { 1082 throw new BuildException(ex); 1083 } 1084 1085 Path catPath = getCatalogPath(); 1087 if (catPath != null) { 1088 log("Using catalogpath '" + getCatalogPath() + "'", 1089 Project.MSG_DEBUG); 1090 String [] catPathList = getCatalogPath().list(); 1091 1092 for (int i = 0; i < catPathList.length; i++) { 1093 File catFile = new File (catPathList[i]); 1094 log("Parsing " + catFile, Project.MSG_DEBUG); 1095 try { 1096 parseCatalog.invoke(resolverImpl, 1097 new Object [] {catFile.getPath()}); 1098 } catch (Exception ex) { 1099 throw new BuildException(ex); 1100 } 1101 } 1102 } 1103 } 1104 externalCatalogsProcessed = true; 1105 } 1106 } 1107} | Popular Tags |