Skip to content

Commit

Permalink
Refactor to remove ThreadLocal usage (#896)
Browse files Browse the repository at this point in the history
* Refactor to remove threadlocal usage

* Remove option for resetting the context as context reuse is explicit
  • Loading branch information
justin-tay authored Dec 7, 2023
1 parent 2971b79 commit b33561f
Show file tree
Hide file tree
Showing 73 changed files with 534 additions and 552 deletions.
8 changes: 4 additions & 4 deletions src/main/java/com/networknt/schema/AbstractJsonValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@

public abstract class AbstractJsonValidator implements JsonValidator {

public Set<ValidationMessage> validate(JsonNode node) {
return validate(node, node, PathType.LEGACY.getRoot());
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node) {
return validate(executionContext, node, node, PathType.LEGACY.getRoot());
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
Set<ValidationMessage> validationMessages = Collections.emptySet();
if (shouldValidateSchema) {
validationMessages = validate(node, rootNode, at);
validationMessages = validate(executionContext, node, rootNode, at);
}
return validationMessages;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ public AdditionalPropertiesValidator(String schemaPath, JsonNode schemaNode, Jso
parseErrorCode(getValidatorType().getErrorCodeKey());
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);
CollectorContext collectorContext = CollectorContext.getInstance();
CollectorContext collectorContext = executionContext.getCollectorContext();

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
if (!node.isObject()) {
Expand Down Expand Up @@ -102,9 +102,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
if (additionalPropertiesSchema != null) {
ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY);
if (state != null && state.isWalkEnabled()) {
errors.addAll(additionalPropertiesSchema.walk(node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled()));
errors.addAll(additionalPropertiesSchema.walk(executionContext, node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled()));
} else {
errors.addAll(additionalPropertiesSchema.validate(node.get(pname), rootNode, atPath(at, pname)));
errors.addAll(additionalPropertiesSchema.validate(executionContext, node.get(pname), rootNode, atPath(at, pname)));
}
}
}
Expand All @@ -114,9 +114,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(node, rootNode, at);
return validate(executionContext, node, rootNode, at);
}

if (node == null || !node.isObject()) {
Expand All @@ -142,9 +142,9 @@ public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at,
if (!allowedProperties.contains(pname) && !handledByPatternProperties) {
if (allowAdditionalProperties) {
if (additionalPropertiesSchema != null) {
ValidatorState state = (ValidatorState) CollectorContext.getInstance().get(ValidatorState.VALIDATOR_STATE_KEY);
ValidatorState state = (ValidatorState) executionContext.getCollectorContext().get(ValidatorState.VALIDATOR_STATE_KEY);
if (state != null && state.isWalkEnabled()) {
additionalPropertiesSchema.walk(node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled());
additionalPropertiesSchema.walk(executionContext, node.get(pname), rootNode, atPath(at, pname), state.isValidationEnabled());
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/com/networknt/schema/AllOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public AllOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
}

@Override
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);
CollectorContext collectorContext = CollectorContext.getInstance();
CollectorContext collectorContext = executionContext.getCollectorContext();

// get the Validator state object storing validation data
ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY);
Expand All @@ -55,9 +55,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
Scope parentScope = collectorContext.enterDynamicScope();
try {
if (!state.isWalkEnabled()) {
localErrors = schema.validate(node, rootNode, at);
localErrors = schema.validate(executionContext, node, rootNode, at);
} else {
localErrors = schema.walk(node, rootNode, at, true);
localErrors = schema.walk(executionContext, node, rootNode, at, true);
}

childSchemaErrors.addAll(localErrors);
Expand Down Expand Up @@ -105,13 +105,13 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(node, rootNode, at);
return validate(executionContext, node, rootNode, at);
}
for (JsonSchema schema : this.schemas) {
// Walk through the schema
schema.walk(node, rootNode, at, false);
schema.walk(executionContext, node, rootNode, at, false);
}
return Collections.emptySet();
}
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/com/networknt/schema/AnyOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
}

@Override
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);
CollectorContext collectorContext = CollectorContext.getInstance();
CollectorContext collectorContext = executionContext.getCollectorContext();

// get the Validator state object storing validation data
ValidatorState state = (ValidatorState) collectorContext.get(ValidatorState.VALIDATOR_STATE_KEY);
Expand Down Expand Up @@ -82,9 +82,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}
}
if (!state.isWalkEnabled()) {
errors = schema.validate(node, rootNode, at);
errors = schema.validate(executionContext, node, rootNode, at);
} else {
errors = schema.walk(node, rootNode, at, true);
errors = schema.walk(executionContext, node, rootNode, at, true);
}

// check if any validation errors have occurred
Expand Down Expand Up @@ -151,12 +151,12 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(node, rootNode, at);
return validate(executionContext, node, rootNode, at);
}
for (JsonSchema schema : this.schemas) {
schema.walk(node, rootNode, at, false);
schema.walk(executionContext, node, rootNode, at, false);
}
return new LinkedHashSet<>();
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/networknt/schema/BaseJsonValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ protected JsonSchema fetchSubSchemaNode(ValidationContext validationContext) {
}

@Override
public Set<ValidationMessage> validate(JsonNode node) {
return validate(node, node, atRoot());
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node) {
return validate(executionContext, node, node, atRoot());
}

