This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git
The following commit(s) were added to refs/heads/master by this push:
new 6cc9c10d Fix resolved schema cache key collisions and validate cache
hits (#129)
6cc9c10d is described below
commit 6cc9c10db2d35adffe9328ce5d135e57d13b49b5
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Tue Aug 25 11:45:10 2026 +0100
Fix resolved schema cache key collisions and validate cache hits (#129)
---
.../apache/ws/commons/schema/SchemaBuilder.java | 28 +++++++++++++++---
.../ws/commons/schema/SchemaBuilderCacheTest.java | 34 ++++++++++++++++++++++
2 files changed, 58 insertions(+), 4 deletions(-)
diff --git
a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
index 65150643..92b366af 100644
---
a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
+++
b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
@@ -669,8 +669,12 @@ public class SchemaBuilder {
XmlSchema resolveXmlSchema(String targetNamespace, String schemaLocation,
String baseUri,
TargetNamespaceValidator validator) {
- if (getCachedSchema(targetNamespace, schemaLocation, baseUri) != null)
{
- return getCachedSchema(targetNamespace, schemaLocation, baseUri);
+ final XmlSchema cachedSchema = getCachedSchema(targetNamespace,
schemaLocation, baseUri);
+ if (cachedSchema != null) {
+ if (validator != null) {
+ validator.validate(cachedSchema);
+ }
+ return cachedSchema;
}
// use the entity resolver provided if the schema location is present
@@ -772,7 +776,7 @@ public class SchemaBuilder {
// only by a trailing slash. As it is now, we assume a single
// character difference
// means it's a schema that has yet to be resolved.
- String schemaKey = targetNamespace + schemaLocation + baseUri;
+ String schemaKey = getCacheKey(targetNamespace,
schemaLocation, baseUri);
SoftReference<XmlSchema> softref =
threadResolvedSchemas.get(schemaKey);
if (softref != null) {
resolvedSchema = softref.get();
@@ -782,6 +786,22 @@ public class SchemaBuilder {
return resolvedSchema;
}
+ private static String getCacheKey(String targetNamespace, String
schemaLocation, String baseUri) {
+ StringBuilder key = new StringBuilder();
+ appendCacheKeyComponent(key, targetNamespace);
+ appendCacheKeyComponent(key, schemaLocation);
+ appendCacheKeyComponent(key, baseUri);
+ return key.toString();
+ }
+
+ private static void appendCacheKeyComponent(StringBuilder key, String
component) {
+ if (component == null) {
+ key.append("-|");
+ } else {
+ key.append(component.length()).append('|').append(component);
+ }
+ }
+
private List<Node> getChildren(Element content) {
List<Node> result = new ArrayList<Node>();
for (Node n = content.getFirstChild(); n != null; n =
n.getNextSibling()) {
@@ -1893,7 +1913,7 @@ public class SchemaBuilder {
if (resolvedSchemas != null) {
Map<String, SoftReference<XmlSchema>> threadResolvedSchemas =
resolvedSchemas.get();
if (threadResolvedSchemas != null) {
- String schemaKey = targetNamespace + schemaLocation + baseUri;
+ String schemaKey = getCacheKey(targetNamespace,
schemaLocation, baseUri);
threadResolvedSchemas.put(schemaKey, new
SoftReference<XmlSchema>(readSchema));
}
}
diff --git
a/xmlschema-core/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java
b/xmlschema-core/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java
index 7bc06921..a4035b3b 100644
---
a/xmlschema-core/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java
+++
b/xmlschema-core/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java
@@ -19,12 +19,15 @@
package org.apache.ws.commons.schema;
+import java.io.StringReader;
import java.lang.ref.SoftReference;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.ws.commons.schema.resolver.URIResolver;
import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
import org.junit.Assert;
import org.junit.Ignore;
@@ -171,6 +174,37 @@ public class SchemaBuilderCacheTest extends Assert {
assertNull(getThreadResolvedSchemaHashtable());
}
+ @Test
+ public void testCacheKeySeparatesComponents() {
+ try {
+ SchemaBuilder.initCache();
+ XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
+ CountingResolver resolver = new CountingResolver();
+ schemaCollection.setSchemaResolver(resolver);
+ SchemaBuilder builder = new SchemaBuilder(schemaCollection, null);
+
+ XmlSchema first = builder.resolveXmlSchema("urn:test", "a", "bc",
null);
+ XmlSchema second = builder.resolveXmlSchema("urn:test", "ab", "c",
null);
+
+ assertNotSame(first, second);
+ assertEquals(2, resolver.resolveCount);
+ } finally {
+ resetResolvedSchemasHashtable();
+ }
+ }
+
+ private static final class CountingResolver implements URIResolver {
+ private int resolveCount;
+
+ public InputSource resolveEntity(String targetNamespace, String
schemaLocation, String baseUri) {
+ resolveCount++;
+ InputSource source = new InputSource(new StringReader(
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"
targetNamespace=\"urn:test\"/>"));
+ source.setSystemId("memory:" + schemaLocation);
+ return source;
+ }
+ }
+
/**
* Configure and start the test threads for the multi-threaded testing. The
* threads will perform various tests between themselves such as clearing