8253569: javax.xml.catalog.Catalog.matchURI() implementation should reset state variables
Reviewed-by: lancea, naoto
This commit is contained in:
parent
ec0897ab80
commit
eeca3a3155
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, 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
|
||||
@ -28,10 +28,8 @@ import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, 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
|
||||
@ -40,6 +40,9 @@ class GroupEntry extends BaseEntry {
|
||||
static final int ATTRIBUTE_DEFFER = 1;
|
||||
static final int ATTRIBUTE_RESOLUTION = 2;
|
||||
|
||||
//Indicates a continuous session, should not reset state
|
||||
boolean shouldKeepState = false;
|
||||
|
||||
//Unmodifiable features when the Catalog is created
|
||||
CatalogFeatures features;
|
||||
|
||||
@ -164,6 +167,16 @@ class GroupEntry extends BaseEntry {
|
||||
longestSuffixMatch = 0;
|
||||
systemEntrySearched = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of the Catalog instance, allowing it to be reused.
|
||||
*/
|
||||
private void resetOnStart() {
|
||||
if (this instanceof Catalog && !shouldKeepState) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a group entry.
|
||||
* @param catalog the catalog this GroupEntry belongs to
|
||||
@ -228,6 +241,7 @@ class GroupEntry extends BaseEntry {
|
||||
* @return a URI string if a mapping is found, or null otherwise.
|
||||
*/
|
||||
public String matchSystem(String systemId) {
|
||||
resetOnStart();
|
||||
systemEntrySearched = true;
|
||||
String match = null;
|
||||
for (BaseEntry entry : entries) {
|
||||
@ -296,6 +310,7 @@ class GroupEntry extends BaseEntry {
|
||||
* @return a URI string if a mapping is found, or null otherwise.
|
||||
*/
|
||||
public String matchPublic(String publicId) {
|
||||
resetOnStart();
|
||||
/*
|
||||
When both public and system identifiers are specified, and prefer is
|
||||
not public (that is, system), only system entry will be used.
|
||||
@ -326,6 +341,51 @@ class GroupEntry extends BaseEntry {
|
||||
return matchDelegate(CatalogEntryType.DELEGATEPUBLIC, publicId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find a matching entry in the catalog by publicId or systemId.
|
||||
*
|
||||
* <p>
|
||||
* The resolution follows the following rules determined by the prefer
|
||||
* setting:
|
||||
*
|
||||
* prefer "system": attempts to resolve with a system entry; attempts to
|
||||
* resolve with a public entry when only publicId is specified.
|
||||
*
|
||||
* prefer "public": attempts to resolve with a system entry; attempts to
|
||||
* resolve with a public entry if no matching system entry is found.
|
||||
*
|
||||
* If no match is found, continue searching uri entries.
|
||||
*
|
||||
* @param publicId The public identifier of the external entity being
|
||||
* referenced.
|
||||
*
|
||||
* @param systemId The system identifier of the external entity being
|
||||
* referenced.
|
||||
*
|
||||
* @return the resolved systemId if a match is found, null otherwise
|
||||
*/
|
||||
String resolve(String publicId, String systemId) {
|
||||
String resolvedSystemId = null;
|
||||
shouldKeepState = true;
|
||||
if (systemId != null) {
|
||||
/*
|
||||
If a system identifier is specified, it is used no matter how
|
||||
prefer is set.
|
||||
*/
|
||||
resolvedSystemId = matchSystem(systemId);
|
||||
}
|
||||
|
||||
if (resolvedSystemId == null && publicId != null) {
|
||||
resolvedSystemId = matchPublic(publicId);
|
||||
}
|
||||
|
||||
if (resolvedSystemId == null && systemId != null) {
|
||||
resolvedSystemId = matchURI(systemId);
|
||||
}
|
||||
shouldKeepState = false;
|
||||
return resolvedSystemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find a matching entry in the catalog by the uri element.
|
||||
*
|
||||
@ -340,6 +400,7 @@ class GroupEntry extends BaseEntry {
|
||||
* @return a URI string if a mapping is found, or null otherwise.
|
||||
*/
|
||||
public String matchURI(String uri) {
|
||||
resetOnStart();
|
||||
String match = null;
|
||||
for (BaseEntry entry : entries) {
|
||||
switch (entry.type) {
|
||||
@ -399,6 +460,7 @@ class GroupEntry extends BaseEntry {
|
||||
* @return the URI string if a mapping is found, or null otherwise.
|
||||
*/
|
||||
private String matchDelegate(CatalogEntryType type, String id) {
|
||||
resetOnStart();
|
||||
String match = null;
|
||||
int longestMatch = 0;
|
||||
URI catalogId = null;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, 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
|
||||
@ -74,25 +74,9 @@ class Util {
|
||||
* @return the resolved systemId if a match is found, null otherwise
|
||||
*/
|
||||
static String resolve(CatalogImpl catalog, String publicId, String systemId) {
|
||||
String resolvedSystemId = null;
|
||||
|
||||
//search the current catalog
|
||||
catalog.reset();
|
||||
if (systemId != null) {
|
||||
/*
|
||||
If a system identifier is specified, it is used no matter how
|
||||
prefer is set.
|
||||
*/
|
||||
resolvedSystemId = catalog.matchSystem(systemId);
|
||||
}
|
||||
|
||||
if (resolvedSystemId == null && publicId != null) {
|
||||
resolvedSystemId = catalog.matchPublic(publicId);
|
||||
}
|
||||
|
||||
if (resolvedSystemId == null && systemId != null) {
|
||||
resolvedSystemId = catalog.matchURI(systemId);
|
||||
}
|
||||
String resolvedSystemId = catalog.resolve(publicId, systemId);
|
||||
|
||||
//mark the catalog as having been searched before trying alternatives
|
||||
catalog.markAsSearched();
|
||||
|
126
test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogReuseTest.java
Normal file
126
test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogReuseTest.java
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 catalog;
|
||||
|
||||
import java.net.URI;
|
||||
import javax.xml.catalog.Catalog;
|
||||
import javax.xml.catalog.CatalogFeatures;
|
||||
import javax.xml.catalog.CatalogManager;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8253569
|
||||
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
|
||||
* @run testng catalog.CatalogReuseTest
|
||||
* @summary Verifies that a catalog can be reused.
|
||||
*/
|
||||
public class CatalogReuseTest extends CatalogSupportBase {
|
||||
static final CatalogFeatures FEATURES_STRICT = CatalogFeatures.builder().
|
||||
with(CatalogFeatures.Feature.RESOLVE, "strict").build();
|
||||
|
||||
/*
|
||||
DataProvider: reuses a catalog. The length of the URIs is in descending order.
|
||||
Data columns: catalog, uri, expected
|
||||
*/
|
||||
@DataProvider(name = "dataWithCatalogD")
|
||||
public Object[][] dataWithCatalogD() {
|
||||
Catalog c = getCatalog();
|
||||
return new Object[][]{
|
||||
{c, "http://entailments/example.org/A/B/derived.ttl", "derived/A/B/derived.ttl"},
|
||||
{c, "http://example.org/A/B.owl", "sources/A/B.owl"},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
DataProvider: reuses a catalog. The length of the URIs is in ascending order.
|
||||
Data columns: catalog, uri, expected
|
||||
*/
|
||||
@DataProvider(name = "dataWithCatalogA")
|
||||
public Object[][] dataWithCatalogA() {
|
||||
Catalog c = getCatalog();
|
||||
return new Object[][]{
|
||||
{c, "http://example.org/A/B.owl", "sources/A/B.owl"},
|
||||
{c, "http://entailments/example.org/A/B/derived.ttl", "derived/A/B/derived.ttl"},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
DataProvider: provides no catalog. A new catalog will be created for each test.
|
||||
Data columns: uri, expected
|
||||
*/
|
||||
@DataProvider(name = "dataWithoutCatalog")
|
||||
public Object[][] dataWithoutCatalog() {
|
||||
return new Object[][]{
|
||||
{"http://entailments/example.org/A/B/derived.ttl", "derived/A/B/derived.ttl"},
|
||||
{"http://example.org/A/B.owl", "sources/A/B.owl"},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializing fields
|
||||
*/
|
||||
@BeforeClass
|
||||
public void setUpClass() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that a Catalog object can be reused, that no state data are
|
||||
* in the way of a subsequent matching attempt.
|
||||
*/
|
||||
@Test(dataProvider = "dataWithCatalogD")
|
||||
public void testD(Catalog c, String uri, String expected) throws Exception {
|
||||
String m = c.matchURI(uri);
|
||||
Assert.assertTrue(m.endsWith(expected), "Expected: " + expected);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that a Catalog object can be reused.
|
||||
*/
|
||||
@Test(dataProvider = "dataWithCatalogA")
|
||||
public void testA(Catalog c, String uri, String expected) throws Exception {
|
||||
String m = c.matchURI(uri);
|
||||
Assert.assertTrue(m.endsWith(expected), "Expected: " + expected);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that a match is found in a newly created Catalog.
|
||||
*/
|
||||
@Test(dataProvider = "dataWithoutCatalog")
|
||||
public void testNew(String uri, String expected) throws Exception {
|
||||
Catalog c = getCatalog();
|
||||
String m = c.matchURI(uri);
|
||||
Assert.assertTrue(m.endsWith(expected), "Expected: " + expected);
|
||||
|
||||
}
|
||||
|
||||
private Catalog getCatalog() {
|
||||
String uri = "file://" + slash + filepath + "/catalogReuse.xml";
|
||||
Catalog c = CatalogManager.catalog(FEATURES_STRICT, uri != null? URI.create(uri) : null);
|
||||
return c;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?xml version='1.0'?>
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="public">
|
||||
<rewriteURI uriStartString="http://entailments/example.org/" rewritePrefix="derived/"/>
|
||||
<rewriteURI uriStartString="http://example.org/" rewritePrefix="sources/"/>
|
||||
</catalog>
|
Loading…
Reference in New Issue
Block a user