8323571: Regression in source resolution process
Reviewed-by: lancea, naoto
This commit is contained in:
parent
49e6121347
commit
e4389d8dc2
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
@ -94,7 +94,7 @@ import org.xml.sax.InputSource;
|
||||
* @author K.Venugopal SUN Microsystems
|
||||
* @author Neeraj Bajaj SUN Microsystems
|
||||
* @author Sunitha Reddy SUN Microsystems
|
||||
* @LastModified: Nov 2023
|
||||
* @LastModified: Jan 2024
|
||||
*/
|
||||
public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
|
||||
@ -1038,8 +1038,9 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
}
|
||||
|
||||
// Step 2: custom catalog if specified
|
||||
if ((publicId != null || literalSystemId != null) &&
|
||||
staxInputSource == null && (fUseCatalog && fCatalogFile != null)) {
|
||||
if (staxInputSource == null
|
||||
&& (publicId != null || literalSystemId != null)
|
||||
&& (fUseCatalog && fCatalogFile != null)) {
|
||||
if (fCatalogResolver == null) {
|
||||
fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve);
|
||||
fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
|
||||
@ -1049,8 +1050,9 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
}
|
||||
|
||||
// Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
|
||||
if ((publicId != null || literalSystemId != null) &&
|
||||
staxInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
|
||||
if (staxInputSource == null
|
||||
&& (publicId != null || literalSystemId != null)
|
||||
&& JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
|
||||
initJdkCatalogResolver();
|
||||
|
||||
staxInputSource = resolveWithCatalogStAX(fDefCR, JdkCatalog.JDKCATALOG, publicId, literalSystemId);
|
||||
@ -1061,9 +1063,9 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
// Note if both publicId and systemId are null, the resolution process continues as usual
|
||||
if (staxInputSource != null) {
|
||||
fISCreatedByResolver = true;
|
||||
} else if ((publicId == null && literalSystemId == null) ||
|
||||
(JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
|
||||
fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
|
||||
} else if ((publicId == null && literalSystemId == null)
|
||||
|| (JdkXmlUtils.isResolveContinue(fCatalogFeatures)
|
||||
&& fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
|
||||
staxInputSource = new StaxXMLInputSource(
|
||||
new XMLInputSource(publicId, literalSystemId, baseSystemId, true), false);
|
||||
}
|
||||
@ -1206,8 +1208,9 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
}
|
||||
|
||||
// Step 2: custom catalog if specified
|
||||
if ((publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null)
|
||||
&& xmlInputSource == null && (fUseCatalog && fCatalogFile != null)) {
|
||||
if (xmlInputSource == null
|
||||
&& (publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null)
|
||||
&& (fUseCatalog && fCatalogFile != null)) {
|
||||
if (fCatalogResolver == null) {
|
||||
fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve);
|
||||
fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
|
||||
@ -1217,8 +1220,9 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
}
|
||||
|
||||
// Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
|
||||
if ((publicId != null || literalSystemId != null)
|
||||
&& xmlInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
|
||||
if (xmlInputSource == null
|
||||
&& (publicId != null || literalSystemId != null)
|
||||
&& JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
|
||||
initJdkCatalogResolver();
|
||||
// unlike a custom catalog, the JDK Catalog only contains entity references
|
||||
xmlInputSource = resolveEntity(fDefCR, publicId, literalSystemId, baseSystemId);
|
||||
@ -1226,11 +1230,13 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
|
||||
|
||||
// Step 4: default resolution if not resolved by a resolver and the RESOLVE
|
||||
// feature is set to 'continue'
|
||||
// Note if both publicId and systemId are null, the resolution process continues as usual
|
||||
if ((publicId == null && literalSystemId == null) ||
|
||||
((xmlInputSource == null) && JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
|
||||
fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
|
||||
xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false);
|
||||
if (xmlInputSource == null) {
|
||||
// Note if both publicId and systemId are null, the resolution process continues as usual
|
||||
if ((publicId == null && literalSystemId == null) ||
|
||||
(JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
|
||||
fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
|
||||
xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false);
|
||||
}
|
||||
}
|
||||
|
||||
return xmlInputSource;
|
||||
|
201
test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java
Normal file
201
test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package common.catalog;
|
||||
|
||||
import org.w3c.dom.ls.LSInput;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.catalog.CatalogFeatures;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
|
||||
import static javax.xml.catalog.CatalogManager.catalogResolver;
|
||||
import javax.xml.catalog.CatalogResolver;
|
||||
import javax.xml.validation.Validator;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8323571
|
||||
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
|
||||
* @run testng common.catalog.NullIdTest
|
||||
* @summary Verifies null values are handled properly in the source resolution
|
||||
* process.
|
||||
*/
|
||||
public class NullIdTest {
|
||||
private static final Map<String, String> SCHEMAS;
|
||||
// Source Level JDK 8
|
||||
static {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("https://schemas.opentest4j.org/reporting/events/0.1.0", "events.xsd");
|
||||
map.put("https://schemas.opentest4j.org/reporting/core/0.1.0", "core.xsd");
|
||||
SCHEMAS = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the source resolution process recognizes the custom InputSource
|
||||
* correctly even though the public and system IDs are null.
|
||||
*/
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
String xml = "<events xmlns=\"https://schemas.opentest4j.org/reporting/events/0.1.0\"/>";
|
||||
validate(new StreamSource(new StringReader(xml)));
|
||||
System.out.println("Successfully validated");
|
||||
}
|
||||
|
||||
private static void validate(Source source) throws SAXException, IOException {
|
||||
SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI);
|
||||
Validator validator = schemaFactory.newSchema().newValidator();
|
||||
validator.setResourceResolver(createResourceResolver());
|
||||
validator.validate(source);
|
||||
}
|
||||
|
||||
private static LSResourceResolver createResourceResolver() {
|
||||
return (type, namespaceURI, publicId, systemId, baseURI) -> {
|
||||
if (namespaceURI != null) {
|
||||
if (SCHEMAS.containsKey(namespaceURI)) {
|
||||
CustomLSInputImpl input = new CustomLSInputImpl();
|
||||
input.setPublicId(publicId);
|
||||
String schema = SCHEMAS.get(namespaceURI);
|
||||
input.setSystemId(requireNonNull(NullIdTest.class.getResource(schema)).toExternalForm());
|
||||
input.setBaseURI(baseURI);
|
||||
InputStream stream = NullIdTest.class.getResourceAsStream(schema);
|
||||
input.setCharacterStream(new InputStreamReader(requireNonNull(stream)));
|
||||
return input;
|
||||
}
|
||||
}
|
||||
if (systemId != null) {
|
||||
CatalogFeatures features = CatalogFeatures.builder()
|
||||
.with(CatalogFeatures.Feature.RESOLVE, "continue")
|
||||
.build();
|
||||
CatalogResolver catalogResolver = catalogResolver(features);
|
||||
return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
static class CustomLSInputImpl implements LSInput {
|
||||
|
||||
private Reader characterStream;
|
||||
private InputStream byteStream;
|
||||
private String stringData;
|
||||
private String systemId;
|
||||
private String publicId;
|
||||
private String baseURI;
|
||||
private String encoding;
|
||||
private boolean certifiedText;
|
||||
|
||||
@Override
|
||||
public Reader getCharacterStream() {
|
||||
return characterStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(Reader characterStream) {
|
||||
this.characterStream = characterStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getByteStream() {
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setByteStream(InputStream byteStream) {
|
||||
this.byteStream = byteStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringData() {
|
||||
return stringData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStringData(String stringData) {
|
||||
this.stringData = stringData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystemId() {
|
||||
return systemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemId(String systemId) {
|
||||
this.systemId = systemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPublicId() {
|
||||
return publicId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicId(String publicId) {
|
||||
this.publicId = publicId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseURI() {
|
||||
return baseURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseURI(String baseURI) {
|
||||
this.baseURI = baseURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncoding(String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCertifiedText() {
|
||||
return certifiedText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCertifiedText(boolean certifiedText) {
|
||||
this.certifiedText = certifiedText;
|
||||
}
|
||||
}
|
||||
}
|
97
test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd
Normal file
97
test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd
Normal file
@ -0,0 +1,97 @@
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:core="https://schemas.opentest4j.org/reporting/core/0.1.0"
|
||||
targetNamespace="https://schemas.opentest4j.org/reporting/core/0.1.0"
|
||||
elementFormDefault="qualified">
|
||||
<xs:element name="infrastructure" type="core:Infrastructure"/>
|
||||
<xs:complexType name="Infrastructure">
|
||||
<xs:sequence>
|
||||
<xs:element name="hostName" minOccurs="0" type="xs:string"/>
|
||||
<xs:element name="userName" minOccurs="0" type="xs:string"/>
|
||||
<xs:element name="operatingSystem" minOccurs="0" type="xs:string"/>
|
||||
<xs:element name="cpuCores" minOccurs="0" type="xs:int"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TestInfo">
|
||||
<xs:sequence>
|
||||
<xs:element name="metadata" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="tags" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="sources" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="directorySource" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="path" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="fileSource" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="filePosition" type="core:FilePosition" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="path" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="attachments" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="data" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="key" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="time" type="xs:dateTime" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="result" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="reason" type="xs:string" minOccurs="0"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="status" type="core:Status"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Status">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SUCCESSFUL"/>
|
||||
<xs:enumeration value="SKIPPED"/>
|
||||
<xs:enumeration value="ABORTED"/>
|
||||
<xs:enumeration value="FAILED"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="FilePosition">
|
||||
<xs:attribute name="line" type="xs:int" use="required"/>
|
||||
<xs:attribute name="column" type="xs:int"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
35
test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd
Normal file
35
test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd
Normal file
@ -0,0 +1,35 @@
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:core="https://schemas.opentest4j.org/reporting/core/0.1.0"
|
||||
xmlns:e="https://schemas.opentest4j.org/reporting/events/0.1.0"
|
||||
targetNamespace="https://schemas.opentest4j.org/reporting/events/0.1.0"
|
||||
elementFormDefault="qualified">
|
||||
<xs:import schemaLocation="core.xsd" namespace="https://schemas.opentest4j.org/reporting/core/0.1.0"/>
|
||||
<xs:element name="events">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="core:infrastructure" minOccurs="0"/>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="started" type="e:Started"/>
|
||||
<xs:element name="reported" type="e:Event"/>
|
||||
<xs:element name="finished" type="e:Event"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="Event">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="core:TestInfo">
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
<xs:attribute name="time" type="xs:dateTime" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Started">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="e:Event">
|
||||
<xs:attribute name="parentId" type="xs:string"/>
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
Loading…
Reference in New Issue
Block a user