From 4e2ed9a4f9e2370eab743c0cf9d3427b8e462064 Mon Sep 17 00:00:00 2001 From: Loris Sauter Date: Fri, 4 Dec 2020 16:30:55 +0100 Subject: [PATCH] Resolved #160 by properly documenting and refactoring APIEndpoint --- .../org/vitrivr/cineast/api/APIEndpoint.java | 414 ++++++++--------- .../api/docs/GenerateOpenApiSpecs.java | 5 +- .../cineast/api/rest/OpenApiCompatHelper.java | 149 ++++++ .../FindObjectMetadataByDomainGetHandler.java | 4 +- ...FindObjectMetadataByDomainPostHandler.java | 4 +- .../FindObjectMetadataByKeyGetHandler.java | 4 +- .../FindObjectMetadataByKeyPostHandler.java | 4 +- ...bjectMetadataFullyQualifiedGetHandler.java | 4 +- .../FindObjectMetadataGetHandler.java | 4 +- .../FindObjectMetadataPostHandler.java | 4 +- .../api/rest/routes/ResolvedContentRoute.java | 10 +- .../cineast/standalone/config/APIConfig.java | 429 ++++++++++-------- .../vitrivr/cineast/standalone/util/CLI.java | 2 +- 13 files changed, 614 insertions(+), 423 deletions(-) create mode 100644 cineast-api/src/main/java/org/vitrivr/cineast/api/rest/OpenApiCompatHelper.java diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java index 7aad2cd09..1217379b1 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java @@ -1,22 +1,13 @@ package org.vitrivr.cineast.api; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import io.javalin.Javalin; import io.javalin.http.staticfiles.Location; -import io.javalin.plugin.openapi.OpenApiOptions; import io.javalin.plugin.openapi.OpenApiPlugin; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; -import io.javalin.plugin.openapi.ui.ReDocOptions; -import io.javalin.plugin.openapi.ui.SwaggerOptions; -import io.swagger.v3.core.jackson.ModelResolver; -import io.swagger.v3.core.util.Json; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Contact; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.tags.Tag; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -25,21 +16,37 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.actions.StatusInvocationHandler; import org.vitrivr.cineast.api.rest.handlers.actions.bool.FindDistinctElementsByColumnPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.mediaobject.FindObjectAllGetHandler; import org.vitrivr.cineast.api.rest.handlers.actions.mediaobject.FindObjectByIdPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.mediaobject.FindObjectGetHandler; -import org.vitrivr.cineast.api.rest.handlers.actions.metadata.*; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataByDomainGetHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataByDomainPostHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataByKeyGetHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataByKeyPostHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataFullyQualifiedGetHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataGetHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindObjectMetadataPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentByIdPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentSimilarPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentsByIdGetHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentsByObjectIdGetHandler; -import org.vitrivr.cineast.api.rest.handlers.actions.session.*; +import org.vitrivr.cineast.api.rest.handlers.actions.session.EndExtractionHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.session.EndSessionHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.session.ExtractItemHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.session.StartExtractionHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.session.StartSessionHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.session.ValidateSessionHandler; import org.vitrivr.cineast.api.rest.handlers.actions.tag.FindTagsAllGetHandler; import org.vitrivr.cineast.api.rest.handlers.actions.tag.FindTagsByIdsPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.tag.FindTagsGetHandler; -import org.vitrivr.cineast.api.rest.handlers.interfaces.*; +import org.vitrivr.cineast.api.rest.handlers.interfaces.DeleteRestHandler; +import org.vitrivr.cineast.api.rest.handlers.interfaces.DocumentedRestHandler; +import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler; +import org.vitrivr.cineast.api.rest.handlers.interfaces.PostRestHandler; +import org.vitrivr.cineast.api.rest.handlers.interfaces.PutRestHandler; import org.vitrivr.cineast.api.rest.resolvers.FileSystemObjectResolver; import org.vitrivr.cineast.api.rest.resolvers.FileSystemThumbnailResolver; import org.vitrivr.cineast.api.rest.routes.ResolvedContentRoute; @@ -49,53 +56,60 @@ import org.vitrivr.cineast.standalone.config.Config; import org.vitrivr.cineast.standalone.util.ContinuousRetrievalLogic; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - /** - * This class establishes a HTTP API endpoint listening on the specified port(s). - * The HTTP handling is facilitated by the Javalin framework (https://javalin.io/). + * This class establishes a HTTP API endpoint listening on the specified port(s). The HTTP handling + * is facilitated by the Javalin framework (https://javalin.io/). *

- * The {@link APIEndpoint} class supports setup for both the WebSocket and RestFul API endpoints, depending on the - * configuration. + * The {@link APIEndpoint} class supports setup for both the WebSocket and RestFul API endpoints, + * depending on the configuration. *

- * Incoming requests are routed towards a {@link DocumentedRestHandler} based on the HTTP method and the URL, provided that - * such a handler hasn't been registered beforehand. + * Incoming requests are routed towards a {@link DocumentedRestHandler} based on the HTTP method and + * the URL, provided that such a handler hasn't been registered beforehand. *

