From 280d86e3338aa026fb4f6562cc65a94fbed08dc6 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Sun, 5 May 2024 12:33:33 +0200 Subject: [PATCH] [FEAT] add a minimum sample (Not tested) --- sample/archidata/basic/WebLauncher.java | 126 ++++++++++++++++++ sample/archidata/basic/WebLauncherLocal.java | 45 +++++++ .../archidata/basic/api/MyModelResource.java | 79 +++++++++++ .../basic/migration/Initialization.java | 28 ++++ sample/archidata/basic/model/MyModel.java | 36 +++++ 5 files changed, 314 insertions(+) create mode 100755 sample/archidata/basic/WebLauncher.java create mode 100755 sample/archidata/basic/WebLauncherLocal.java create mode 100644 sample/archidata/basic/api/MyModelResource.java create mode 100644 sample/archidata/basic/migration/Initialization.java create mode 100644 sample/archidata/basic/model/MyModel.java diff --git a/sample/archidata/basic/WebLauncher.java b/sample/archidata/basic/WebLauncher.java new file mode 100755 index 0000000..ab08261 --- /dev/null +++ b/sample/archidata/basic/WebLauncher.java @@ -0,0 +1,126 @@ +package sample.archidata.basic; + +import java.net.URI; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.UpdateJwtPublicKey; +import org.kar.archidata.api.DataResource; +import org.kar.archidata.catcher.ExceptionCatcher; +import org.kar.archidata.catcher.FailExceptionCatcher; +import org.kar.archidata.catcher.InputExceptionCatcher; +import org.kar.archidata.catcher.SystemExceptionCatcher; +import org.kar.archidata.db.DBConfig; +import org.kar.archidata.filter.CORSFilter; +import org.kar.archidata.filter.OptionFilter; +import org.kar.archidata.migration.MigrationEngine; +import org.kar.archidata.tools.ConfigBaseVariable; +import sample.archidata.basic.api.Front; +import sample.archidata.basic.api.HealthCheck; +import sample.archidata.basic.api.MediaResource; +import sample.archidata.basic.api.SeasonResource; +import sample.archidata.basic.api.SeriesResource; +import sample.archidata.basic.api.TypeResource; +import sample.archidata.basic.api.UserMediaAdvancementResource; +import sample.archidata.basic.api.UserResource; +import sample.archidata.basic.filter.KarideoAuthenticationFilter; +import sample.archidata.basic.migration.Initialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.UriBuilder; + +public class WebLauncher { + final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class); + public static DBConfig dbConfig; + protected UpdateJwtPublicKey keyUpdater = null; + protected HttpServer server = null; + + public WebLauncher() { + ConfigBaseVariable.bdDatabase = "sample_archidata_basic"; + } + + private static URI getBaseURI() { + return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build(); + } + + public void migrateDB() throws Exception { + WebLauncher.LOGGER.info("Create migration engine"); + final MigrationEngine migrationEngine = new MigrationEngine(); + WebLauncher.LOGGER.info("Add initialization"); + migrationEngine.setInit(new Initialization()); + //WebLauncher.LOGGER.info("Add migration since last version"); + //migrationEngine.add(new Migration20230810()); + WebLauncher.LOGGER.info("Migrate the DB [START]"); + migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig); + WebLauncher.LOGGER.info("Migrate the DB [STOP]"); + } + + public static void main(final String[] args) throws Exception { + WebLauncher.LOGGER.info("[START] application wake UP"); + final WebLauncher launcher = new WebLauncher(); + launcher.migrateDB(); + launcher.process(); + WebLauncher.LOGGER.info("end-configure the server & wait finish process:"); + Thread.currentThread().join(); + WebLauncher.LOGGER.info("STOP the REST server"); + } + + public void process() throws InterruptedException { + + // =================================================================== + // Configure resources + // =================================================================== + final ResourceConfig rc = new ResourceConfig(); + + // Permit to accept OPTION request + rc.register(OptionFilter.class); + // remove cors ==> not obviously needed ... + rc.register(CORSFilter.class); + // register exception catcher (this permit to format return error with a normalized JSON) + rc.register(InputExceptionCatcher.class); + rc.register(SystemExceptionCatcher.class); + rc.register(FailExceptionCatcher.class); + rc.register(ExceptionCatcher.class); + + // add default resource: + rc.register(MyModelResource.class); + + + // add jackson to be discover when we are in stand-alone server + rc.register(JacksonFeature.class); + + this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc); + final HttpServer serverLink = this.server; + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Stopping server.."); + serverLink.shutdownNow(); + } + }, "shutdownHook")); + + + // =================================================================== + // run JERSEY + // =================================================================== + try { + this.server.start(); + LOGGER.info("Jersey app started at {}", getBaseURI()); + } catch (final Exception e) { + LOGGER.error("There was an error while starting Grizzly HTTP server."); + e.printStackTrace(); + } + } + // This is used for TEST (See it later) + public void stop() { + if (this.server != null) { + this.server.shutdownNow(); + this.server = null; + } + } +} diff --git a/sample/archidata/basic/WebLauncherLocal.java b/sample/archidata/basic/WebLauncherLocal.java new file mode 100755 index 0000000..4f97232 --- /dev/null +++ b/sample/archidata/basic/WebLauncherLocal.java @@ -0,0 +1,45 @@ + +package sample.archidata.basic; + +import java.util.List; + +import org.kar.archidata.api.DataResource; +import org.kar.archidata.dataAccess.DataFactoryTsApi; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebLauncherLocal extends WebLauncher { + private final static Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class); + + private WebLauncherLocal() {} + + public static void main(final String[] args) throws Exception { + final WebLauncherLocal launcher = new WebLauncherLocal(); + launcher.process(); + LOGGER.info("end-configure the server & wait finish process:"); + Thread.currentThread().join(); + LOGGER.info("STOP the REST server:"); + } + + @Override + public void process() throws InterruptedException { + if (true) { + // for local test: + ConfigBaseVariable.apiAddress = "http://0.0.0.0:9000/sample/api/"; + ConfigBaseVariable.dbPort = "3906"; + } + try { + super.migrateDB(); + } catch (final Exception e) { + e.printStackTrace(); + while (true) { + LOGGER.error("============================================================================"); + LOGGER.error("== Migration fail ==> waiting intervention of administrator..."); + LOGGER.error("============================================================================"); + Thread.sleep(60 * 60 * 1000); + } + } + super.process(); + } +} diff --git a/sample/archidata/basic/api/MyModelResource.java b/sample/archidata/basic/api/MyModelResource.java new file mode 100644 index 0000000..3dd050b --- /dev/null +++ b/sample/archidata/basic/api/MyModelResource.java @@ -0,0 +1,79 @@ +package sample.archidata.basic.api; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.kar.archidata.annotation.AsyncType; +import org.kar.archidata.annotation.TypeScriptProgress; +import org.kar.archidata.api.DataResource; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.addOn.AddOnDataJson; +import org.kar.archidata.exception.FailException; +import org.kar.archidata.exception.InputException; +import org.kar.archidata.model.Data; +import org.kar.archidata.tools.DataTools; +import sample.archidata.basic.model.MyModel; +import sample.archidata.basic.model.Season; +import sample.archidata.basic.model.Series; +import sample.archidata.basic.model.Type; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.swagger.v3.oas.annotations.Operation; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MyModelType; + +@Path("/media") +@Produces(MyModelType.APPLICATION_JSON) +public class MyModelResource { + + @GET + @PermitAll + public List gets() throws Exception { + return DataAccess.gets(MyModel.class); + } + + @POST + @PermitAll + @Consumes(MyModelType.APPLICATION_JSON) + public MyModel create(final MyModel data) throws Exception { + return DataAccess.insert(data); + } + + @GET + @Path("{id}") + @PermitAll + public MyModel get(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(MyModel.class, id); + } + + + @PATCH + @Path("{id}") + @PermitAll + @Consumes(MyModelType.APPLICATION_JSON) + public MyModel patch(@PathParam("id") final Long id, final String jsonRequest) throws Exception { + DataAccess.updateWithJson(MyModel.class, id, jsonRequest); + return DataAccess.get(MyModel.class, id); + } + + @DELETE + @Path("{id}") + @PermitAll + public void remove(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(MyModel.class, id); + } +} diff --git a/sample/archidata/basic/migration/Initialization.java b/sample/archidata/basic/migration/Initialization.java new file mode 100644 index 0000000..8b5a71e --- /dev/null +++ b/sample/archidata/basic/migration/Initialization.java @@ -0,0 +1,28 @@ +package sample.archidata.basic.migration; + +import java.util.List; + +import org.kar.archidata.migration.MigrationSqlStep; +import sample.archidata.basic.model.MyModel; + +public class Initialization extends MigrationSqlStep { + public static final List> CLASSES_BASE = List.of(MyModel.class); + @Override + public String getName() { + return "Initialization"; + } + + @Override + public void generateStep() throws Exception { + for(final Class clazz : CLASSES_BASE) { + addClass(clazz); + } + + addAction(""" + ALTER TABLE `MyModel` AUTO_INCREMENT = 1000; + """, + // Only MySql support this request (fail in SQLite) + "mysql"); + } + +} diff --git a/sample/archidata/basic/model/MyModel.java b/sample/archidata/basic/model/MyModel.java new file mode 100644 index 0000000..420d7d2 --- /dev/null +++ b/sample/archidata/basic/model/MyModel.java @@ -0,0 +1,36 @@ +package sample.archidata.basic.model; + +import java.util.List; +import java.util.UUID; + +import org.kar.archidata.annotation.DataJson; +import org.kar.archidata.model.Data; +import org.kar.archidata.model.GenericDataSoftDelete; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +// needed for Swagger interface +@Entity +// Do not generate Null in Json serialization ==> prefer undefined +@JsonInclude(JsonInclude.Include.NON_NULL) +public class MyModel extends GenericDataSoftDelete { + // Can not be NULL and max length is 300 (note default is 255) + @Column(nullable = false, length = 300) + public String name; + // Can be null and no max length + @Column(length = 0) + public String description; + + @Override + public String toString() { + return "MyModel [name=" + this.name + ", description=" + this.description + "]"; + } + + +}