Commit 7aa1bf15 authored by ethiraj krishnamanaidu's avatar ethiraj krishnamanaidu
Browse files

Merge branch 'schema-validation-slb' into 'master'

Schema validation changes

See merge request !109
parents 77601685 612b6bb2
Pipeline #49720 failed with stages
in 54 minutes and 27 seconds
......@@ -714,6 +714,8 @@ CDDL-1.1
========================================================================
The following software have components provided under the terms of this license:
- JSR 353 (JSON Processing) API (from http://json-processing-spec.java.net)
- JSR 353 (JSON Processing) Default Provider (from http://jsonp.java.net)
- JavaBeans Activation Framework (from )
- JavaBeans(TM) Activation Framework (from http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
- tomcat-embed-core (from http://tomcat.apache.org/)
......@@ -788,6 +790,8 @@ GPL-2.0-only
The following software have components provided under the terms of this license:
- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
- JSR 353 (JSON Processing) API (from http://json-processing-spec.java.net)
- JSR 353 (JSON Processing) Default Provider (from http://jsonp.java.net)
- JavaBeans Activation Framework (from )
- JavaMail API (from )
- jakarta.annotation-api (from https://projects.eclipse.org/projects/ee4j.ca)
......@@ -802,6 +806,8 @@ The following software have components provided under the terms of this license:
- Checker Qual (from https://checkerframework.org)
- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
- Google Guice - Core Library (from )
- JSR 353 (JSON Processing) API (from http://json-processing-spec.java.net)
- JSR 353 (JSON Processing) Default Provider (from http://jsonp.java.net)
- JavaBeans Activation Framework (from )
- JavaMail API (from )
- jakarta.annotation-api (from https://projects.eclipse.org/projects/ee4j.ca)
......@@ -989,4 +995,3 @@ The following software have components provided under the terms of this license:
- JavaMail API (from )
- Spongy Castle (from http://rtyley.github.io/spongycastle/)
......@@ -4,6 +4,7 @@
- [Concepts](#concepts)
- [How to use this service?](#using_this_service)
- [Current limitation](#limitation)
- [Schema Validation](#schema-validation)
## Introduction <a name="introduction"></a>
......@@ -245,4 +246,69 @@ The following parameters are required to create a schema:
| schema | Schema definition | JSON object. Please refer example above. | Object | No |
## Schema Validation <a name="schema-validation"></a>
Schema service does multiple checks on different levels to make sure the inserted schema fits into validations on major, minor and patch version levels.
Following is the list of all validations that is performed while creating/updating any schema into the system.
Schema version constitutes three parts, MAJOR, MINOR, and PATCH. Depending upon the nature of changes done to the structure of schema, the application may force the user to update the version number. At a high level, the upgrading versions would be required when:
* PATCH version when you make backwards compatible bug fixes or documentation/decoration changes
* MINOR version when you add functionality or contents in a backwards compatible manner, and
* MAJOR version when you make incompatible schema changes. e.g.Whenever an attribute is removed or `type` of an attribute is updated
##### Permitted Changes for PATCH Version Increments:
Changes in the values of following attributes is permitted at patch version increment. They are non-mandatory attributes so addition or removal of any of these attributes is permitted.
* title
* description
* example/examples
* pattern
* $id
* $comment
* any JSON extension tag starting with x-osdu
##### Permitted Changes for MINOR Version Increments:
In addition to all permitted changes in PATCH versions, the following actions are permitted:
1. Adding properties to existing data and nested structures
2. Adding object structures to below arrays:
* [allOf](https://json-schema.org/understanding-json-schema/reference/combining.html#allof) : To validate against allOf, the given data must be valid against all of the given subschemas
* [oneOf](https://json-schema.org/understanding-json-schema/reference/combining.html#oneof) : To validate against oneOf, the given data must be valid against exactly one of the given subschemas
* [anyOf](https://json-schema.org/understanding-json-schema/reference/combining.html#anyof) : To validate against anyOf, the given data must be valid against any (one or more) of the given subschemas
3. Changing the indices of objects containing title inside oneof or allof arrays
4. Changing indices of ref attributes keeping same text values
5. Changing the order of required attribute
Explicitly not permitted is changing
1. The list of [required](https://json-schema.org/understanding-json-schema/reference/object.html#required-properties) properties
2. The state of [additionalProperties](https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties)
* If `additionalProperties` is not present in original schema then it cannot be added with value as false
* If `additionalProperties` is present with value equal to false then cannot be removed/altered
* Value of `additionalProperties` cannot be changed from true to false
3. Changing type of any attribute
It is permitted to declare existing properties as deprecated, preferable with instructions how to migrate from the previous to the next version. The documentation will automatically mark properties with strike-through if the description starts with "DEPRECATED: " .
##### Permitted Changes for MAJOR Version Increments:
Any changes are permitted, specifically
1. Removal of properties
2. Removal of structures in allOf, oneOf, anyOf
3. Changing the list of required properties
4. Changing the state of additionalProperties
5. Changing the indices of attributes without title in oneof and allof arrays
6. Changing type of any attribute
7. Breaking change introduced in external schema of `ref` attribute
Following table gives you error message when breaking change is introduced at any level:
##### Error codes along with message
| Error Code | Condition | Error Message |
|------------|----------------|---------------|
| 400 | When breaking change not allowed at patch versionlevel |Patch version validation failed. Changes requiring a minor or major version increment were found; analysed version: 2.2.15 and 2.2.14. Updating the schema version to a higher minor or major version is required.|
| 400 | When breaking change not allowed at minor version level | Minor version validation failed. Breaking changes were found; analysed versions 1013.2.0 and 1013.1.0. Updating the schema version to a higher major version is required.|
Note: The above array message would contain given schema version and existing schema in the system
......@@ -121,7 +121,16 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<build>
......
......@@ -17,6 +17,10 @@ public class SchemaConstants {
// authority
public static final String AUTHORITY_KIND = "authority";
//Delimeters
public static final String SCHEMA_KIND_DELIMITER = ":";
public static final String SCHEMA_Version_DELIMITER = ".";
// schema
public static final String SCHEMA_KIND = "schema";
public static final String AUTHORITY = "authority";
......@@ -31,6 +35,8 @@ public class SchemaConstants {
public static final String SCHEMA = "schema";
public static final String SCOPE = "scope";
public static final String STATUS = "status";
public static final String XOSDU_TAG = "x-osdu";
public static final String TITLE_TAG = "title";
// general
public static final String ALREADY_EXISTS = "ALREADY_EXISTS";
......@@ -103,6 +109,8 @@ public class SchemaConstants {
public static final String SCHEMA_ID_EXISTS = "Schema Id is already present";
public static final String INVALID_UPDATE_OPERATION = "Update/Create failed because schema id is present in another tenant";
public static final String UNAUTHORIZED_EXCEPTION = "User is unauthorized to perform this action";
public static final String BREAKING_CHANGES_PATCH = "Patch version validation failed. Changes requiring a minor or major version increment were found; analysed version: {0} and {1}. Updating the schema version to a higher minor or major version is required.";
public static final String BREAKING_CHANGES_MINOR = "Minor version validation failed. Breaking changes were found; analysed versions {0} and {1}. Updating the schema version to a higher major version is required.";
// OSDU
public static final String DATA_PARTITION_ID = "data-partition-id";
......@@ -115,4 +123,45 @@ public class SchemaConstants {
public final static String SCHEMA_CREATE_EVENT_TYPE = "create";
public final static String SCHEMA_UPDATE_EVENT_TYPE = "update";
public final static String KIND = "kind";
//Schema Validation Constants
public static enum SkipTags
{
TITLE("title"),
DESCRIPTION("description"),
EXAMPLES("examples"),
EXAMPLE("example"),
PATTERN("pattern"),
ID("$id"),
COMMENT("$comment");
private final String value;
private SkipTags(String value)
{
this.value = value;
}
public String getValue()
{
return this.value;
}
}
//Schema Composition Tags
public static enum CompositionTags
{
ALL_OF("allOf"),
ONE_OF("oneOf"),
ANY_OF("anyOf");
private final String value;
private CompositionTags(String value)
{
this.value = value;
}
public String getValue()
{
return this.value;
}
}
}
package org.opengroup.osdu.schema.exceptions;
import org.springframework.http.HttpStatus;
public class SchemaVersionException extends BadRequestException{
private final HttpStatus status;
private final String errorMsg;
private static final long serialVersionUID = 5234324334634627L;
public SchemaVersionException(HttpStatus status, String errorMsg, Throwable throwable) {
super(errorMsg, throwable);
this.errorMsg = errorMsg;
this.status = status;
}
public SchemaVersionException(HttpStatus status, String errorMsg) {
this(status, errorMsg, null);
}
public SchemaVersionException(String errorMsg, Throwable throwable) {
this(HttpStatus.BAD_REQUEST, errorMsg, throwable);
}
public SchemaVersionException(String errorMsg) {
this(HttpStatus.BAD_REQUEST, errorMsg, null);
}
public SchemaVersionException(Throwable throwable) {
this(HttpStatus.BAD_REQUEST.toString(), throwable);
}
public SchemaVersionException() {
this(HttpStatus.BAD_REQUEST.toString());
}
}
......@@ -3,7 +3,7 @@ package org.opengroup.osdu.schema.model;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.opengroup.osdu.schema.validation.SchemaConstraint;
import org.opengroup.osdu.schema.validation.SchemaRequestConstraint;
import lombok.AllArgsConstructor;
import lombok.Builder;
......@@ -21,7 +21,7 @@ public class SchemaRequest {
private SchemaInfo schemaInfo;
@NotNull(message = "schema must not be null")
@SchemaConstraint
@SchemaRequestConstraint
private Object schema;
}
......@@ -21,6 +21,7 @@ import org.opengroup.osdu.schema.exceptions.ApplicationException;
import org.opengroup.osdu.schema.exceptions.BadRequestException;
import org.opengroup.osdu.schema.exceptions.NoSchemaFoundException;
import org.opengroup.osdu.schema.exceptions.NotFoundException;
import org.opengroup.osdu.schema.exceptions.SchemaVersionException;
import org.opengroup.osdu.schema.logging.AuditLogger;
import org.opengroup.osdu.schema.model.QueryParams;
import org.opengroup.osdu.schema.model.SchemaIdentity;
......@@ -35,12 +36,16 @@ import org.opengroup.osdu.schema.service.IAuthorityService;
import org.opengroup.osdu.schema.service.IEntityTypeService;
import org.opengroup.osdu.schema.service.ISchemaService;
import org.opengroup.osdu.schema.service.ISourceService;
import org.opengroup.osdu.schema.util.SchemaComparatorByVersion;
import org.opengroup.osdu.schema.util.SchemaResolver;
import org.opengroup.osdu.schema.util.SchemaUtil;
import org.opengroup.osdu.schema.validation.SchemaVersionValidatorFactory;
import org.opengroup.osdu.schema.validation.SchemaVersionValidatorType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
......@@ -71,6 +76,8 @@ public class SchemaService implements ISchemaService {
private SchemaResolver schemaResolver;
private final SchemaVersionValidatorFactory versionValidatorFactory;
@Value("${shared.tenant.name:common}")
private String sharedTenant;
......@@ -131,13 +138,7 @@ public class SchemaService implements ISchemaService {
if (schemaInfoStore.isUnique(schemaId, dataPartitionId)) {
setScope(schemaRequest, dataPartitionId);
String latestMinorSchema = schemaInfoStore.getLatestMinorVerSchema(schemaRequest.getSchemaInfo());
Gson gson = new Gson();
if (StringUtils.isNotEmpty(latestMinorSchema)) {
schemaUtil.checkBreakingChange(gson.toJson(schemaRequest.getSchema()), latestMinorSchema);
}
String schema = schemaResolver.resolveSchema(gson.toJson(schemaRequest.getSchema()));
String schema = resolveAndCheckBreakingChanges(schemaRequest);
Boolean authority = authorityService.checkAndRegisterAuthorityIfNotPresent(
schemaRequest.getSchemaInfo().getSchemaIdentity().getAuthority());
......@@ -205,8 +206,7 @@ public class SchemaService implements ISchemaService {
if (SchemaStatus.DEVELOPMENT.equals(schemaInfo.getStatus())) {
log.info(MessageFormat.format(SchemaConstants.SCHEMA_UPDATION_STARTED, createdSchemaId));
setScope(schemaRequest, dataPartitionId);
Gson gson = new Gson();
String schema = schemaResolver.resolveSchema(gson.toJson(schemaRequest.getSchema()));
String schema = resolveAndCheckBreakingChanges(schemaRequest);
SchemaInfo schInfo = schemaInfoStore.updateSchemaInfo(schemaRequest);
auditLogger.schemaUpdatedSuccess(Collections.singletonList(schemaRequest.toString()));
schemaStore.createSchema(schemaRequest.getSchemaInfo().getSchemaIdentity().getId(), schema);
......@@ -236,6 +236,15 @@ public class SchemaService implements ISchemaService {
return schemaId;
}
private String resolveAndCheckBreakingChanges(SchemaRequest schemaRequest) throws ApplicationException, BadRequestException {
Gson gson = new Gson();
String schemaInRequestPayload = gson.toJson(schemaRequest.getSchema());
String fullyResolvedInputSchema = schemaResolver.resolveSchema(schemaInRequestPayload);
compareFullyResolvedSchema(schemaRequest.getSchemaInfo(), fullyResolvedInputSchema);
return fullyResolvedInputSchema;
}
@Override
public SchemaInfoResponse getSchemaInfoList(QueryParams queryParams)
throws BadRequestException, ApplicationException {
......@@ -343,6 +352,7 @@ public class SchemaService implements ISchemaService {
List<SchemaInfo> latestSchemaList = new ArrayList<>();
Map<String, SchemaInfo> latestSchemaMap = new HashMap<>();
SchemaComparatorByVersion schemaComparatorByVersion = new SchemaComparatorByVersion();
for(SchemaInfo schemaInfo :filteredSchemaList) {
......@@ -351,7 +361,7 @@ public class SchemaService implements ISchemaService {
SchemaInfo value = latestSchemaMap.get(key);
if(compareSchemaVersion(schemaInfo, value) >= 0)
if(schemaComparatorByVersion.compare(schemaInfo, value) >= 0)
latestSchemaMap.put(key, schemaInfo);
}
......@@ -373,28 +383,45 @@ public class SchemaService implements ISchemaService {
schemaInfo.getSchemaIdentity().getEntityType());
}
/****
* This method compares the schema versions of two SchemaInfo attribute. The comparison is done based on the following order <br>
* 1. Major Version <br>
* 2. Minor Version <br>
* 3. Patch Version <br>
*
* @param scInfo1 SchemaInfo version
* @param scInfo2 SchemaInfo
* @return Returns positive integer if version of scInfo1 is greater than version of scInfo2
*/
private int compareSchemaVersion(SchemaInfo scInfo1, SchemaInfo scInfo2){
private void compareFullyResolvedSchema(SchemaInfo inputSchemaInfo, String resolvedInputSchema) throws BadRequestException, ApplicationException {
try {
SchemaInfo[] schemaInfoToCompareWith = schemaUtil.findSchemaToCompare(inputSchemaInfo);
for(SchemaInfo existingSchemaInfo : schemaInfoToCompareWith) {
if(null == existingSchemaInfo)
continue;
Comparator<SchemaInfo> compareByMajor =
(s1,s2) -> s1.getSchemaIdentity().getSchemaVersionMajor().compareTo(s2.getSchemaIdentity().getSchemaVersionMajor());
String existingSchemaInStore = getSchema(existingSchemaInfo.getSchemaIdentity().getId()).toString();
try {
//Compare Major version of the schemas are different
if(inputSchemaInfo.getSchemaIdentity().getSchemaVersionMajor().compareTo(existingSchemaInfo.getSchemaIdentity().getSchemaVersionMajor()) != 0) {
continue;
//Compare Minor version is greater or smaller
}else if(inputSchemaInfo.getSchemaIdentity().getSchemaVersionMinor().compareTo(existingSchemaInfo.getSchemaIdentity().getSchemaVersionMinor()) < 0){
versionValidatorFactory.getSchemaVersionValidator(SchemaVersionValidatorType.MINOR).validate(resolvedInputSchema, existingSchemaInStore);
}else if(inputSchemaInfo.getSchemaIdentity().getSchemaVersionMinor().compareTo(existingSchemaInfo.getSchemaIdentity().getSchemaVersionMinor()) > 0) {
versionValidatorFactory.getSchemaVersionValidator(SchemaVersionValidatorType.MINOR).validate(existingSchemaInStore, resolvedInputSchema);
}else {
versionValidatorFactory.getSchemaVersionValidator(SchemaVersionValidatorType.PATCH).validate(existingSchemaInStore, resolvedInputSchema);
}
}catch (SchemaVersionException exc) {
log.error("Failed to resolve the schema and find breaking changes. Reason :" + exc.getMessage());
Comparator<SchemaInfo> compareByMinor =
(s1,s2) -> s1.getSchemaIdentity().getSchemaVersionMinor().compareTo(s2.getSchemaIdentity().getSchemaVersionMinor());
String message = MessageFormat.format(exc.getMessage(), StringUtils.substringAfterLast(inputSchemaInfo.getSchemaIdentity().getId(), SchemaConstants.SCHEMA_KIND_DELIMITER),
StringUtils.substringAfterLast(existingSchemaInfo.getSchemaIdentity().getId(), SchemaConstants.SCHEMA_KIND_DELIMITER));
throw new BadRequestException(message);
}
}
Comparator<SchemaInfo> compareByPatch =
(s1,s2) -> s1.getSchemaIdentity().getSchemaVersionPatch().compareTo(s2.getSchemaIdentity().getSchemaVersionPatch());
} catch ( NotFoundException e) {
throw new ApplicationException("Schema not found to evaluate breaking changes.");
}catch (JSONException exc) {
log.error("Failed to resolve the schema and find breaking changes. Reason :"+exc.getMessage());
throw new BadRequestException("Bad Input, invalid json");
}
return compareByMajor.thenComparing(compareByMinor).thenComparing(compareByPatch).compare(scInfo1, scInfo2);
}
}
\ No newline at end of file
package org.opengroup.osdu.schema.util;
import java.io.StringReader;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonPatch;
import javax.json.JsonPointer;
import javax.json.JsonReader;
import javax.json.JsonStructure;
import javax.json.JsonValue;
import org.opengroup.osdu.schema.constants.SchemaConstants;
import org.opengroup.osdu.schema.constants.SchemaConstants.CompositionTags;
import org.opengroup.osdu.schema.constants.SchemaConstants.SkipTags;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class JSONUtil {
private EnumSet<SkipTags> skipTags = EnumSet.allOf(SkipTags.class);
private EnumSet<CompositionTags> compositionTags = EnumSet.allOf(CompositionTags.class);
public String getCleanJSON(String inputJSON) throws JsonMappingException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(inputJSON);
clean(root, "");
return root.toString();
}
private boolean checkIfParentIsCompositionTag(String path) {
String [] tags = path.split("/");
if(tags.length < 3)
return false;
boolean isCompositionTag = compositionTags.stream().anyMatch(tag -> tag.getValue().equals(tags[tags.length-2]));
return isCompositionTag;
}
public JsonPatch findJSONDiff(JsonValue source, JsonValue target) {
JsonPatch diff = Json.createDiff(source.asJsonObject(), target.asJsonObject());
return diff;
}
public JsonArray getJsonArrayFromGivenPath(String jsonString, String rootPath) {
JsonReader reader = Json.createReader(new StringReader(jsonString));
JsonStructure jsonStruct = reader.read();
JsonPointer jp = Json.createPointer(rootPath);
JsonValue oldJsonVal = jp.getValue(jsonStruct);
return oldJsonVal.asJsonArray();
}
private void clean(JsonNode node, String path) {
if (node.isObject()) {
ObjectNode object = (ObjectNode) node;
Iterator<Entry<String, JsonNode>> itr = object.fields();
while(itr.hasNext()) {
Entry<String, JsonNode> entry = itr.next();
String key = entry.getKey();
if(skipTags.stream().anyMatch(tag -> tag.getValue().equals(key))
|| entry.getKey().startsWith(SchemaConstants.XOSDU_TAG)) {
//Don't delete the title tag of elements inside composition tag
//This will be utilized later for comparision
if(SchemaConstants.TITLE_TAG.equals(key)
&& checkIfParentIsCompositionTag(path)){
continue;
}
itr.remove();
}
clean(entry.getValue(), path + "/" + entry.getKey());
}
} else if (node.isArray()) {
ArrayNode array = (ArrayNode) node;
Iterator<JsonNode> itr = array.elements();
AtomicInteger counter = new AtomicInteger();
while(itr.hasNext()) {
JsonNode entry = itr.next();
if(skipTags.stream().anyMatch(tag -> tag.getValue().equals(entry))
|| entry.asText().startsWith(SchemaConstants.XOSDU_TAG)) {
itr.remove();
}
clean(entry, path + "/" + counter.getAndIncrement());
}
}
}
}
package org.opengroup.osdu.schema.util;
import java.util.Comparator;
import org.opengroup.osdu.schema.model.SchemaIdentity;
import org.opengroup.osdu.schema.model.SchemaInfo;
public class SchemaComparatorByVersion implements Comparator<SchemaInfo> {
@Override
public int compare(SchemaInfo sch1, SchemaInfo sch2) {
SchemaIdentity schemaIdentity1 = sch1.getSchemaIdentity();
SchemaIdentity schemaIdentity2 = sch2.getSchemaIdentity();
Comparator<SchemaIdentity> compareByMajor = (s1,s2) -> s1.getSchemaVersionMajor().compareTo(s2.getSchemaVersionMajor());
Comparator<SchemaIdentity> compareByMinor = (s1,s2) -> s1.getSchemaVersionMinor().compareTo(s2.getSchemaVersionMinor());
Comparator<SchemaIdentity> compareByPatch = (s1,s2) -> s1.getSchemaVersionPatch().compareTo(s2.getSchemaVersionPatch());
return compareByMajor.thenComparing(compareByMinor).thenComparing(compareByPatch).compare(schemaIdentity1, schemaIdentity2);
}
}
\ No newline at end of file
package org.opengroup.osdu.schema.util;
import org.json.JSONException;
import org.opengroup.osdu.schema.exceptions.BadRequestException;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import java.util.Collections;
import java.util.List;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.schema.exceptions.ApplicationException;
import org.opengroup.osdu.schema.model.QueryParams;
import org.opengroup.osdu.schema.model.SchemaIdentity;
import org.opengroup.osdu.schema.model.SchemaInfo;
import org.opengroup.osdu.schema.provider.interfaces.schemainfostore.ISchemaInfoStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class SchemaUtil {
public void checkBreakingChange(String newSchema, String originalSchema) throws BadRequestException {
private final ISchemaInfoStore schemaInfoStore;
private final JaxRsDpsLog log;
private final DpsHeaders headers;
@Value("${shared.tenant.name:common}")
private String sharedTenant;