- * WebSocket communication is forwarded to the {@link WebsocketAPI} class, which handles incoming packets. + * WebSocket communication is forwarded to the {@link WebsocketAPI} class, which handles incoming + * packets. * - * @author rgasser & loris.sauter + * @author rgasser & Loris Sauter * @version 2.1 * @created 07.12.17 * @see WebsocketAPI */ public class APIEndpoint { + /** - * OpenAPI Specification tag for metadata related routes + * Version of the protocol used by the RESTful endpoint. Will be appended to the endpoint URL. */ - public static final String METADATA_OAS_TAG = "Metadata"; - - private static final Logger LOGGER = LogManager.getLogger(); - + public static final String VERSION = "v1"; + /** - * Version of the protocol used by the RESTful endpoint. Will be appended to the endpoint URL. + * The Logger used by the api to log general things. It is recommended that {@link + * org.vitrivr.cineast.api.rest.handlers.interfaces.RestHandler}s provide own loggers for more + * logging control. */ - private static final String VERSION = "v1"; - + private static final Logger LOGGER = LogManager.getLogger(); /** * Named context of the RESTful endpoint. Will be appended to the endpoint URL. */ private static final String CONTEXT = "api"; - public static ContinuousRetrievalLogic retrievalLogic = new ContinuousRetrievalLogic(Config.sharedConfig().getDatabase()); //TODO there is certainly a nicer way to do this... + + /** + * The retrieval logic used to retrieve + */ + public static ContinuousRetrievalLogic retrievalLogic = new ContinuousRetrievalLogic( + Config.sharedConfig().getDatabase()); + + /** + * The single instance of this class + */ private static APIEndpoint instance = null; - private WebsocketAPI webSocketApi = null; + /** + * A list of {@link DocumentedRestHandler}s to register in this API. + */ private final List restHandlers = new ArrayList<>(); + /** + * Websocket API + */ + private WebsocketAPI webSocketApi = null; /** * References to the HTTP and HTTPS service. */ @@ -104,18 +118,18 @@ public class APIEndpoint { * The Javalin OpenAPI plugin that generates the specification and serves the Swagger-UI */ private OpenApiPlugin openApi; - + private APIEndpoint() { registerRestOperations(); } - + public static APIEndpoint getInstance() { if (instance == null) { instance = new APIEndpoint(); } return instance; } - + /** * Stops the RESTful / WebSocket API. */ @@ -125,7 +139,7 @@ public static void stop() { } retrievalLogic.shutdown(); } - + /** * Concatenates the provided service name into a full URL path. * @@ -138,26 +152,67 @@ private static String makePath(String name) { /** * Returns the namespace of the API. Concatenation of /{@link #CONTEXT}/{@link #VERSION} + * * @return The REST API namespace */ - private static String namespace() { + public static String namespace() { return String.format("/%s/%s", CONTEXT, VERSION); } - + + /** + * Returns the non-secure {@link Javalin} instance this API uses + * + *

+ * * Warning This is only exposed for {@link OpenApiCompatHelper} and might be removed * + * in a future update *

+ * + * @return The non-secure http instance this API uses + */ + public Javalin getHttp() { + return http; + } + + /** + * Sets the non-secure http {@link Javalin} instance this API uses. + *

+ * Warning This is only exposed for {@link OpenApiCompatHelper} and might be removed + * in a future update + *

+ * + * @param http The non-secure {@link Javalin} instance for this API. + */ + public void setHttp(Javalin http) { + this.http = http; + } + + /** + * Returns the {@link OpenApiPlugin} this API has configured + * + * @return The {@link OpenApiPlugin} this API has configured + */ + public OpenApiPlugin getOpenApi() { + return openApi; + } + /** * Starts the RESTful / WebSocket API. */ public void start() { /* Start insecure HTTP connection. */ - if (Config.sharedConfig().getApi().getEnableRest() || Config.sharedConfig().getApi().getEnableWebsocket()) { + if (Config.sharedConfig().getApi().getEnableRest() || Config.sharedConfig().getApi() + .getEnableWebsocket()) { http = dispatchService(false); } - - if (Config.sharedConfig().getApi().getEnableRestSecure() || Config.sharedConfig().getApi().getEnableWebsocketSecure()) { + /* Start secure HTTP connection */ + if (Config.sharedConfig().getApi().getEnableRestSecure() || Config.sharedConfig().getApi() + .getEnableWebsocketSecure()) { https = dispatchService(true); } } - + + /** + * Shuts down this API + */ public void shutdown() { if (Config.sharedConfig().getApi().getEnableRest() || Config.sharedConfig().getApi() .getEnableWebsocket()) { @@ -171,51 +226,28 @@ public void shutdown() { webSocketApi.shutdown(); } } - - public void writeOpenApiDocPersistently(final String path) throws IOException { - try { - http = dispatchService(false); - if (openApi != null) { - String schema = Json.pretty(openApi.getOpenApiHandler().createOpenAPISchema()); - File file = new File(path); - File folder = file.getParentFile(); - if (folder != null) { - folder.mkdirs(); - } - if (file.exists()) { - file.delete(); - } - try (FileOutputStream stream = new FileOutputStream(file); PrintWriter writer = new PrintWriter(stream)) { - writer.print(schema); - writer.flush(); - } - LOGGER.info("Successfully stored openapi spec at {}", path); - } - } finally { - stop(); - } - } - + /** - * Dispatches a new Jetty {@link Javalin} (HTTP endpoint). The method takes care of all the necessary setup. + * Dispatches a new Jetty {@link Javalin} (HTTP endpoint). The method takes care of all the + * necessary setup. * * @param secure If true, the new Service will be setup as secure with TLS enabled. * @return {@link Javalin} */ - private Javalin dispatchService(boolean secure) { + public Javalin dispatchService(boolean secure) { final APIConfig config = Config.sharedConfig().getApi(); - + final int port = this.validateAndNormalizePort(secure, config); - + final Javalin service = Javalin.create(serviceConfig -> { - serviceConfig.enableDevLogging(); /* Configure server (TLS, thread pool, etc.) */ serviceConfig.enableCorsForAllOrigins(); + /* Configuration of the actual server */ serviceConfig.server(() -> { QueuedThreadPool threadPool = new QueuedThreadPool(config.getThreadPoolSize(), 2, 30000); - + Server server = new Server(threadPool); - + ServerConnector connector; if (secure) { /* Setup TLS if secure flag was set. */ @@ -226,56 +258,51 @@ private Javalin dispatchService(boolean secure) { } else { connector = new ServerConnector(server); } - + if (port > 0) { connector.setPort(port); } - + server.setConnectors(new Connector[]{connector}); - + return server; }); - + /* Configure OpenAPI/Swagger doc */ if (config.getEnableLiveDoc()) { - this.openApi = new OpenApiPlugin(this.getJavalinOpenApiOptions(config)); + this.openApi = new OpenApiPlugin(OpenApiCompatHelper.getJavalinOpenApiOptions(config)); serviceConfig.registerPlugin(this.openApi); - + /* Enable webjars to serve Swagger-UI */ serviceConfig.enableWebjars(); } /* Serve the UI if requested statically*/ - if(config.getServeUI()){ + if (config.getServeUI()) { + /* Add css, js and other static files */ serviceConfig.addStaticFiles(config.getUiLocation(), Location.EXTERNAL); - serviceConfig.addSinglePageRoot("/", config.getUiLocation()+"/index.html", Location.EXTERNAL); - /*Arrays.asList("/gallery", - "/list", - "/mini-gallery", - "/mediaobject", - "/mediaobject/:objectId") - .forEach(url -> { - serviceConfig.addStaticFiles(url, config.getUiLocation(), Location.EXTERNAL); - });*/ + /* Add index.html - the ui's front page as default route. Anything reroutes to thre */ + serviceConfig + .addSinglePageRoot("/", config.getUiLocation() + "/index.html", Location.EXTERNAL); } }); - + /* Enable WebSocket (if configured). */ if (config.getEnableWebsocket()) { this.webSocketApi = new WebsocketAPI(); - + service.ws(String.format("%s/websocket", namespace()), handler -> { handler.onConnect(ctx -> { webSocketApi.connected(ctx.session); }); - + handler.onClose(ctx -> { webSocketApi.closed(ctx.session, ctx.status(), ctx.reason()); }); - + handler.onError(ctx -> { webSocketApi.onWebSocketException(ctx.session, ctx.error()); }); - + handler.onMessage(ctx -> { webSocketApi.message(ctx.session, ctx.message()); }); @@ -283,23 +310,23 @@ private Javalin dispatchService(boolean secure) { } - + /* Setup HTTP/RESTful connection (if configured). */ if (config.getEnableRest() || config.getEnableRestSecure()) { - this.restHandlers.forEach(handler -> registerRestHandler(service, handler, config)); + this.restHandlers.forEach(handler -> registerRestHandler(service, handler)); this.registerServingRoutes(service, config); } - + /* Register a general exception handler. TODO: Add fine grained exception handling. */ service.exception(Exception.class, (ex, ctx) -> { ex.printStackTrace(); LOGGER.error(ex); }); - + /* General settings */ service.config.defaultContentType = "application/json"; service.config.prefer405over404 = true; - + /* Start javalin */ try { if (port > 0) { @@ -308,13 +335,21 @@ private Javalin dispatchService(boolean secure) { service.start(); } } catch (Exception ex) { - LOGGER.log(Level.FATAL, "Failed to start HTTP endpoint due to an exception. Cineast will shut down now!", ex); + LOGGER.log(Level.FATAL, + "Failed to start HTTP endpoint due to an exception. Cineast will shut down now!", ex); System.exit(100); } - + return service; } - + + /** + * Makes sure the configured port(s) is (are) in valid range. Fallback to default otherwise + * + * @param secure If the validation is for the secure configuration + * @param config The active config + * @return The port, validated and otherwise default port fromt he default config. + */ private int validateAndNormalizePort(boolean secure, APIConfig config) { int port = secure ? config.getHttpsPort() : config.getHttpPort(); if (port <= 0 || port >= 65535) { @@ -325,22 +360,44 @@ private int validateAndNormalizePort(boolean secure, APIConfig config) { } return port; } - - private void registerRestHandler(final Javalin javalin, final DocumentedRestHandler handler, final APIConfig config) { + + /** + * Registers a {@link DocumentedRestHandler} according its specialisation with the corresponding + * http method. Currently, there are four specialisations: + * + * + * @param javalin The {@link Javalin} instance to register the handler at + * @param handler The handler to register + */ + private void registerRestHandler(final Javalin javalin, final DocumentedRestHandler handler) { if (handler instanceof GetRestHandler) { - javalin.get(makePath(handler.route()), OpenApiBuilder.documented(handler.docs(), ((GetRestHandler) handler)::get)); + javalin.get(makePath(handler.route()), + OpenApiBuilder.documented(handler.docs(), ((GetRestHandler) handler)::get)); } else if (handler instanceof PostRestHandler) { - javalin.post(makePath(handler.route()), OpenApiBuilder.documented(handler.docs(), ((PostRestHandler) handler)::post)); + javalin.post(makePath(handler.route()), + OpenApiBuilder.documented(handler.docs(), ((PostRestHandler) handler)::post)); } else if (handler instanceof DeleteRestHandler) { - javalin.delete(makePath(handler.route()), OpenApiBuilder.documented(handler.docs(), ((DeleteRestHandler) handler)::delete)); + javalin.delete(makePath(handler.route()), + OpenApiBuilder.documented(handler.docs(), ((DeleteRestHandler) handler)::delete)); } else if (handler instanceof PutRestHandler) { - javalin.put(makePath(handler.route()), OpenApiBuilder.documented(handler.docs(), ((PutRestHandler) handler)::put)); + javalin.put(makePath(handler.route()), + OpenApiBuilder.documented(handler.docs(), ((PutRestHandler) handler)::put)); } else { - throw new IllegalArgumentException("The given handler of type " + handler.getClass() + " has no specified method"); + throw new IllegalArgumentException( + "The given handler of type " + handler.getClass() + " has no specified method"); } /* One would implement the remaining HTTP methods here */ } - + + /** + * Registers all the rest handlers. + * Must be called before actually creating the server + */ private void registerRestOperations() { restHandlers.addAll(Arrays.asList( /* Metadata */ @@ -377,94 +434,41 @@ private void registerRestOperations() { new StatusInvocationHandler() )); } - + + /** + * If configured, this registers two special routes that serve the media objects as media content + * and additionally a thumbnails endpoint for them. + * + * @param service + * @param config + */ private void registerServingRoutes(final Javalin service, final APIConfig config) { - // TODO Register these special cases as well with the new model if (config.getServeContent()) { service.get("/thumbnails/:id", new ResolvedContentRoute( new FileSystemThumbnailResolver( new File(Config.sharedConfig().getApi().getThumbnailLocation())))); - - service.get("/objects/:id", new ResolvedContentRoute( - new FileSystemObjectResolver( - new File(Config.sharedConfig().getApi().getObjectLocation()), - new MediaObjectReader(Config.sharedConfig().getDatabase().getSelectorSupplier().get()), - ((baseDir, object) -> { - String ext = object.getPath().substring(object.getPath().lastIndexOf('.')); - return new File(baseDir, object.getObjectId()+ext); - })))); + + /* The VBS database in-use is broken, this is the hack to circumvent object paths being wrong */ + FileSystemObjectResolver fsor; + if (config.isObjectsFilesAreIDed()) { + fsor = new FileSystemObjectResolver( + new File(Config.sharedConfig().getApi().getObjectLocation()), + new MediaObjectReader( + Config.sharedConfig().getDatabase().getSelectorSupplier().get()), + ((baseDir, object) -> { + String ext = object.getPath().substring(object.getPath().lastIndexOf('.')); + return new File(baseDir, object.getObjectId() + ext); + })); + } else { + fsor = new FileSystemObjectResolver( + new File(Config.sharedConfig().getApi().getObjectLocation()), + new MediaObjectReader( + Config.sharedConfig().getDatabase().getSelectorSupplier().get())); + } + + service.get("/objects/:id", new ResolvedContentRoute(fsor + )); } } - - /** - * Creates the Javalin options used to create an OpenAPI specification. - * - * @param config - * @return - */ - private OpenApiOptions getJavalinOpenApiOptions(APIConfig config) { - //Default Javalin JSON mapper includes all null values and breaks spec json - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - - return new OpenApiOptions(() -> this.getOpenApi(config)) - .path("/openapi-specs") - .activateAnnotationScanningFor("org.vitrivr.cineast.api") -// .toJsonMapper(new JacksonToJsonMapper()) -// .modelConverterFactory(new JacksonModelConverterFactory()) - .toJsonMapper(o -> { - try { - return mapper.writeValueAsString(o); - } catch (JsonProcessingException e) { - throw new RuntimeException("Couldn't serialise due to ", e); - } - }) - .modelConverterFactory(() -> new ModelResolver(mapper)) - .swagger(new SwaggerOptions("/swagger-ui").title("Swagger UI for Cineast Documentation")) - .reDoc(new ReDocOptions("/redoc").title("ReDoc for Cineast Documentation")); - } - - /** - * Creates the base {@link OpenAPI} specification. - * - * @param config - * @return - */ - private OpenAPI getOpenApi(APIConfig config) { - OpenAPI api = new OpenAPI(); - - api.info( - new Info() - .title("Cineast RESTful API") - .description("Cineast is vitrivr's content-based multimedia retrieval engine. This is it's RESTful API.") - .version(VERSION) - .license( - new License() - .name("Apache 2.0") - .url("http://www.apache.org/licenses/LICENSE-2.0.html") - ) - .contact( - new Contact() - .name("Cineast Team") - .url("https://vitrivr.org") - .email("contact@vitrivr.org") - ) - ); - - api.addTagsItem( - new Tag() - .name(namespace()) - .description("Cineast Default") - ); - - api.addTagsItem(new Tag().name(METADATA_OAS_TAG).description("Metadata related operations")); - - api.addServersItem( - new io.swagger.v3.oas.models.servers.Server() - .description("Cineast API Address") - .url(config.getApiAddress()) - ); - - return api; - } + } diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/docs/GenerateOpenApiSpecs.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/docs/GenerateOpenApiSpecs.java index d541d5d34..008b5a4ea 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/docs/GenerateOpenApiSpecs.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/docs/GenerateOpenApiSpecs.java @@ -2,9 +2,8 @@ import java.io.IOException; import org.vitrivr.cineast.api.APIEndpoint; -import org.vitrivr.cineast.standalone.cli.CineastCli; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.standalone.config.Config; -import org.vitrivr.cineast.standalone.util.CLI; /** * Main class for standalone persistent openapi specs generation. @@ -32,7 +31,7 @@ public static void main(String[] args) { } try { - APIEndpoint.getInstance().writeOpenApiDocPersistently("docs/openapi.json"); // TODO use config? + OpenApiCompatHelper.writeOpenApiDocPersistently(APIEndpoint.getInstance(), "docs/openapi.json"); // TODO use config? } catch (IOException e) { e.printStackTrace(); } diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/OpenApiCompatHelper.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/OpenApiCompatHelper.java new file mode 100644 index 000000000..5680e3f77 --- /dev/null +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/OpenApiCompatHelper.java @@ -0,0 +1,149 @@ +package org.vitrivr.cineast.api.rest; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.javalin.plugin.openapi.OpenApiOptions; +import io.javalin.plugin.openapi.ui.ReDocOptions; +import io.javalin.plugin.openapi.ui.SwaggerOptions; +import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.util.Json; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.tags.Tag; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.vitrivr.cineast.api.APIEndpoint; +import org.vitrivr.cineast.standalone.config.APIConfig; + +import java.util.Arrays; +import java.util.List; + +/** + * Helper class for openapi compatibility. + * + * @author Loris Sauter + * @version 1.0 + */ +public class OpenApiCompatHelper { + + /** + * OpenAPI Specification tag for metadata related routes + */ + public static final String METADATA_OAS_TAG = "Metadata"; + public static final String SEGMENT_OAS_TAG = "Segment"; + + + public static final List OAS_TAGS = Arrays.asList( + new Tag().name(METADATA_OAS_TAG).description("Metadata related operations") + ); + private static final Logger LOGGER = LogManager.getLogger(); + + private OpenApiCompatHelper() { + /* A static helper class. */ + } + + /** + * Creates the Javalin options used to create an OpenAPI specification. + * + * @param config + * @return + */ + public static OpenApiOptions getJavalinOpenApiOptions(APIConfig config) { + //Default Javalin JSON mapper includes all null values and breaks spec json + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + return new OpenApiOptions(() -> getOpenApi(config)) + .path("/openapi-specs") + .activateAnnotationScanningFor("org.vitrivr.cineast.api") + // .toJsonMapper(new JacksonToJsonMapper()) + // .modelConverterFactory(new JacksonModelConverterFactory()) + .toJsonMapper(o -> { + try { + return mapper.writeValueAsString(o); + } catch (JsonProcessingException e) { + throw new RuntimeException("Couldn't serialise due to ", e); + } + }) + .modelConverterFactory(() -> new ModelResolver(mapper)) + .swagger(new SwaggerOptions("/swagger-ui").title("Swagger UI for Cineast Documentation")) + .reDoc(new ReDocOptions("/redoc").title("ReDoc for Cineast Documentation")); + } + + /** + * Creates the base {@link OpenAPI} specification. + * + * @param config + * @return + */ + public static OpenAPI getOpenApi(APIConfig config) { + OpenAPI api = new OpenAPI(); + + api.info( + new Info() + .title("Cineast RESTful API") + .description("Cineast is vitrivr's content-based multimedia retrieval engine. This is it's RESTful API.") + .version(APIEndpoint.VERSION) + .license( + new License() + .name("Apache 2.0") + .url("http://www.apache.org/licenses/LICENSE-2.0.html") + ) + .contact( + new Contact() + .name("Cineast Team") + .url("https://vitrivr.org") + .email("contact@vitrivr.org") + ) + ); + + api.addTagsItem( + new Tag() + .name(APIEndpoint.namespace()) + .description("Cineast Default") + ); + + /* Add the OAS tags */ + OAS_TAGS.forEach(api::addTagsItem); + + api.addServersItem( + new io.swagger.v3.oas.models.servers.Server() + .description("Cineast API Address") + .url(config.getApiAddress()) + ); + + return api; + } + + public static void writeOpenApiDocPersistently(APIEndpoint apiEndpoint, final String path) throws IOException { + try { + apiEndpoint.setHttp(apiEndpoint.dispatchService(false)); + if (apiEndpoint.getOpenApi() != null) { + String schema = Json.pretty(apiEndpoint.getOpenApi().getOpenApiHandler().createOpenAPISchema()); + File file = new File(path); + File folder = file.getParentFile(); + if (folder != null) { + folder.mkdirs(); + } + if (file.exists()) { + file.delete(); + } + try (FileOutputStream stream = new FileOutputStream( + file); PrintWriter writer = new PrintWriter(stream)) { + writer.print(schema); + writer.flush(); + } + LOGGER.info("Successfully stored openapi spec at {}", path); + } + } finally { + APIEndpoint.stop(); + } + } +} diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainGetHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainGetHandler.java index 48112dbfe..b24acd7f0 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainGetHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainGetHandler.java @@ -3,8 +3,8 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; @@ -51,7 +51,7 @@ public OpenApiDocumentation docs() { op.summary("Find metadata for specific object id in given domain"); op.description("Find metadata for specific object id in given domain"); op.operationId("findMetadataByDomain"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); }) .pathParam(DOMAIN_NAME, String.class, p -> p.description("The domain of the metadata to find")) .pathParam(OBJECT_ID_NAME, String.class, p -> p.description("The object id of the multimedia object to find metadata for")) diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainPostHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainPostHandler.java index 9ac5fc791..0a84ad794 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainPostHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByDomainPostHandler.java @@ -3,9 +3,9 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.lookup.IdList; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; @@ -60,7 +60,7 @@ public OpenApiDocumentation docs() { op.summary("Find metadata in the specified domain for all the given ids"); op.description("Find metadata in the specified domain for all the given ids"); op.operationId("findMetadataByDomainBatched"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); }) .pathParam(DOMAIN_NAME, String.class, p -> p.description("The domain of the metadata to find")) .body(inClass()) diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyGetHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyGetHandler.java index ee7b292f6..05d5ea18a 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyGetHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyGetHandler.java @@ -3,8 +3,8 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; @@ -43,7 +43,7 @@ public OpenApiDocumentation docs() { op.summary("Find metadata for a given object id with specified key"); op.description("Find metadata for a given object id with specified key"); op.operationId("findMetadataByKey"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); }) .pathParam(KEY_NAME, String.class, p -> p.description("The key of the metadata to find")) .pathParam(OBJECT_ID_NAME, String.class, p -> p.description("The object id of for which the metadata should be find")) diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyPostHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyPostHandler.java index 95a71d266..494ac0bbd 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyPostHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataByKeyPostHandler.java @@ -3,9 +3,9 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.lookup.IdList; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; @@ -51,7 +51,7 @@ public OpenApiDocumentation docs() { op.summary("Find metadata for a given object id with specified key"); op.description("Find metadata with a the speicifed key from the path across all domains and for the provided ids"); op.operationId("findMetadataByKeyBatched"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); }) .pathParam(KEY_NAME, String.class, p -> p.description("The key of the metadata to find")) .body(inClass()) diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataFullyQualifiedGetHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataFullyQualifiedGetHandler.java index 2b1a31a59..55597405f 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataFullyQualifiedGetHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataFullyQualifiedGetHandler.java @@ -3,8 +3,8 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; @@ -45,7 +45,7 @@ public OpenApiDocumentation docs() { .operation(op -> { op.description("The description"); op.summary("Find metadata for specific object id in given domain with given key"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); op.operationId("findMetaFullyQualified"); }) .pathParam(OBJECT_ID_NAME, String.class, param -> { diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataGetHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataGetHandler.java index faba080f0..eed7ff154 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataGetHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataGetHandler.java @@ -3,8 +3,8 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; @@ -41,7 +41,7 @@ public OpenApiDocumentation docs() { op.operationId("findMetaById"); op.description("Find metadata by the given object id"); op.summary("Find metadata for the given object id"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); }) .pathParam(OBJECT_ID_NAME, String.class, p -> p.description("The object id to find metadata of")) .json("200", outClass()); diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataPostHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataPostHandler.java index 26e377cda..b92766e2a 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataPostHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/metadata/FindObjectMetadataPostHandler.java @@ -3,10 +3,10 @@ import io.javalin.http.Context; import io.javalin.plugin.openapi.dsl.OpenApiBuilder; import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; -import org.vitrivr.cineast.api.APIEndpoint; import org.vitrivr.cineast.api.messages.components.AbstractMetadataFilterDescriptor; import org.vitrivr.cineast.api.messages.lookup.OptionallyFilteredIdList; import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult; +import org.vitrivr.cineast.api.rest.OpenApiCompatHelper; import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler; import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService; import org.vitrivr.cineast.core.data.entities.MediaObjectMetadataDescriptor; @@ -58,7 +58,7 @@ public OpenApiDocumentation docs() { op.description("Finds metadata for the given list of object ids"); op.summary("Finds metadata for the given list of object ids"); op.operationId("findMetadataForObjectIdBatched"); - op.addTagsItem(APIEndpoint.METADATA_OAS_TAG); + op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG); }) .body(inClass()) .json("200", outClass()); diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/routes/ResolvedContentRoute.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/routes/ResolvedContentRoute.java index 64e38bb9c..170ba3d2d 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/routes/ResolvedContentRoute.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/routes/ResolvedContentRoute.java @@ -1,15 +1,11 @@ package org.vitrivr.cineast.api.rest.routes; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.util.Map; - -import org.apache.commons.io.IOUtils; +import io.javalin.http.Context; +import io.javalin.http.Handler; import org.vitrivr.cineast.api.rest.resolvers.ResolutionResult; import org.vitrivr.cineast.api.rest.resolvers.Resolver; -import io.javalin.http.Context; -import io.javalin.http.Handler; +import java.util.Map; public class ResolvedContentRoute implements Handler { diff --git a/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/APIConfig.java b/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/APIConfig.java index 84f81ba52..8e83bb42e 100644 --- a/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/APIConfig.java +++ b/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/APIConfig.java @@ -1,8 +1,20 @@ package org.vitrivr.cineast.standalone.config; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; - +import org.vitrivr.cineast.core.data.entities.MediaObjectDescriptor; + +/** + * The API configuration for cineast. + * + * Settings regarding all aspects of the API are collected in this configuration. + * + * @author rgasser & Loris Sauter + * @version 2.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) public final class APIConfig { private boolean enableWebsocket = true; @@ -11,256 +23,287 @@ public final class APIConfig { private boolean enableRest = false; private boolean enableRestSecure = false; - private boolean enableGRPC = true; + private boolean enableGRPC = true; private String keystore; private String keystorePassword; - + private boolean enableRestLiveDoc = false; // Defaults to same result as enableRest private String apiAddress = "http://localhost:4567/"; - + private int httpPort = 4567; private int httpsPort = 4568; + private int grpcPort = 4570; + private int maxMessageSize = + 5120 * 1000; /* Maximum size of a single WebSocket message (binary or text). */ - private int grpcPort = 4570; - private int maxMessageSize = 5120 * 1000; /* Maximum size of a single WebSocket message (binary or text). */ + private boolean enableLegacy = false; + private int legacyPort = 12345; - private boolean enableLegacy = false; - private int legacyPort = 12345; + private boolean allowExtraction = true; + private boolean enableCLI = false; - private boolean allowExtraction = true; - private boolean enableCLI = false; + private int threadPoolSize = 8; - private int threadPoolSize = 8; + private boolean serveContent = false; - private boolean serveContent = false; - private boolean serveUI = false; - private String thumbnailLocation = ""; - private String objectLocation = ""; - private String uiLocation = ""; + /** + * A hack-flag to prevent the object serving using {@link MediaObjectDescriptor#getPath()} + * to find the actual media file. If this is true, the {@link MediaObjectDescriptor#getPath()}'s + * extension is appendet to {@link MediaObjectDescriptor#getObjectId()} and this is resolved + * to be directly under {@link #objectLocation}. + */ + private boolean objectsFilesAreIDed = false; - - @JsonCreator - public APIConfig() { - } - @JsonProperty - public boolean getEnableWebsocket() { - return this.enableWebsocket; - } + private boolean serveUI = false; + private String thumbnailLocation = ""; + private String objectLocation = ""; + private String uiLocation = ""; - public void setEnableWebsocket(boolean enableWebsocket) { - this.enableWebsocket = enableWebsocket; - } - @JsonProperty - public boolean getEnableWebsocketSecure() { - return this.enableWebsocketSecure; - } + @JsonCreator + public APIConfig() { + } - public void setEnableWebsocketSecure(boolean enableWebsocket) { - this.enableWebsocketSecure = enableWebsocket; - } + @JsonProperty + public boolean getEnableWebsocket() { + return this.enableWebsocket; + } - @JsonProperty - public boolean getEnableRest() { - return this.enableRest; - } + public void setEnableWebsocket(boolean enableWebsocket) { + this.enableWebsocket = enableWebsocket; + } - public void setEnableRest(boolean enableRest) { - this.enableRest = enableRest; - } + @JsonProperty + public boolean getEnableWebsocketSecure() { + return this.enableWebsocketSecure; + } - @JsonProperty - public boolean getEnableRestSecure() { - return this.enableRestSecure; - } + public void setEnableWebsocketSecure(boolean enableWebsocket) { + this.enableWebsocketSecure = enableWebsocket; + } - public void setEnableRestSecure(boolean enableRest) { - this.enableRestSecure = enableRest; - } + @JsonProperty + public boolean getEnableRest() { + return this.enableRest; + } + + public void setEnableRest(boolean enableRest) { + this.enableRest = enableRest; + } @JsonProperty - public boolean getEnableLiveDoc(){return this.enableRestLiveDoc;} - public void setEnableRestLiveDoc(boolean enableRestLiveDoc){this.enableRestLiveDoc = enableRestLiveDoc;} + public boolean getEnableRestSecure() { + return this.enableRestSecure; + } - @JsonProperty - public String getKeystore() { - return keystore; - } + public void setEnableRestSecure(boolean enableRest) { + this.enableRestSecure = enableRest; + } - public void setKeystore(String keystore) { - this.keystore = keystore; - } + @JsonProperty + public boolean getEnableLiveDoc() { + return this.enableRestLiveDoc; + } - @JsonProperty - public String getKeystorePassword() { - return keystorePassword; - } + public void setEnableRestLiveDoc(boolean enableRestLiveDoc) { + this.enableRestLiveDoc = enableRestLiveDoc; + } - public void setKeystorePassword(String keystorePassword) { - this.keystorePassword = keystorePassword; - } + @JsonProperty + public String getKeystore() { + return keystore; + } - @JsonProperty - public String getApiAddress() { - return apiAddress; - } + public void setKeystore(String keystore) { + this.keystore = keystore; + } - public void setApiAddress(String apiAddress) { - this.apiAddress = apiAddress; - } - - @JsonProperty - public int getHttpPort() { - return httpPort; - } + @JsonProperty + public String getKeystorePassword() { + return keystorePassword; + } - public void setHttpPort(int httpPort) { - if (httpPort < 1) { - throw new IllegalArgumentException("httpPort must be > 0"); - } - this.httpPort = httpPort; - } + public void setKeystorePassword(String keystorePassword) { + this.keystorePassword = keystorePassword; + } - @JsonProperty - public int getHttpsPort() { - return httpsPort; - } + @JsonProperty + public String getApiAddress() { + return apiAddress; + } - public void setHttpsPort(int httpsPort) { - if (httpsPort < 1) { - throw new IllegalArgumentException("httpPort must be > 0"); - } - this.httpsPort = httpsPort; - } + public void setApiAddress(String apiAddress) { + this.apiAddress = apiAddress; + } - @JsonProperty - public int getMaxMessageSize() { - return this.maxMessageSize; - } + @JsonProperty + public int getHttpPort() { + return httpPort; + } - public void setMaxMessageSize(int maxTextMessageSize) { - this.maxMessageSize = maxTextMessageSize; + public void setHttpPort(int httpPort) { + if (httpPort < 1) { + throw new IllegalArgumentException("httpPort must be > 0"); } + this.httpPort = httpPort; + } - @JsonProperty - public boolean getEnableLegacy() { - return enableLegacy; - } + @JsonProperty + public int getHttpsPort() { + return httpsPort; + } - public void setEnableLegacy(boolean enableLegacy) { - this.enableLegacy = enableLegacy; + public void setHttpsPort(int httpsPort) { + if (httpsPort < 1) { + throw new IllegalArgumentException("httpPort must be > 0"); } + this.httpsPort = httpsPort; + } - @JsonProperty - public int getLegacyPort() { - return legacyPort; - } + @JsonProperty + public int getMaxMessageSize() { + return this.maxMessageSize; + } - public void setLegacyPort(int legacyPort) { - this.legacyPort = legacyPort; - } + public void setMaxMessageSize(int maxTextMessageSize) { + this.maxMessageSize = maxTextMessageSize; + } - @JsonProperty - public boolean getAllowExtraction() { - return this.allowExtraction; - } + @JsonProperty + public boolean getEnableLegacy() { + return enableLegacy; + } - public void setAllowExtraction(boolean allowExtraction) { - this.allowExtraction = allowExtraction; - } + public void setEnableLegacy(boolean enableLegacy) { + this.enableLegacy = enableLegacy; + } - @JsonProperty - public boolean getEnableCli() { - return this.enableCLI; - } + @JsonProperty + public int getLegacyPort() { + return legacyPort; + } - public void setEnableCLI(boolean enableCLI) { - this.enableCLI = enableCLI; - } + public void setLegacyPort(int legacyPort) { + this.legacyPort = legacyPort; + } - @JsonProperty - public int getThreadPoolSize() { - return threadPoolSize; - } + @JsonProperty + public boolean getAllowExtraction() { + return this.allowExtraction; + } - @JsonProperty - public String getThumbnailLocation() { - return thumbnailLocation; - } + public void setAllowExtraction(boolean allowExtraction) { + this.allowExtraction = allowExtraction; + } - public void setThumbnailLocation(String thumbnailLocation) { - this.thumbnailLocation = thumbnailLocation; - } + @JsonProperty + public boolean getEnableCli() { + return this.enableCLI; + } - @JsonProperty - public String getObjectLocation() { - return objectLocation; - } + public void setEnableCLI(boolean enableCLI) { + this.enableCLI = enableCLI; + } - public void setObjectLocation(String objectLocation) { - this.objectLocation = objectLocation; - } + @JsonProperty + public int getThreadPoolSize() { + return threadPoolSize; + } - @JsonProperty - public String getUiLocation() { - return uiLocation; - } + public void setThreadPoolSize(int threadPoolSize) { + this.threadPoolSize = threadPoolSize; + } - public void setUiLocation(String uiLocation) { - this.uiLocation = uiLocation; - } + @JsonProperty + public String getThumbnailLocation() { + return thumbnailLocation; + } - public void setThreadPoolSize(int threadPoolSize) { - this.threadPoolSize = threadPoolSize; - } + public void setThumbnailLocation(String thumbnailLocation) { + this.thumbnailLocation = thumbnailLocation; + } - @JsonProperty - public boolean getServeContent() { - return this.serveContent; - } + @JsonProperty + public String getObjectLocation() { + return objectLocation; + } - public void setServeContent(boolean serveContent) { - this.serveContent = serveContent; - } + public void setObjectLocation(String objectLocation) { + this.objectLocation = objectLocation; + } - @JsonProperty - public boolean getServeUI() { - return this.serveUI; - } + @JsonProperty + public String getUiLocation() { + return uiLocation; + } - public void setServeUI(boolean serveUI) { - this.serveUI = serveUI; - } + public void setUiLocation(String uiLocation) { + this.uiLocation = uiLocation; + } - @JsonProperty - public boolean getEnableExtractionServer() { - return enableExtractionServer; - } + @JsonProperty + public boolean getServeContent() { + return this.serveContent; + } - public void setEnableExtractionServer(boolean enableExtractionServer) { - this.enableExtractionServer = enableExtractionServer; - } + public void setServeContent(boolean serveContent) { + this.serveContent = serveContent; + } + + @JsonProperty + public boolean getServeUI() { + return this.serveUI; + } + + public void setServeUI(boolean serveUI) { + this.serveUI = serveUI; + } + + @JsonProperty + public boolean getEnableExtractionServer() { + return enableExtractionServer; + } + + public void setEnableExtractionServer(boolean enableExtractionServer) { + this.enableExtractionServer = enableExtractionServer; + } - @JsonProperty - public boolean getEnableGRPC() { - return enableGRPC; - } - - @JsonProperty - public void setEnableGRPC(boolean enableGRPC) { - this.enableGRPC = enableGRPC; - } - - @JsonProperty - public int getGrpcPort() { - return grpcPort; - } - - @JsonProperty - public void setGrpcPort(int grpcPort) { - this.grpcPort = grpcPort; - } + @JsonProperty + public boolean getEnableGRPC() { + return enableGRPC; + } + + @JsonProperty + public void setEnableGRPC(boolean enableGRPC) { + this.enableGRPC = enableGRPC; + } + + @JsonProperty + public int getGrpcPort() { + return grpcPort; + } + + @JsonProperty + public void setGrpcPort(int grpcPort) { + this.grpcPort = grpcPort; + } + + /** + * A hack-flag to prevent the object serving using {@link MediaObjectDescriptor#getPath()} + * to find the actual media file. If this is true, the {@link MediaObjectDescriptor#getPath()}'s + * extension is appendet to {@link MediaObjectDescriptor#getObjectId()} and this is resolved + * to be directly under {@link #objectLocation}. + */ + @JsonProperty + public boolean isObjectsFilesAreIDed(){ + return objectsFilesAreIDed; + } + + @JsonProperty + public void setObjectsFilesAreIDed(boolean b){ + objectsFilesAreIDed = b; + } } diff --git a/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/util/CLI.java b/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/util/CLI.java index 9fed7f98f..ea29c1657 100644 --- a/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/util/CLI.java +++ b/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/util/CLI.java @@ -32,7 +32,7 @@ public class CLI { private static final String PROMPT = "cineast> "; - private static final String LOGO = "################################################################################\u0085#                                                                              #\u0085#                @@@                           @@@                             #\u0085#                @@@                           @@@                             #\u0085#                     @@@@                                                     #\u0085#   @@@     @@@  @@@  @@@@@@@         @@@@@    @@@  &@@     @@@     @@@@@      #\u0085#   @@@@( (@@@@  @@@( @@@@@@@      %@@@@@@@@@ ,@@@( @@@@( (@@@@  @@@@@@@@@@    #\u0085#    (@@@@@@@(   @@@( @@@@   (@@@  @@@@       ,@@@(  (@@@@@@@(   @@@(          #\u0085#      @@@@@     @@@(  @@@@@@@@@@  @@@@       ,@@@(    @@@@@     @@@(          #\u0085#       @@@      @@@     @@@@@*    @@@         @@@      @@@      @@@           #\u0085#                                                                              #\u0085################################################################################"; + private static final String LOGO = "################################################################################\u0085#                                                                              #\u0085#                @@@                           @@@                             #\u0085#                @@@                           @@@                             #\u0085#                     @@@@                                                     #\u0085#   @@@     @@@  @@@  @@@@@@@         @@@@@    @@@  @@@     @@@     @@@@@      #\u0085#   @@@@   @@@@  @@@  @@@@          @@@@@@@@@  @@@  @@@@   @@@@   @@@@@@@@@    #\u0085#     @@@@@@@    @@@  @@@@    @@@  @@@@        @@@    @@@@@@@    @@@@          #\u0085#      @@@@@     @@@   @@@@@@@@@@  @@@@        @@@     @@@@@     @@@@          #\u0085#       @@@      @@@     @@@@@     @@@         @@@      @@@      @@@           #\u0085#                                                                              #\u0085################################################################################"; private CLI() { }