From bc11fa61d4a1e8903ec01f01c46f7e217713334d Mon Sep 17 00:00:00 2001 From: Dominick Leppich Date: Fri, 25 Oct 2024 08:03:41 +0200 Subject: [PATCH 1/3] version: set to version 1.1.7-SNAPSHOT --- module-core/pom.xml | 4 ++-- module-exchange/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module-core/pom.xml b/module-core/pom.xml index 05423d6..324dd5b 100644 --- a/module-core/pom.xml +++ b/module-core/pom.xml @@ -10,7 +10,7 @@ io.goobi.vocabulary vocabulary-server-core - 1.1.6 + 1.1.7-SNAPSHOT Vocabulary-Server-Core Spring Boot based RESTful web service for vocabulary management jar @@ -26,7 +26,7 @@ io.goobi.vocabulary vocabulary-server-exchange - 1.1.6 + 1.1.7-SNAPSHOT compile diff --git a/module-exchange/pom.xml b/module-exchange/pom.xml index bda10a1..1403784 100644 --- a/module-exchange/pom.xml +++ b/module-exchange/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.goobi.vocabulary vocabulary-server-exchange - 1.1.6 + 1.1.7-SNAPSHOT Vocabulary Exchange Vocabulary data exchange classes jar diff --git a/pom.xml b/pom.xml index 27b1769..f04f7e5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.goobi.vocabulary vocabulary-server - 1.1.6 + 1.1.7-SNAPSHOT Vocabulary-Server pom RESTful webservice for vocabulary management From e979ddc953118fb207a75f58d05439c0837a699c Mon Sep 17 00:00:00 2001 From: Dominick Leppich Date: Fri, 25 Oct 2024 10:48:10 +0200 Subject: [PATCH 2/3] task: monitoring endpoint and self-check refactorings --- module-core/pom.xml | 44 +++++++ .../vocabulary/api/MaintenanceController.java | 13 +- .../vocabulary/api/MonitoringController.java | 25 ++++ .../maintenance/FlywayInformation.java | 6 + .../maintenance/ManifestReader.java | 36 ++++++ .../maintenance/MonitoringResult.java | 6 + .../maintenance/MonitoringState.java | 4 + .../maintenance/VersionInformation.java | 4 + .../maintenance/VersionsCollection.java | 4 + .../selfcheck/SelfCheckResult.java | 9 ++ .../selfcheck/ValidationResult.java | 6 + .../service/manager/MaintenanceManager.java | 116 ++++++++++++++---- 12 files changed, 238 insertions(+), 35 deletions(-) create mode 100644 module-core/src/main/java/io/goobi/vocabulary/api/MonitoringController.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/FlywayInformation.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/ManifestReader.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringResult.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringState.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionInformation.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionsCollection.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/SelfCheckResult.java create mode 100644 module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/ValidationResult.java diff --git a/module-core/pom.xml b/module-core/pom.xml index 324dd5b..cb4ebee 100644 --- a/module-core/pom.xml +++ b/module-core/pom.xml @@ -20,8 +20,17 @@ UTF-8 + + yyyy-MM-dd HH:mm:ss + ${maven.build.timestamp} + + 5.2.5 + + scm:git:https://github.com/intranda/goobi-vocabulary-server + scm:git:https://github.com/intranda/goobi-vocabulary-server + io.goobi.vocabulary @@ -162,6 +171,41 @@ + + + org.codehaus.mojo + buildnumber-maven-plugin + 1.4 + + + validate + + create + + + + + 7 + false + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + ${project.name} + ${buildDate} + ${project.version} + ${buildNumber} + + + + + + maven-compiler-plugin diff --git a/module-core/src/main/java/io/goobi/vocabulary/api/MaintenanceController.java b/module-core/src/main/java/io/goobi/vocabulary/api/MaintenanceController.java index f1303a6..0cc0249 100644 --- a/module-core/src/main/java/io/goobi/vocabulary/api/MaintenanceController.java +++ b/module-core/src/main/java/io/goobi/vocabulary/api/MaintenanceController.java @@ -1,7 +1,7 @@ package io.goobi.vocabulary.api; +import io.goobi.vocabulary.maintenance.selfcheck.SelfCheckResult; import io.goobi.vocabulary.service.manager.MaintenanceManager; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -16,14 +16,7 @@ public MaintenanceController(MaintenanceManager maintenanceManager) { } @GetMapping("/selfcheck") - public ResponseEntity selfCheck() { - String status = maintenanceManager.testAllData(); - if (status.contains("FAIL")) { - return ResponseEntity.internalServerError() - .body(status); - } else { - return ResponseEntity.ok() - .body(status); - } + public SelfCheckResult selfCheck() { + return maintenanceManager.performFullSelfCheck(); } } diff --git a/module-core/src/main/java/io/goobi/vocabulary/api/MonitoringController.java b/module-core/src/main/java/io/goobi/vocabulary/api/MonitoringController.java new file mode 100644 index 0000000..9c498ea --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/api/MonitoringController.java @@ -0,0 +1,25 @@ +package io.goobi.vocabulary.api; + +import io.goobi.vocabulary.maintenance.MonitoringResult; +import io.goobi.vocabulary.service.manager.MaintenanceManager; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/api/v1") +public class MonitoringController { + private final MaintenanceManager maintenanceManager; + + public MonitoringController(MaintenanceManager maintenanceManager) { + this.maintenanceManager = maintenanceManager; + } + + @GetMapping("/monitoring") + public MonitoringResult monitoring() { + return maintenanceManager.getMonitoringResult(); + } + +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/FlywayInformation.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/FlywayInformation.java new file mode 100644 index 0000000..d7c8b9f --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/FlywayInformation.java @@ -0,0 +1,6 @@ +package io.goobi.vocabulary.maintenance; + +import java.util.Date; + +public record FlywayInformation(String schemaVersion, String description, Date date, int executionTime, boolean success) { +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/ManifestReader.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/ManifestReader.java new file mode 100644 index 0000000..a0d860b --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/ManifestReader.java @@ -0,0 +1,36 @@ +package io.goobi.vocabulary.maintenance; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.Optional; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +@Getter +@Service +public class ManifestReader { + private final Manifest manifest; + + private final String revision; + private final String version; + private final String buildDate; + + public ManifestReader() throws IllegalArgumentException, IOException { + manifest = new Manifest(getClass().getResourceAsStream("/META-INF/MANIFEST.MF")); + Attributes mainAttributes = manifest.getMainAttributes(); + revision = getOptionalValue(mainAttributes, "Revision").orElse("unknown"); + version = getOptionalValue(mainAttributes, "Version").orElse("unknown"); + buildDate = getOptionalValue(mainAttributes, "Build-Date").orElse("unknown"); + } + + private Optional getOptionalValue(Attributes attributes, String attributeName) throws IllegalArgumentException { + String result = attributes.getValue(attributeName); + if (StringUtils.isBlank(result)) { + result = null; + } + return Optional.ofNullable(result); + } +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringResult.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringResult.java new file mode 100644 index 0000000..5da4e48 --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringResult.java @@ -0,0 +1,6 @@ +package io.goobi.vocabulary.maintenance; + +import io.goobi.vocabulary.maintenance.selfcheck.SelfCheckResult; + +public record MonitoringResult(MonitoringState monitoring, VersionsCollection versions, FlywayInformation flyway, SelfCheckResult selfCheck) { +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringState.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringState.java new file mode 100644 index 0000000..a42d3de --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/MonitoringState.java @@ -0,0 +1,4 @@ +package io.goobi.vocabulary.maintenance; + +public record MonitoringState(String database, String selfCheck) { +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionInformation.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionInformation.java new file mode 100644 index 0000000..cd9aafd --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionInformation.java @@ -0,0 +1,4 @@ +package io.goobi.vocabulary.maintenance; + +public record VersionInformation(String version, String hash) { +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionsCollection.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionsCollection.java new file mode 100644 index 0000000..c8b537d --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/VersionsCollection.java @@ -0,0 +1,4 @@ +package io.goobi.vocabulary.maintenance; + +public record VersionsCollection(VersionInformation core) { +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/SelfCheckResult.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/SelfCheckResult.java new file mode 100644 index 0000000..8d7f2a9 --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/SelfCheckResult.java @@ -0,0 +1,9 @@ +package io.goobi.vocabulary.maintenance.selfcheck; + +import java.util.Date; + +public record SelfCheckResult(Date date, ValidationResult types, ValidationResult vocabularies, ValidationResult schemas, ValidationResult records) { + public boolean success() { + return types.errors().isEmpty() && vocabularies.errors().isEmpty() && schemas.errors().isEmpty() && records.errors().isEmpty(); + } +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/ValidationResult.java b/module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/ValidationResult.java new file mode 100644 index 0000000..1c87522 --- /dev/null +++ b/module-core/src/main/java/io/goobi/vocabulary/maintenance/selfcheck/ValidationResult.java @@ -0,0 +1,6 @@ +package io.goobi.vocabulary.maintenance.selfcheck; + +import java.util.List; + +public record ValidationResult(List errors) { +} diff --git a/module-core/src/main/java/io/goobi/vocabulary/service/manager/MaintenanceManager.java b/module-core/src/main/java/io/goobi/vocabulary/service/manager/MaintenanceManager.java index abfc4e5..fde262b 100644 --- a/module-core/src/main/java/io/goobi/vocabulary/service/manager/MaintenanceManager.java +++ b/module-core/src/main/java/io/goobi/vocabulary/service/manager/MaintenanceManager.java @@ -1,6 +1,15 @@ package io.goobi.vocabulary.service.manager; +import com.fasterxml.jackson.databind.ObjectMapper; import io.goobi.vocabulary.exception.VocabularyException; +import io.goobi.vocabulary.maintenance.FlywayInformation; +import io.goobi.vocabulary.maintenance.ManifestReader; +import io.goobi.vocabulary.maintenance.MonitoringResult; +import io.goobi.vocabulary.maintenance.MonitoringState; +import io.goobi.vocabulary.maintenance.VersionInformation; +import io.goobi.vocabulary.maintenance.VersionsCollection; +import io.goobi.vocabulary.maintenance.selfcheck.SelfCheckResult; +import io.goobi.vocabulary.maintenance.selfcheck.ValidationResult; import io.goobi.vocabulary.model.jpa.FieldTypeEntity; import io.goobi.vocabulary.model.jpa.VocabularyEntity; import io.goobi.vocabulary.model.jpa.VocabularyRecordEntity; @@ -10,14 +19,23 @@ import io.goobi.vocabulary.repositories.VocabularyRepository; import io.goobi.vocabulary.repositories.VocabularySchemaRepository; import io.goobi.vocabulary.validation.Validator; +import lombok.extern.slf4j.Slf4j; +import org.flywaydb.core.Flyway; import org.springframework.data.repository.ListCrudRepository; import org.springframework.stereotype.Service; +import java.io.File; +import java.io.IOException; +import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Optional; +@Slf4j @Service public class MaintenanceManager { + public static final File SELF_CHECK_CACHE_FILE = new File("/tmp/vocabulary-server-self-check.json"); + private final FieldTypeRepository fieldTypeRepository; private final VocabularyRepository vocabularyRepository; private final VocabularySchemaRepository vocabularySchemaRepository; @@ -28,7 +46,12 @@ public class MaintenanceManager { private final Validator vocabularySchemaValidator; private final Validator vocabularyRecordValidator; - public MaintenanceManager(FieldTypeRepository fieldTypeRepository, VocabularyRepository vocabularyRepository, VocabularySchemaRepository vocabularySchemaRepository, VocabularyRecordRepository vocabularyRecordRepository, Validator fieldTypeValidator, Validator vocabularyValidator, Validator vocabularySchemaValidator, Validator vocabularyRecordValidator) { + private final ManifestReader manifestReader; + private final Flyway flyway; + + private final ObjectMapper objectMapper; + + public MaintenanceManager(FieldTypeRepository fieldTypeRepository, VocabularyRepository vocabularyRepository, VocabularySchemaRepository vocabularySchemaRepository, VocabularyRecordRepository vocabularyRecordRepository, Validator fieldTypeValidator, Validator vocabularyValidator, Validator vocabularySchemaValidator, Validator vocabularyRecordValidator, ManifestReader manifestReader, Flyway flyway, ObjectMapper objectMapper) { this.fieldTypeRepository = fieldTypeRepository; this.vocabularyRepository = vocabularyRepository; this.vocabularyValidator = vocabularyValidator; @@ -37,47 +60,90 @@ public MaintenanceManager(FieldTypeRepository fieldTypeRepository, VocabularyRep this.fieldTypeValidator = fieldTypeValidator; this.vocabularySchemaValidator = vocabularySchemaValidator; this.vocabularyRecordValidator = vocabularyRecordValidator; + this.manifestReader = manifestReader; + this.flyway = flyway; + this.objectMapper = objectMapper; } - public String testAllData() { - List selfCheckResults = new LinkedList<>(); + public SelfCheckResult performFullSelfCheck() { + ValidationResult types = new ValidationResult(selfTest(fieldTypeRepository, fieldTypeValidator)); + ValidationResult vocabularies = new ValidationResult(selfTest(vocabularyRepository, vocabularyValidator)); + ValidationResult vocabularySchemas = new ValidationResult(selfTest(vocabularySchemaRepository, vocabularySchemaValidator)); + ValidationResult vocabularyRecords = new ValidationResult(selfTest(vocabularyRecordRepository, vocabularyRecordValidator)); - selfCheckResults.add(selfTest("Types", fieldTypeRepository, fieldTypeValidator)); - selfCheckResults.add(selfTest("Vocabularies", vocabularyRepository, vocabularyValidator)); - selfCheckResults.add(selfTest("Vocabulary Schemas", vocabularySchemaRepository, vocabularySchemaValidator)); - selfCheckResults.add(selfTest("Vocabulary Records", vocabularyRecordRepository, vocabularyRecordValidator)); - - return String.join("\n", selfCheckResults); + SelfCheckResult result = new SelfCheckResult(new Date(), types, vocabularies, vocabularySchemas, vocabularyRecords); + saveSelfCheckResult(result); + return result; } - - private String selfTest(String entityName, ListCrudRepository repo, Validator validator) { + private List selfTest(ListCrudRepository repo, Validator validator) { List errors = new LinkedList<>(); for (Entity entity : repo.findAll()) { try { validator.validate(entity); } catch (VocabularyException e) { - errors.add(dumpException(e, 1)); + StringBuilder s = new StringBuilder(); + dumpException(s, e); + errors.add(s.toString()); } } - if (errors.isEmpty()) { - return entityName + ": OK"; - } else { - return entityName + ": FAIL" - + String.join("", errors); - } + return errors; } - private String dumpException(VocabularyException ex, int level) { - StringBuilder s = new StringBuilder(); - s.append('\n') - .append("\t".repeat(level)) - .append(ex.getMessage()); + private void dumpException(StringBuilder s, VocabularyException ex) { + s.append(ex.getMessage()); if (ex.getCauses() != null) { for (VocabularyException c : ex.getCauses()) { - s.append(dumpException(c, level + 1)); + s.append("; "); + dumpException(s, c); } } - return s.toString(); + } + + public MonitoringResult getMonitoringResult() { + VersionInformation coreVersion = new VersionInformation(manifestReader.getVersion(), manifestReader.getRevision()); + VersionsCollection versions = new VersionsCollection(coreVersion); + FlywayInformation flywayInformation = getFlywayInformation(); + Optional selfCheckResult = loadSelfCheckResult(); + MonitoringState monitoringState = getMonitoringState(flywayInformation, selfCheckResult); + return new MonitoringResult(monitoringState, versions, flywayInformation, selfCheckResult.orElse(null)); + } + + private MonitoringState getMonitoringState(FlywayInformation flywayInformation, Optional selfCheckStatus) { + String database = flywayInformation.success() ? "ok" : "error"; + String selfCheck = "unknown"; + if (selfCheckStatus.isPresent()) { + selfCheck = selfCheckStatus.get().success() ? "ok" : "error"; + } + return new MonitoringState(database, selfCheck); + } + + private FlywayInformation getFlywayInformation() { + String version = flyway.info().current().getVersion().getVersion(); + String description = flyway.info().current().getDescription(); + Date date = flyway.info().current().getInstalledOn(); + int executionTime = flyway.info().current().getExecutionTime(); + boolean success = flyway.info().current().getState().isApplied(); + return new FlywayInformation(version, description, date, executionTime, success); + } + + private void saveSelfCheckResult(SelfCheckResult result) { + try { + objectMapper.writeValue(SELF_CHECK_CACHE_FILE, result); + } catch (IOException e) { + log.error("Error saving self-check result", e); + } + } + + private Optional loadSelfCheckResult() { + if (!MaintenanceManager.SELF_CHECK_CACHE_FILE.exists()) { + return Optional.empty(); + } + try { + return Optional.of(objectMapper.readValue(MaintenanceManager.SELF_CHECK_CACHE_FILE, SelfCheckResult.class)); + } catch (IOException e) { + log.error("Error reading cached self-check results", e); + return Optional.empty(); + } } } From dd1af1a55740e4007280c60c24a2cf29a89bf9da Mon Sep 17 00:00:00 2001 From: Dominick Leppich Date: Fri, 25 Oct 2024 10:50:29 +0200 Subject: [PATCH 3/3] version: set to version 1.1.7 --- module-core/pom.xml | 4 ++-- module-exchange/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module-core/pom.xml b/module-core/pom.xml index cb4ebee..f0c0172 100644 --- a/module-core/pom.xml +++ b/module-core/pom.xml @@ -10,7 +10,7 @@ io.goobi.vocabulary vocabulary-server-core - 1.1.7-SNAPSHOT + 1.1.7 Vocabulary-Server-Core Spring Boot based RESTful web service for vocabulary management jar @@ -35,7 +35,7 @@ io.goobi.vocabulary vocabulary-server-exchange - 1.1.7-SNAPSHOT + 1.1.7 compile diff --git a/module-exchange/pom.xml b/module-exchange/pom.xml index 1403784..de5135d 100644 --- a/module-exchange/pom.xml +++ b/module-exchange/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.goobi.vocabulary vocabulary-server-exchange - 1.1.7-SNAPSHOT + 1.1.7 Vocabulary Exchange Vocabulary data exchange classes jar diff --git a/pom.xml b/pom.xml index f04f7e5..dc5e9d9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.goobi.vocabulary vocabulary-server - 1.1.7-SNAPSHOT + 1.1.7 Vocabulary-Server pom RESTful webservice for vocabulary management