Skip to content

Commit

Permalink
chore: properties grouped to container field for applications with ty…
Browse files Browse the repository at this point in the history
…pe schema (#644)
  • Loading branch information
sergey-zinchenko authored Jan 16, 2025
1 parent f4c9e32 commit 9bfc3c7
Show file tree
Hide file tree
Showing 16 changed files with 332 additions and 160 deletions.
25 changes: 6 additions & 19 deletions config/src/main/java/com/epam/aidial/core/config/Application.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.epam.aidial.core.config;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
Expand All @@ -25,21 +22,11 @@ public class Application extends Deployment {

private Function function;

@JsonIgnore
private Map<String, Object> customProperties = new HashMap<>(); //all custom application properties will land there
@JsonAlias({"applicationProperties", "application_properties"})
private Map<String, Object> applicationProperties; //all custom application properties will land there

@JsonAnySetter
public void setCustomProperty(String key, Object value) { //all custom application properties will land there
customProperties.put(key, value);
}

@JsonAnyGetter
public Map<String, Object> getCustomProperties() {
return customProperties;
}

@JsonAlias({"customAppSchemaId", "custom_app_schema_id"})
private URI customAppSchemaId;
@JsonAlias({"applicationTypeSchemaId", "application_type_schema_id"})
private URI applicationTypeSchemaId;

@Data
@Accessors(chain = true)
Expand Down Expand Up @@ -135,7 +122,7 @@ public Application(Application source) {
this.setInterceptors(source.getInterceptors());
this.setDescriptionKeywords(source.getDescriptionKeywords());
this.setFunction(source.getFunction());
this.setCustomProperties(source.getCustomProperties());
this.setCustomAppSchemaId(source.getCustomAppSchemaId());
this.setApplicationProperties(source.getApplicationProperties());
this.setApplicationTypeSchemaId(source.getApplicationTypeSchemaId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,16 @@ public boolean isValid(Config value, ConstraintValidatorContext context) {
ObjectMapper mapper = new ObjectMapper();
for (Map.Entry<String, Application> entry : value.getApplications().entrySet()) {
Application application = entry.getValue();
URI schemaId = application.getCustomAppSchemaId();
URI schemaId = application.getApplicationTypeSchemaId();
if (schemaId == null) {
continue;
}

JsonSchema schema = schemaFactory.getSchema(schemaId);
JsonNode applicationNode = mapper.valueToTree(application);
if (application.getApplicationProperties() == null) {
continue;
}
JsonNode applicationNode = mapper.valueToTree(application.getApplicationProperties());
Set<ValidationMessage> validationResults = schema.validate(applicationNode);
if (!validationResults.isEmpty()) {
String logMessage = validationResults.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,44 @@ void isValidReturnsTrueWhenApplicationsAreEmpty() {
assertTrue(validator.isValid(config, context));
}

@Test
void isValidReturnsTrueWhenApplicationHasNullProps() {
Map<String, Application> applications = new HashMap<>();
Application application = new Application();
application.setApplicationTypeSchemaId(URI.create("https://mydial.epam.com/custom_application_schemas/specific_application_type"));
applications.put("app1", application);
config.setApplications(applications);
Map<String, String> schemas = new HashMap<>();
String customSchemaStr = "{"
+ "\"$schema\": \"https://dial.epam.com/application_type_schemas/schema#\","
+ "\"$id\": \"https://mydial.epam.com/custom_application_schemas/specific_application_type\","
+ "\"dial:applicationTypeEditorUrl\": \"https://mydial.epam.com/specific_application_type_editor\","
+ "\"dial:applicationTypeDisplayName\": \"Specific Application Type\","
+ "\"dial:applicationTypeCompletionEndpoint\": \"http://specific_application_service/opeani/v1/completion\","
+ "\"properties\": {"
+ " \"file\": {"
+ " \"type\": \"string\","
+ " \"format\": \"dial-file-encoded\","
+ " \"dial:meta\": {"
+ " \"dial:propertyKind\": \"client\","
+ " \"dial:propertyOrder\": 1"
+ " }"
+ " }"
+ "},"
+ "\"required\": [\"file\"]"
+ "}";
schemas.put("https://mydial.epam.com/custom_application_schemas/specific_application_type", customSchemaStr);
config.setApplicationTypeSchemas(schemas);

assertTrue(validator.isValid(config, context));
}

@Test
void isValidReturnsFalseWhenSchemaValidationFails() {
Map<String, Application> applications = new HashMap<>();
Application application = new Application();
application.setCustomAppSchemaId(URI.create("https://mydial.epam.com/custom_application_schemas/specific_application_type"));
application.setApplicationTypeSchemaId(URI.create("https://mydial.epam.com/custom_application_schemas/specific_application_type"));
application.setApplicationProperties(Map.of());
applications.put("app1", application);
config.setApplications(applications);
Map<String, String> schemas = new HashMap<>();
Expand Down Expand Up @@ -93,10 +126,10 @@ void isValidReturnsFalseWhenSchemaValidationFails() {
void isValidReturnsTrueWhenSchemaValidationPasses() {
Map<String, Application> applications = new HashMap<>();
Application application = new Application();
application.setCustomAppSchemaId(URI.create("https://mydial.epam.com/custom_application_schemas/specific_application_type"));
application.setApplicationTypeSchemaId(URI.create("https://mydial.epam.com/custom_application_schemas/specific_application_type"));
Map<String, Object> props = new HashMap<>();
props.put("file", "files/bucket/path/name.ext");
application.setCustomProperties(props);
application.setApplicationProperties(props);
applications.put("app1", application);
config.setApplications(applications);
Map<String, String> schemas = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public ApplicationData mapApplication(Application application) {
data.setDefaults(application.getDefaults());
data.setDescriptionKeywords(application.getDescriptionKeywords());

data.setCustomAppSchemaId(application.getCustomAppSchemaId());
data.setCustomProperties(application.getCustomProperties());
data.setApplicationTypeSchemaId(application.getApplicationTypeSchemaId());
data.setApplicationProperties(application.getApplicationProperties());
String reference = application.getReference();
data.setReference(reference == null ? application.getName() : reference);
data.setFunction(application.getFunction());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static Future<Deployment> selectDeployment(ProxyContext context, String i
return Future.succeededFuture(deployment);
}
return proxy.getVertx().executeBlocking(() -> {
if (application.getCustomAppSchemaId() == null) {
if (application.getApplicationTypeSchemaId() == null) {
return application;
}
Application modifiedApp = application;
Expand Down Expand Up @@ -118,7 +118,7 @@ public static Future<Deployment> selectDeployment(ProxyContext context, String i

Application app = proxy.getApplicationService().getApplication(resource).getValue();

if (app.getCustomAppSchemaId() != null) {
if (app.getApplicationTypeSchemaId() != null) {
if (filterCustomProperties) {
app = ApplicationTypeSchemaUtils.filterCustomClientPropertiesWhenNoWriteAccess(context, resource, app);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@

import com.epam.aidial.core.config.Application;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

Expand All @@ -26,22 +22,12 @@ public class ApplicationData extends DeploymentData {
setScaleSettings(null);
}

@JsonIgnore
private Map<String, Object> customProperties = new HashMap<>(); //all custom application properties will land there

@JsonAnySetter
public void setCustomProperty(String key, Object value) { //all custom application properties will land there
customProperties.put(key, value);
}

@JsonAnyGetter
public Map<String, Object> getCustomProperty() {
return customProperties;
}
@Nullable
private Map<String, Object> applicationProperties; //all custom application properties will land there

@Nullable
@JsonAlias({"customAppSchemaId", "custom_app_schema_id"})
private URI customAppSchemaId;
@JsonAlias({"applicationTypeSchemaId", "application_type_schema_id"})
private URI applicationTypeSchemaId;

private Application.Function function;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public AppendApplicationPropertiesFn(Proxy proxy, ProxyContext context) {
@Override
public Boolean apply(ObjectNode tree) {
Deployment deployment = context.getDeployment();
if (!(deployment instanceof Application application && application.getCustomAppSchemaId() != null)) {
if (!(deployment instanceof Application application && application.getApplicationTypeSchemaId() != null)) {
return false;
}
Map<String, Object> props = ApplicationTypeSchemaUtils.getCustomServerProperties(context.getConfig(), application);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import com.epam.aidial.core.storage.util.EtagHeader;
import com.epam.aidial.core.storage.util.UrlUtil;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -221,6 +220,11 @@ public Pair<ResourceItemMetadata, Application> putApplication(ResourceDescriptor
Application existing = ProxyUtil.convertToObject(json, Application.class);
Application.Function function = application.getFunction();

if (application.getApplicationTypeSchemaId() != null && existing != null
&& existing.getApplicationProperties() != null && application.getApplicationProperties() == null) {
throw new HttpException(HttpStatus.BAD_REQUEST, "The application with schema can not be updated to the one without properties");
}

if (function != null) {
if (existing == null || existing.getFunction() == null) {
if (isPublicOrReview(resource)) {
Expand Down Expand Up @@ -421,7 +425,7 @@ public Application.Logs getApplicationLogs(ResourceDescriptor resource) {
private void prepareApplication(ResourceDescriptor resource, Application application) {
verifyApplication(resource);

if (application.getCustomAppSchemaId() != null) {
if (application.getApplicationTypeSchemaId() != null) {
if (application.getEndpoint() != null || application.getFunction() != null) {
throw new IllegalArgumentException("Endpoint must not be set for custom application");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ private void addCustomApplicationRelatedFiles(ProxyContext context, Publication
return Stream.empty();
}
Application application = applicationService.getApplication(source).getValue();
if (application.getCustomAppSchemaId() == null) {
if (application.getApplicationTypeSchemaId() == null) {
return Stream.empty();
}
String targetFolder = buildTargetFolderForCustomAppFiles(resource);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class ApplicationTypeSchemaUtils {
.build();

static String getCustomApplicationSchemaOrThrow(Config config, Application application) {
URI schemaId = application.getCustomAppSchemaId();
URI schemaId = application.getApplicationTypeSchemaId();
if (schemaId == null) {
return null;
}
Expand All @@ -60,12 +60,12 @@ static String getCustomApplicationSchemaOrThrow(Config config, Application appli
}

@SuppressWarnings("unchecked")
private static Map<String, Object> filterProperties(Map<String, Object> customProps, String schema, String collectorName) {
private static Map<String, Object> filterProperties(Map<String, Object> applicationProperties, String schema, String collectorName) {
try {
JsonSchema appSchema = SCHEMA_FACTORY.getSchema(schema);
CollectorContext collectorContext = new CollectorContext();
String customPropsJson = ProxyUtil.MAPPER.writeValueAsString(customProps);
Set<ValidationMessage> validationResult = appSchema.validate(customPropsJson, InputFormat.JSON,
String applicationPropertiesJson = ProxyUtil.MAPPER.writeValueAsString(applicationProperties);
Set<ValidationMessage> validationResult = appSchema.validate(applicationPropertiesJson, InputFormat.JSON,
e -> e.setCollectorContext(collectorContext));
if (!validationResult.isEmpty()) {
throw new ApplicationTypeSchemaValidationException("Failed to validate custom app against the schema", validationResult);
Expand All @@ -76,7 +76,7 @@ private static Map<String, Object> filterProperties(Map<String, Object> customPr
}
Map<String, Object> result = new HashMap<>();
for (String propertyName : propsCollector.collect()) {
result.put(propertyName, customProps.get(propertyName));
result.put(propertyName, applicationProperties.get(propertyName));
}
return result;
} catch (ApplicationTypeSchemaValidationException e) {
Expand All @@ -91,7 +91,10 @@ public static Map<String, Object> getCustomServerProperties(Config config, Appli
if (customApplicationSchema == null) {
return Collections.emptyMap();
}
return filterProperties(application.getCustomProperties(), customApplicationSchema, "server");
if (application.getApplicationProperties() == null) {
throw new ApplicationTypeSchemaValidationException("Typed application's properties not set");
}
return filterProperties(application.getApplicationProperties(), customApplicationSchema, "server");
}

public static String getCustomApplicationEndpoint(Config config, Application application) {
Expand Down Expand Up @@ -123,9 +126,12 @@ public static Application filterCustomClientProperties(Config config, Applicatio
if (customApplicationSchema == null) {
return application;
}
if (application.getApplicationProperties() == null) {
return application;
}
Application copy = new Application(application);
Map<String, Object> appWithClientOptionsOnly = filterProperties(application.getCustomProperties(), customApplicationSchema, "client");
copy.setCustomProperties(appWithClientOptionsOnly);
Map<String, Object> appWithClientOptionsOnly = filterProperties(application.getApplicationProperties(), customApplicationSchema, "client");
copy.setApplicationProperties(appWithClientOptionsOnly);
return copy;
}

Expand All @@ -137,15 +143,15 @@ public static Application filterCustomClientPropertiesWhenNoWriteAccess(ProxyCon
}

public static void replaceCustomAppFiles(Application application, Map<String, String> replacementLinks) {
if (application.getCustomAppSchemaId() == null) {
if (application.getApplicationTypeSchemaId() == null) {
return;
}
JsonNode customProperties = ProxyUtil.MAPPER.convertValue(application.getCustomProperties(), JsonNode.class);
JsonNode customProperties = ProxyUtil.MAPPER.convertValue(application.getApplicationProperties(), JsonNode.class);
replaceLinksInJsonNode(customProperties, replacementLinks, null, null);
Map<String, Object> customPropertiesMap = ProxyUtil.MAPPER.convertValue(customProperties, new TypeReference<>() {
});

application.setCustomProperties(customPropertiesMap);
application.setApplicationProperties(customPropertiesMap);
}

@SuppressWarnings("unchecked")
Expand All @@ -157,7 +163,7 @@ public static List<ResourceDescriptor> getFiles(Config config, Application appli
}
JsonSchema appSchema = SCHEMA_FACTORY.getSchema(customApplicationSchema);
CollectorContext collectorContext = new CollectorContext();
String customPropsJson = ProxyUtil.MAPPER.writeValueAsString(application.getCustomProperties());
String customPropsJson = ProxyUtil.MAPPER.writeValueAsString(application.getApplicationProperties());
Set<ValidationMessage> validationResult = appSchema.validate(customPropsJson, InputFormat.JSON,
e -> e.setCollectorContext(collectorContext));
if (!validationResult.isEmpty()) {
Expand Down
Loading

0 comments on commit 9bfc3c7

Please sign in to comment.