Skip to content

Commit

Permalink
AppSchemasController constants moved to top
Browse files Browse the repository at this point in the history
ControllerSelector handles routing for schemas
  • Loading branch information
sergey-zinchenko committed Nov 19, 2024
1 parent 2e9628c commit e441c14
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import com.epam.aidial.core.metaschemas.MetaSchemaHolder;
import com.epam.aidial.core.server.ProxyContext;
import com.epam.aidial.core.server.util.ProxyUtil;
import com.epam.aidial.core.storage.http.HttpException;
import com.epam.aidial.core.storage.http.HttpStatus;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServerRequest;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
Expand All @@ -21,94 +22,68 @@
import java.util.Map;

@Slf4j
public class AppSchemasController implements Controller {
public class AppSchemaController {

private static final String FAILED_READ_SCHEMA_MESSAGE = "Failed to read schema from resources";
private static final String ID_FIELD = "$id";
private static final String ID_PARAM = "id";
private static final String EDITOR_URL_FIELD = "dial:custom-application-type-editor-url";
private static final String DISPLAY_NAME_FIELD = "dial:custom-application-type-display-name";
private static final String COMPLETION_ENDPOINT_FIELD = "dial:custom-application-type-completion-endpoint";

private final ProxyContext context;
private final Vertx vertx;

public AppSchemasController(ProxyContext context) {
public AppSchemaController(ProxyContext context) {
this.context = context;
this.vertx = context.getProxy().getVertx();
}

private static final String LIST_SCHEMAS_RELATIVE_PATH = "list";
private static final String META_SCHEMA_RELATIVE_PATH = "schema";

@Override
public Future<?> handle() {
HttpServerRequest request = context.getRequest();
String path = request.path();
if (path.endsWith(LIST_SCHEMAS_RELATIVE_PATH)) {
return handleListSchemas();
} else if (path.endsWith(META_SCHEMA_RELATIVE_PATH)) {
return handleGetMetaSchema();
} else {
return handleGetSchema();
}
}

private static final String FAILED_READ_META_SCHEMA_MESSAGE = "Failed to read meta-schema from resources";


private Future<?> handleGetMetaSchema() {
try {
return vertx.executeBlocking(MetaSchemaHolder::getCustomApplicationMetaSchema)
.onSuccess(metaSchema -> context.respond(HttpStatus.OK, metaSchema));
} catch (Throwable e) {
log.error(FAILED_READ_META_SCHEMA_MESSAGE, e);
return context.respond(HttpStatus.INTERNAL_SERVER_ERROR, FAILED_READ_META_SCHEMA_MESSAGE);
}
public Future<?> handleGetMetaSchema() {
return vertx.executeBlocking(MetaSchemaHolder::getCustomApplicationMetaSchema)
.onSuccess(metaSchema -> context.respond(HttpStatus.OK, metaSchema))
.onFailure(throwable -> context.respond(throwable, FAILED_READ_SCHEMA_MESSAGE));
}

private static final String COMPLETION_ENDPOINT_FIELD = "dial:custom-application-type-completion-endpoint";

private Future<?> handleGetSchema() {
private JsonNode getSchema() throws JsonProcessingException {
HttpServerRequest request = context.getRequest();
String schemaIdParam = request.getParam("id");
String schemaIdParam = request.getParam(ID_PARAM);

if (schemaIdParam == null) {
return context.respond(HttpStatus.BAD_REQUEST, "Schema ID is required");
throw new HttpException(HttpStatus.BAD_REQUEST, "Schema ID is required");
}

URI schemaId;
try {
schemaId = URI.create(URLDecoder.decode(schemaIdParam, StandardCharsets.UTF_8));
} catch (IllegalArgumentException e) {
return context.respond(HttpStatus.BAD_REQUEST, "Schema ID should be a valid uri");
throw new HttpException(HttpStatus.BAD_REQUEST, "Schema ID is required");
}

String schema = context.getConfig().getCustomApplicationSchemas().get(schemaId.toString());
if (schema == null) {
return context.respond(HttpStatus.NOT_FOUND, "Schema not found");
return null;
}

try {
JsonNode schemaNode = ProxyUtil.MAPPER.readTree(schema);
if (schemaNode.has(COMPLETION_ENDPOINT_FIELD)) {
((ObjectNode) schemaNode).remove(COMPLETION_ENDPOINT_FIELD); //we need to remove completion endpoint from response to avoid disclosure
}
return context.respond(HttpStatus.OK, schemaNode);
} catch (IOException e) {
log.error("Failed to parse schema", e);
return context.respond(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to parse schema");
JsonNode schemaNode = ProxyUtil.MAPPER.readTree(schema);
if (schemaNode.has(COMPLETION_ENDPOINT_FIELD)) {
((ObjectNode) schemaNode).remove(COMPLETION_ENDPOINT_FIELD); //we need to remove completion endpoint from response to avoid disclosure
}
return schemaNode;
}

private static final String ID_FIELD = "$id";
private static final String EDITOR_URL_FIELD = "dial:custom-application-type-editor-url";
private static final String DISPLAY_NAME_FIELD = "dial:custom-application-type-display-name";
public Future<?> handleGetSchema() {
return vertx.executeBlocking(this::getSchema)
.onSuccess(schemaNode -> context.respond(HttpStatus.OK, schemaNode))
.onFailure(throwable -> context.respond(throwable, FAILED_READ_SCHEMA_MESSAGE));
}

public Future<?> handleListSchemas() {
private List<JsonNode> listSchemas() throws JsonProcessingException {
Config config = context.getConfig();
List<JsonNode> filteredSchemas = new ArrayList<>();

for (Map.Entry<String, String> entry : config.getCustomApplicationSchemas().entrySet()) {
JsonNode schemaNode;
try {
schemaNode = ProxyUtil.MAPPER.readTree(entry.getValue());
} catch (IOException e) {
log.error("Failed to parse schema", e);
continue;
}
schemaNode = ProxyUtil.MAPPER.readTree(entry.getValue());

if (schemaNode.has(ID_FIELD)
&& schemaNode.has(EDITOR_URL_FIELD)
Expand All @@ -120,9 +95,12 @@ public Future<?> handleListSchemas() {
filteredSchemas.add(filteredNode);
}
}

return context.respond(HttpStatus.OK, filteredSchemas);
return filteredSchemas;
}


public Future<?> handleListSchemas() {
return vertx.executeBlocking(this::listSchemas)
.onSuccess(schemas -> context.respond(HttpStatus.OK, schemas))
.onFailure(throwable -> context.respond(throwable, FAILED_READ_SCHEMA_MESSAGE));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import lombok.experimental.UtilityClass;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -173,7 +172,18 @@ public class ControllerSelector {
return () -> controller.handle(deploymentId, getter, false);
});
get(USER_INFO, (proxy, context, pathMatcher) -> new UserInfoController(context));
get(APP_SCHEMAS, (proxy, context, pathMatcher) -> new AppSchemasController(context));
get(APP_SCHEMAS, (proxy, context, pathMatcher) -> {
AppSchemaController controller = new AppSchemaController(context);
String operation = pathMatcher.group(1);
if (operation == null) {
return controller::handleGetSchema;
}
return switch (operation) {
case "/list" -> controller::handleListSchemas;
case "/schema" -> controller::handleGetMetaSchema;
default -> null;
};
});

// POST routes
post(PATTERN_POST_DEPLOYMENT, (proxy, context, pathMatcher) -> {
Expand Down

0 comments on commit e441c14

Please sign in to comment.