protected String getNodeFieldType() {
Expand Down
20 changes: 0 additions & 20 deletions src/main/java/com/networknt/schema/CollectorContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,6 @@
* implementations.
*/
public class CollectorContext {

// Using a namespace string as key in ThreadLocal so that it is unique in
// ThreadLocal.
static final String COLLECTOR_CONTEXT_THREAD_LOCAL_KEY = "com.networknt.schema.CollectorKey";

// Get an instance from thread info (which uses ThreadLocal).
public static CollectorContext getInstance() {
return (CollectorContext) ThreadInfo.get(COLLECTOR_CONTEXT_THREAD_LOCAL_KEY);
}

/**
* Map for holding the name and {@link Collector} or a simple Object.
*/
Expand Down Expand Up @@ -212,16 +202,6 @@ public void combineWithCollector(String name, Object data) {
}
}

/**
* Reset the context
*/
public void reset() {
this.collectorMap = new HashMap<>();
this.collectorLoadMap = new HashMap<>();
this.dynamicScopes.clear();
this.dynamicScopes.push(newTopScope());
}

/**
* Loads data from all collectors.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/ConstValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public ConstValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
this.schemaNode = schemaNode;
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/networknt/schema/ContainsValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ public ContainsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare
}

@Override
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

// ignores non-arrays
if (null != this.schema && node.isArray()) {
Collection<String> evaluatedItems = CollectorContext.getInstance().getEvaluatedItems();
Collection<String> evaluatedItems = executionContext.getCollectorContext().getEvaluatedItems();

int actual = 0, i = 0;
for (JsonNode n : node) {
String path = atPath(at, i);

if (this.schema.validate(n, rootNode, path).isEmpty()) {
if (this.schema.validate(executionContext, n, rootNode, path).isEmpty()) {
++actual;
evaluatedItems.add(path);
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/networknt/schema/DependenciesValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public DependenciesValidator(String schemaPath, JsonNode schemaNode, JsonSchema
parseErrorCode(getValidatorType().getErrorCodeKey());
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand All @@ -68,7 +68,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}
JsonSchema schema = schemaDeps.get(pname);
if (schema != null) {
errors.addAll(schema.validate(node, rootNode, at));
errors.addAll(schema.validate(executionContext, node, rootNode, at));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/DependentRequired.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public DependentRequired(String schemaPath, JsonNode schemaNode, JsonSchema pare
parseErrorCode(getValidatorType().getErrorCodeKey());
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/com/networknt/schema/DependentSchemas.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public DependentSchemas(String schemaPath, JsonNode schemaNode, JsonSchema paren
}

@Override
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

Set<ValidationMessage> errors = new LinkedHashSet<>();
Expand All @@ -51,7 +51,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
String pname = it.next();
JsonSchema schema = this.schemaDependencies.get(pname);
if (schema != null) {
errors.addAll(schema.validate(node, rootNode, at));
errors.addAll(schema.validate(executionContext, node, rootNode, at));
}
}

Expand All @@ -64,12 +64,12 @@ public void preloadJsonSchema() {
}

@Override
public Set<ValidationMessage> walk(JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at, boolean shouldValidateSchema) {
if (shouldValidateSchema) {
return validate(node, rootNode, at);
return validate(executionContext, node, rootNode, at);
}
for (JsonSchema schema : this.schemaDependencies.values()) {
schema.walk(node, rootNode, at, false);
schema.walk(executionContext, node, rootNode, at, false);
}
return Collections.emptySet();
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/EnumValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public EnumValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSc
parseErrorCode(getValidatorType().getErrorCodeKey());
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public String thresholdValue() {
}
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

if (!JsonNodeUtil.isNumber(node, validationContext.getConfig())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public String thresholdValue() {
}
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) {
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/com/networknt/schema/ExecutionContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.networknt.schema;

/**
* Stores the execution context for the validation run.
*/
public class ExecutionContext {
private CollectorContext collectorContext;

public ExecutionContext() {
this(new CollectorContext());
}

public ExecutionContext(CollectorContext collectorContext) {
this.collectorContext = collectorContext;
}

public CollectorContext getCollectorContext() {
return collectorContext;
}

public void setCollectorContext(CollectorContext collectorContext) {
this.collectorContext = collectorContext;
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/FalseValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public FalseValidator(String schemaPath, final JsonNode schemaNode, JsonSchema p
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.FALSE, validationContext);
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);
// For the false validator, it is always not valid
Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/Format.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface Format {
*/
String getName();

boolean matches(String value);
boolean matches(ExecutionContext executionContext, String value);

String getErrorMessageDescription();
}
4 changes: 2 additions & 2 deletions src/main/java/com/networknt/schema/FormatValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public FormatValidator(String schemaPath, JsonNode schemaNode, JsonSchema parent
parseErrorCode(getValidatorType().getErrorCodeKey());
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, String at) {
debug(logger, node, rootNode, at);

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();
Expand All @@ -58,7 +58,7 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}
}
try {
if (!format.matches(node.textValue())) {
if (!format.matches(executionContext, node.textValue())) {
errors.add(buildValidationMessage(at, format.getName(), format.getErrorMessageDescription()));
}
} catch (PatternSyntaxException pse) {
Expand Down
Loading

0 comments on commit b33561f

Please sign in to comment.