Skip to content

Commit e4389d8

Browse files
committedJan 11, 2024
8323571: Regression in source resolution process
Reviewed-by: lancea, naoto
1 parent 49e6121 commit e4389d8

File tree

4 files changed

+357
-18
lines changed

4 files changed

+357
-18
lines changed
 

‎src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java

+24-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
33
*/
44
/*
55
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -94,7 +94,7 @@
9494
* @author K.Venugopal SUN Microsystems
9595
* @author Neeraj Bajaj SUN Microsystems
9696
* @author Sunitha Reddy SUN Microsystems
97-
* @LastModified: Nov 2023
97+
* @LastModified: Jan 2024
9898
*/
9999
public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
100100

@@ -1038,8 +1038,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI
10381038
}
10391039

10401040
// Step 2: custom catalog if specified
1041-
if ((publicId != null || literalSystemId != null) &&
1042-
staxInputSource == null && (fUseCatalog && fCatalogFile != null)) {
1041+
if (staxInputSource == null
1042+
&& (publicId != null || literalSystemId != null)
1043+
&& (fUseCatalog && fCatalogFile != null)) {
10431044
if (fCatalogResolver == null) {
10441045
fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve);
10451046
fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
@@ -1049,8 +1050,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI
10491050
}
10501051

10511052
// Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
1052-
if ((publicId != null || literalSystemId != null) &&
1053-
staxInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
1053+
if (staxInputSource == null
1054+
&& (publicId != null || literalSystemId != null)
1055+
&& JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
10541056
initJdkCatalogResolver();
10551057

10561058
staxInputSource = resolveWithCatalogStAX(fDefCR, JdkCatalog.JDKCATALOG, publicId, literalSystemId);
@@ -1061,9 +1063,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI
10611063
// Note if both publicId and systemId are null, the resolution process continues as usual
10621064
if (staxInputSource != null) {
10631065
fISCreatedByResolver = true;
1064-
} else if ((publicId == null && literalSystemId == null) ||
1065-
(JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
1066-
fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
1066+
} else if ((publicId == null && literalSystemId == null)
1067+
|| (JdkXmlUtils.isResolveContinue(fCatalogFeatures)
1068+
&& fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
10671069
staxInputSource = new StaxXMLInputSource(
10681070
new XMLInputSource(publicId, literalSystemId, baseSystemId, true), false);
10691071
}
@@ -1206,8 +1208,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
12061208
}
12071209

12081210
// Step 2: custom catalog if specified
1209-
if ((publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null)
1210-
&& xmlInputSource == null && (fUseCatalog && fCatalogFile != null)) {
1211+
if (xmlInputSource == null
1212+
&& (publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null)
1213+
&& (fUseCatalog && fCatalogFile != null)) {
12111214
if (fCatalogResolver == null) {
12121215
fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve);
12131216
fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
@@ -1217,20 +1220,23 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
12171220
}
12181221

12191222
// Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
1220-
if ((publicId != null || literalSystemId != null)
1221-
&& xmlInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
1223+
if (xmlInputSource == null
1224+
&& (publicId != null || literalSystemId != null)
1225+
&& JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
12221226
initJdkCatalogResolver();
12231227
// unlike a custom catalog, the JDK Catalog only contains entity references
12241228
xmlInputSource = resolveEntity(fDefCR, publicId, literalSystemId, baseSystemId);
12251229
}
12261230

12271231
// Step 4: default resolution if not resolved by a resolver and the RESOLVE
12281232
// feature is set to 'continue'
1229-
// Note if both publicId and systemId are null, the resolution process continues as usual
1230-
if ((publicId == null && literalSystemId == null) ||
1231-
((xmlInputSource == null) && JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
1232-
fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
1233-
xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false);
1233+
if (xmlInputSource == null) {
1234+
// Note if both publicId and systemId are null, the resolution process continues as usual
1235+
if ((publicId == null && literalSystemId == null) ||
1236+
(JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
1237+
fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
1238+
xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false);
1239+
}
12341240
}
12351241

12361242
return xmlInputSource;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package common.catalog;
24+
25+
import org.w3c.dom.ls.LSInput;
26+
import org.w3c.dom.ls.LSResourceResolver;
27+
import org.xml.sax.SAXException;
28+
29+
import javax.xml.catalog.CatalogFeatures;
30+
import javax.xml.transform.Source;
31+
import javax.xml.transform.stream.StreamSource;
32+
import javax.xml.validation.SchemaFactory;
33+
import java.io.IOException;
34+
import java.io.InputStream;
35+
import java.io.InputStreamReader;
36+
import java.io.Reader;
37+
import java.io.StringReader;
38+
import java.util.Collections;
39+
import java.util.HashMap;
40+
import java.util.Map;
41+
42+
import static java.util.Objects.requireNonNull;
43+
import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
44+
import static javax.xml.catalog.CatalogManager.catalogResolver;
45+
import javax.xml.catalog.CatalogResolver;
46+
import javax.xml.validation.Validator;
47+
import org.testng.annotations.Test;
48+
49+
/*
50+
* @test
51+
* @bug 8323571
52+
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
53+
* @run testng common.catalog.NullIdTest
54+
* @summary Verifies null values are handled properly in the source resolution
55+
* process.
56+
*/
57+
public class NullIdTest {
58+
private static final Map<String, String> SCHEMAS;
59+
// Source Level JDK 8
60+
static {
61+
Map<String, String> map = new HashMap<>();
62+
map.put("https://schemas.opentest4j.org/reporting/events/0.1.0", "events.xsd");
63+
map.put("https://schemas.opentest4j.org/reporting/core/0.1.0", "core.xsd");
64+
SCHEMAS = Collections.unmodifiableMap(map);
65+
}
66+
67+
/*
68+
* Verifies that the source resolution process recognizes the custom InputSource
69+
* correctly even though the public and system IDs are null.
70+
*/
71+
@Test
72+
public void test() throws Exception {
73+
String xml = "<events xmlns=\"https://schemas.opentest4j.org/reporting/events/0.1.0\"/>";
74+
validate(new StreamSource(new StringReader(xml)));
75+
System.out.println("Successfully validated");
76+
}
77+
78+
private static void validate(Source source) throws SAXException, IOException {
79+
SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI);
80+
Validator validator = schemaFactory.newSchema().newValidator();
81+
validator.setResourceResolver(createResourceResolver());
82+
validator.validate(source);
83+
}
84+
85+
private static LSResourceResolver createResourceResolver() {
86+
return (type, namespaceURI, publicId, systemId, baseURI) -> {
87+
if (namespaceURI != null) {
88+
if (SCHEMAS.containsKey(namespaceURI)) {
89+
CustomLSInputImpl input = new CustomLSInputImpl();
90+
input.setPublicId(publicId);
91+
String schema = SCHEMAS.get(namespaceURI);
92+
input.setSystemId(requireNonNull(NullIdTest.class.getResource(schema)).toExternalForm());
93+
input.setBaseURI(baseURI);
94+
InputStream stream = NullIdTest.class.getResourceAsStream(schema);
95+
input.setCharacterStream(new InputStreamReader(requireNonNull(stream)));
96+
return input;
97+
}
98+
}
99+
if (systemId != null) {
100+
CatalogFeatures features = CatalogFeatures.builder()
101+
.with(CatalogFeatures.Feature.RESOLVE, "continue")
102+
.build();
103+
CatalogResolver catalogResolver = catalogResolver(features);
104+
return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI);
105+
}
106+
return null;
107+
};
108+
}
109+
110+
static class CustomLSInputImpl implements LSInput {
111+
112+
private Reader characterStream;
113+
private InputStream byteStream;
114+
private String stringData;
115+
private String systemId;
116+
private String publicId;
117+
private String baseURI;
118+
private String encoding;
119+
private boolean certifiedText;
120+
121+
@Override
122+
public Reader getCharacterStream() {
123+
return characterStream;
124+
}
125+
126+
@Override
127+
public void setCharacterStream(Reader characterStream) {
128+
this.characterStream = characterStream;
129+
}
130+
131+
@Override
132+
public InputStream getByteStream() {
133+
return byteStream;
134+
}
135+
136+
@Override
137+
public void setByteStream(InputStream byteStream) {
138+
this.byteStream = byteStream;
139+
}
140+
141+
@Override
142+
public String getStringData() {
143+
return stringData;
144+
}
145+
146+
@Override
147+
public void setStringData(String stringData) {
148+
this.stringData = stringData;
149+
}
150+
151+
@Override
152+
public String getSystemId() {
153+
return systemId;
154+
}
155+
156+
@Override
157+
public void setSystemId(String systemId) {
158+
this.systemId = systemId;
159+
}
160+
161+
@Override
162+
public String getPublicId() {
163+
return publicId;
164+
}
165+
166+
@Override
167+
public void setPublicId(String publicId) {
168+
this.publicId = publicId;
169+
}
170+
171+
@Override
172+
public String getBaseURI() {
173+
return baseURI;
174+
}
175+
176+
@Override
177+
public void setBaseURI(String baseURI) {
178+
this.baseURI = baseURI;
179+
}
180+
181+
@Override
182+
public String getEncoding() {
183+
return encoding;
184+
}
185+
186+
@Override
187+
public void setEncoding(String encoding) {
188+
this.encoding = encoding;
189+
}
190+
191+
@Override
192+
public boolean getCertifiedText() {
193+
return certifiedText;
194+
}
195+
196+
@Override
197+
public void setCertifiedText(boolean certifiedText) {
198+
this.certifiedText = certifiedText;
199+
}
200+
}
201+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
2+
xmlns:core="https://schemas.opentest4j.org/reporting/core/0.1.0"
3+
targetNamespace="https://schemas.opentest4j.org/reporting/core/0.1.0"
4+
elementFormDefault="qualified">
5+
<xs:element name="infrastructure" type="core:Infrastructure"/>
6+
<xs:complexType name="Infrastructure">
7+
<xs:sequence>
8+
<xs:element name="hostName" minOccurs="0" type="xs:string"/>
9+
<xs:element name="userName" minOccurs="0" type="xs:string"/>
10+
<xs:element name="operatingSystem" minOccurs="0" type="xs:string"/>
11+
<xs:element name="cpuCores" minOccurs="0" type="xs:int"/>
12+
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
13+
</xs:sequence>
14+
</xs:complexType>
15+
<xs:complexType name="TestInfo">
16+
<xs:sequence>
17+
<xs:element name="metadata" minOccurs="0">
18+
<xs:complexType>
19+
<xs:sequence>
20+
<xs:element name="tags" minOccurs="0">
21+
<xs:complexType>
22+
<xs:sequence>
23+
<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
24+
</xs:sequence>
25+
</xs:complexType>
26+
</xs:element>
27+
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
28+
</xs:sequence>
29+
</xs:complexType>
30+
</xs:element>
31+
<xs:element name="sources" minOccurs="0">
32+
<xs:complexType>
33+
<xs:sequence>
34+
<xs:element name="directorySource" minOccurs="0" maxOccurs="unbounded">
35+
<xs:complexType>
36+
<xs:attribute name="path" type="xs:string" use="required"/>
37+
</xs:complexType>
38+
</xs:element>
39+
<xs:element name="fileSource" minOccurs="0" maxOccurs="unbounded">
40+
<xs:complexType>
41+
<xs:sequence>
42+
<xs:element name="filePosition" type="core:FilePosition" minOccurs="0"/>
43+
</xs:sequence>
44+
<xs:attribute name="path" type="xs:string" use="required"/>
45+
</xs:complexType>
46+
</xs:element>
47+
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
48+
</xs:sequence>
49+
</xs:complexType>
50+
</xs:element>
51+
<xs:element name="attachments" minOccurs="0">
52+
<xs:complexType>
53+
<xs:sequence>
54+
<xs:element name="data" minOccurs="0" maxOccurs="unbounded">
55+
<xs:complexType>
56+
<xs:sequence>
57+
<xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
58+
<xs:complexType>
59+
<xs:simpleContent>
60+
<xs:extension base="xs:string">
61+
<xs:attribute name="key" type="xs:string" use="required"/>
62+
</xs:extension>
63+
</xs:simpleContent>
64+
</xs:complexType>
65+
</xs:element>
66+
</xs:sequence>
67+
<xs:attribute name="time" type="xs:dateTime" use="required"/>
68+
</xs:complexType>
69+
</xs:element>
70+
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
71+
</xs:sequence>
72+
</xs:complexType>
73+
</xs:element>
74+
<xs:element name="result" minOccurs="0">
75+
<xs:complexType>
76+
<xs:sequence>
77+
<xs:element name="reason" type="xs:string" minOccurs="0"/>
78+
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
79+
</xs:sequence>
80+
<xs:attribute name="status" type="core:Status"/>
81+
</xs:complexType>
82+
</xs:element>
83+
</xs:sequence>
84+
</xs:complexType>
85+
<xs:simpleType name="Status">
86+
<xs:restriction base="xs:string">
87+
<xs:enumeration value="SUCCESSFUL"/>
88+
<xs:enumeration value="SKIPPED"/>
89+
<xs:enumeration value="ABORTED"/>
90+
<xs:enumeration value="FAILED"/>
91+
</xs:restriction>
92+
</xs:simpleType>
93+
<xs:complexType name="FilePosition">
94+
<xs:attribute name="line" type="xs:int" use="required"/>
95+
<xs:attribute name="column" type="xs:int"/>
96+
</xs:complexType>
97+
</xs:schema>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
2+
xmlns:core="https://schemas.opentest4j.org/reporting/core/0.1.0"
3+
xmlns:e="https://schemas.opentest4j.org/reporting/events/0.1.0"
4+
targetNamespace="https://schemas.opentest4j.org/reporting/events/0.1.0"
5+
elementFormDefault="qualified">
6+
<xs:import schemaLocation="core.xsd" namespace="https://schemas.opentest4j.org/reporting/core/0.1.0"/>
7+
<xs:element name="events">
8+
<xs:complexType>
9+
<xs:sequence>
10+
<xs:element ref="core:infrastructure" minOccurs="0"/>
11+
<xs:choice minOccurs="0" maxOccurs="unbounded">
12+
<xs:element name="started" type="e:Started"/>
13+
<xs:element name="reported" type="e:Event"/>
14+
<xs:element name="finished" type="e:Event"/>
15+
</xs:choice>
16+
</xs:sequence>
17+
</xs:complexType>
18+
</xs:element>
19+
<xs:complexType name="Event">
20+
<xs:complexContent>
21+
<xs:extension base="core:TestInfo">
22+
<xs:attribute name="id" type="xs:string" use="required"/>
23+
<xs:attribute name="time" type="xs:dateTime" use="required"/>
24+
</xs:extension>
25+
</xs:complexContent>
26+
</xs:complexType>
27+
<xs:complexType name="Started">
28+
<xs:complexContent>
29+
<xs:extension base="e:Event">
30+
<xs:attribute name="parentId" type="xs:string"/>
31+
<xs:attribute name="name" type="xs:string" use="required"/>
32+
</xs:extension>
33+
</xs:complexContent>
34+
</xs:complexType>
35+
</xs:schema>

0 commit comments

Comments
 (0)
Please sign in to comment.