|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. |
| 2 | + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. |
3 | 3 | *
|
4 | 4 | * Licensed under the Universal Permissive License v 1.0 as shown at
|
5 |
| - * http://oss.oracle.com/licenses/upl. |
| 5 | + * https://oss.oracle.com/licenses/upl. |
6 | 6 | */
|
7 | 7 | package com.tangosol.run.xml;
|
8 | 8 |
|
|
23 | 23 | import java.net.URLConnection;
|
24 | 24 |
|
25 | 25 | import java.util.ArrayList;
|
| 26 | +import java.util.Collections; |
| 27 | +import java.util.Iterator; |
26 | 28 | import java.util.List;
|
27 | 29 |
|
28 | 30 | import java.util.concurrent.atomic.AtomicBoolean;
|
|
38 | 40 | import javax.xml.validation.SchemaFactory;
|
39 | 41 | import javax.xml.validation.Validator;
|
40 | 42 |
|
| 43 | +import org.w3c.dom.ls.LSInput; |
| 44 | +import org.w3c.dom.ls.LSResourceResolver; |
| 45 | + |
41 | 46 | import org.xml.sax.AttributeList;
|
42 | 47 | import org.xml.sax.DocumentHandler;
|
43 | 48 | import org.xml.sax.ErrorHandler;
|
@@ -270,8 +275,17 @@ public void validateXsd(String sXml, XmlDocument xml)
|
270 | 275 | return;
|
271 | 276 | }
|
272 | 277 |
|
273 |
| - SchemaFactory schemaFactory = SchemaFactory |
| 278 | + ResourceResolver resolver = null; |
| 279 | + SchemaFactory schemaFactory = SchemaFactory |
274 | 280 | .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
| 281 | + |
| 282 | + if (s_fJdk22 && "strict".equalsIgnoreCase(System.getProperty("javax.xml.catalog.resolve"))) |
| 283 | + { |
| 284 | + // specifying a custom resolver is a workaround for issue reported in OWLS-116652 |
| 285 | + resolver = new ResourceResolver(this.getClass()); |
| 286 | + schemaFactory.setResourceResolver(resolver); |
| 287 | + } |
| 288 | + |
275 | 289 | Schema schema = schemaFactory.newSchema(resolveSchemaSources(listSchemaURIs));
|
276 | 290 | Source source = new StreamSource(new StringReader(sXml));
|
277 | 291 | Validator validator = schema.newValidator();
|
@@ -301,6 +315,11 @@ public void validateXsd(String sXml, XmlDocument xml)
|
301 | 315 | validator.setErrorHandler(handler);
|
302 | 316 | validator.validate(source);
|
303 | 317 |
|
| 318 | + if (resolver != null) |
| 319 | + { |
| 320 | + resolver.closeStreams(); |
| 321 | + } |
| 322 | + |
304 | 323 | // optimize error handling to report all errors
|
305 | 324 | // prior to failing; this is easier for user that
|
306 | 325 | // has multiple problems to config files.
|
@@ -746,10 +765,200 @@ public void fatalError(SAXParseException exception)
|
746 | 765 | private XmlElement m_current;
|
747 | 766 | }
|
748 | 767 |
|
| 768 | + // ----- inner class: Input --------------------------------------------- |
| 769 | + |
| 770 | + /** |
| 771 | + * An LSInput implementation that is used when Java 22+ strict XML catalog resolve is enabled. |
| 772 | + * This class is required to work around the issue that is described in OWLS-116652 |
| 773 | + * |
| 774 | + * @since 24.03 |
| 775 | + */ |
| 776 | + public static class Input |
| 777 | + implements LSInput |
| 778 | + { |
| 779 | + // ----- constructors ----------------------------------------------- |
| 780 | + |
| 781 | + public Input(InputStream is, String publicId, String systemId) |
| 782 | + { |
| 783 | + this.is = is; |
| 784 | + this.publicId = publicId; |
| 785 | + this.systemId = systemId; |
| 786 | + } |
| 787 | + |
| 788 | + // ----- LSInput interface ------------------------------------------ |
| 789 | + |
| 790 | + @Override |
| 791 | + public Reader getCharacterStream() |
| 792 | + { |
| 793 | + return null; |
| 794 | + } |
| 795 | + |
| 796 | + @Override |
| 797 | + public void setCharacterStream(Reader characterStream) |
| 798 | + { |
| 799 | + } |
| 800 | + |
| 801 | + @Override |
| 802 | + public InputStream getByteStream() |
| 803 | + { |
| 804 | + return this.is; |
| 805 | + } |
| 806 | + |
| 807 | + @Override |
| 808 | + public void setByteStream(InputStream byteStream) |
| 809 | + { |
| 810 | + } |
| 811 | + |
| 812 | + @Override |
| 813 | + public String getStringData() |
| 814 | + { |
| 815 | + return null; |
| 816 | + } |
| 817 | + |
| 818 | + @Override |
| 819 | + public void setStringData(String stringData) |
| 820 | + { |
| 821 | + } |
| 822 | + |
| 823 | + @Override |
| 824 | + public String getSystemId() |
| 825 | + { |
| 826 | + return this.systemId; |
| 827 | + } |
| 828 | + |
| 829 | + @Override |
| 830 | + public void setSystemId(String systemId) |
| 831 | + { |
| 832 | + } |
| 833 | + |
| 834 | + @Override |
| 835 | + public String getPublicId() |
| 836 | + { |
| 837 | + return this.publicId; |
| 838 | + } |
| 839 | + |
| 840 | + @Override |
| 841 | + public void setPublicId(String publicId) |
| 842 | + { |
| 843 | + } |
| 844 | + @Override |
| 845 | + public String getBaseURI() |
| 846 | + { |
| 847 | + return null; |
| 848 | + } |
| 849 | + |
| 850 | + @Override |
| 851 | + public void setBaseURI(String baseURI) |
| 852 | + { |
| 853 | + } |
| 854 | + |
| 855 | + @Override |
| 856 | + public String getEncoding() |
| 857 | + { |
| 858 | + return null; |
| 859 | + } |
| 860 | + |
| 861 | + @Override |
| 862 | + public void setEncoding(String encoding) |
| 863 | + { |
| 864 | + } |
| 865 | + |
| 866 | + @Override |
| 867 | + public boolean getCertifiedText() |
| 868 | + { |
| 869 | + return false; |
| 870 | + } |
| 871 | + |
| 872 | + @Override |
| 873 | + public void setCertifiedText(boolean certifiedText) |
| 874 | + { |
| 875 | + } |
| 876 | + |
| 877 | + // ----- data members ----------------------------------------------- |
| 878 | + |
| 879 | + private InputStream is; |
| 880 | + |
| 881 | + private String publicId; |
| 882 | + |
| 883 | + private String systemId; |
| 884 | + } |
| 885 | + |
| 886 | + // ----- inner class: ResourceResolver ---------------------------------- |
| 887 | + |
| 888 | + /** |
| 889 | + * An ResourceResolver implementation that is used when Java 22+ strict XML catalog resolve is enabled. |
| 890 | + * This class is required to work around the issue that is described in OWLS-116652 |
| 891 | + * |
| 892 | + * @since 24.03 |
| 893 | + */ |
| 894 | + public static class ResourceResolver |
| 895 | + implements LSResourceResolver |
| 896 | + { |
| 897 | + // ----- constructors ----------------------------------------------- |
| 898 | + |
| 899 | + ResourceResolver(Class<?> clazz) |
| 900 | + { |
| 901 | + this.clazz = clazz; |
| 902 | + } |
| 903 | + |
| 904 | + // ----- LSResourceResolver interface ------------------------------- |
| 905 | + |
| 906 | + @Override |
| 907 | + public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) |
| 908 | + { |
| 909 | + InputStream is = this.clazz.getResourceAsStream("/" + systemId); |
| 910 | + |
| 911 | + if (is == null) |
| 912 | + { |
| 913 | + Logger.warn("SaxParser.ResourceResolver.resolveResource: failed to resolve \"/" + systemId + " resolution: " + baseURI + "/" + systemId); |
| 914 | + return null; |
| 915 | + } |
| 916 | + else |
| 917 | + { |
| 918 | + this.streamsToClose.add(is); |
| 919 | + return new Input(is, publicId, systemId); |
| 920 | + } |
| 921 | + } |
| 922 | + |
| 923 | + /** |
| 924 | + * Close all streams created by this resolver. |
| 925 | + */ |
| 926 | + void closeStreams() |
| 927 | + { |
| 928 | + Iterator iter = this.streamsToClose.iterator(); |
| 929 | + |
| 930 | + while (iter.hasNext()) |
| 931 | + { |
| 932 | + InputStream is = (InputStream) iter.next(); |
| 933 | + if (is != null) |
| 934 | + { |
| 935 | + try |
| 936 | + { |
| 937 | + is.close(); |
| 938 | + } |
| 939 | + catch (IOException e) |
| 940 | + { |
| 941 | + } |
| 942 | + } |
| 943 | + } |
| 944 | + } |
| 945 | + |
| 946 | + // ----- data members ----------------------------------------------- |
| 947 | + |
| 948 | + private List<InputStream> streamsToClose = Collections.synchronizedList(new ArrayList()); |
| 949 | + |
| 950 | + private Class<?> clazz; |
| 951 | + } |
| 952 | + |
749 | 953 | // ----- constants ------------------------------------------------------
|
750 | 954 |
|
751 | 955 | /**
|
752 | 956 | * Record if resolved SaxParser supports JAXP 1.5 {@link XMLConstants#ACCESS_EXTERNAL_DTD} and {@link XMLConstants#ACCESS_EXTERNAL_SCHEMA} properties. Only report warning once if does not.
|
753 | 957 | */
|
754 | 958 | private static final AtomicBoolean ATTEMPT_RESTRICT_EXTERNAL = new AtomicBoolean(true);
|
| 959 | + |
| 960 | + /** |
| 961 | + * True iff if jvm runtime is JDK 22 or higher. |
| 962 | + */ |
| 963 | + private static boolean s_fJdk22 = Runtime.version().feature() > 21; |
755 | 964 | }
|
0 commit comments