From e821c22504ba5aa03ec5886624d7bbfaeb8e5e83 Mon Sep 17 00:00:00 2001 From: anhefti Date: Thu, 7 Mar 2024 10:28:47 +0100 Subject: [PATCH] SEBSERV-455 --- .../webservice/DBIntegrityChecker.java | 5 + .../sebserver/webservice/WebserviceInit.java | 4 +- .../webservice/WebserviceInitException.java | 12 + .../checks/DowngradeSEBSettingsCheck.java | 138 +++++++ .../impl/ConfigurationAttributeDAOImpl.java | 29 -- .../config/application-dev-ws.properties | 4 +- .../config/examConfigAttrVersionTable | 348 ------------------ 7 files changed, 160 insertions(+), 380 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInitException.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/DowngradeSEBSettingsCheck.java delete mode 100644 src/main/resources/config/examConfigAttrVersionTable diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/DBIntegrityChecker.java b/src/main/java/ch/ethz/seb/sebserver/webservice/DBIntegrityChecker.java index 2e3d0768..b12f3058 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/DBIntegrityChecker.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/DBIntegrityChecker.java @@ -60,11 +60,16 @@ public class DBIntegrityChecker { final Result applyCheck = dbIntegrityCheck.applyCheck(this.tryFix); if (applyCheck.hasError()) { + if (applyCheck.getError() instanceof WebserviceInitException) { + throw applyCheck.getError(); + } SEBServerInit.INIT_LOGGER.info("--------> Unexpected Error: {}", applyCheck.getError().getMessage()); } else { SEBServerInit.INIT_LOGGER.info("--------> Result: {}", applyCheck.get()); } + } catch (final WebserviceInitException initE) { + throw initE; } catch (final Exception e) { log.error("Unexpected error while trying to apply data base integrity check: {}", dbIntegrityCheck); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java index 1086b3ec..2f87a1b3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java @@ -99,10 +99,10 @@ public class WebserviceInit implements ApplicationListener *********************************************************"); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInitException.java b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInitException.java new file mode 100644 index 00000000..bd17a090 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInitException.java @@ -0,0 +1,12 @@ +package ch.ethz.seb.sebserver.webservice; + +public class WebserviceInitException extends RuntimeException { + + public WebserviceInitException(final String message) { + super(message); + } + + public WebserviceInitException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/DowngradeSEBSettingsCheck.java b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/DowngradeSEBSettingsCheck.java new file mode 100644 index 00000000..0f9875d4 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/DowngradeSEBSettingsCheck.java @@ -0,0 +1,138 @@ +package ch.ethz.seb.sebserver.webservice.datalayer.checks; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.webservice.DBIntegrityCheck; +import ch.ethz.seb.sebserver.webservice.WebserviceInitException; +import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.*; +import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationAttributeRecord; +import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.OrientationRecord; +import org.apache.commons.lang3.StringUtils; +import org.mybatis.dynamic.sql.SqlBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +@Lazy +@Component +@WebServiceProfile +public class DowngradeSEBSettingsCheck implements DBIntegrityCheck { + + public static final Logger INIT_LOGGER = LoggerFactory.getLogger("ch.ethz.seb.SEB_SERVER_INIT"); + + private final OrientationRecordMapper orientationRecordMapper; + private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper; + private final ConfigurationValueRecordMapper configurationValueRecordMapper; + + private final String versionAttributeIds = + "1,2,3,4,8,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,42,43,44,45,46,47,48," + + "50,51,52,53,54,55,56,57,58,59,60,61,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,81,82,85,86,87,88," + + "89,90,91,92,93,94,95,96,97,98,99,100,200,201,202,203,204,205,206,210,220,221,222,223,231,233,234,235,236," + + "237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262," + + "263,264,265,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322," + + "400,401,402,403,404,405,406,407,408,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516," + + "517,518,519,520,804,812,900,901,904,919,928,940,941,942,950,951,952,953,960,961,970,971,972,973,974,975," + + "1100,1101,1102,1103,1104,1105,1106,1108,1116,1120,1121,1122,1123,1124,1125,1129,1130,1131,1132,1133,1500," + + "1501,1502,1503,1504,1505,1506,1508,1516,1530,1531,1532,1533,1551,1578,"; + private final boolean fixDowngrade; + + public DowngradeSEBSettingsCheck( + final OrientationRecordMapper orientationRecordMapper, + final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper, + final ConfigurationValueRecordMapper configurationValueRecordMapper, + @Value("${sebserver.init.database.integrity.fix.downgrade:false}") final boolean fixDowngrade) { + + this.orientationRecordMapper = orientationRecordMapper; + this.configurationAttributeRecordMapper = configurationAttributeRecordMapper; + this.configurationValueRecordMapper = configurationValueRecordMapper; + this.fixDowngrade = fixDowngrade; + } + + @Override + public String name() { + return "DowngradeSEBSettingsCheck"; + } + + @Override + public String description() { + return "Check if there are additional SEB Settings orientations within the database that do not match the once for the current SEB Server version."; + } + + @Override + public Result applyCheck(boolean tryFix) { + return Result.tryCatch(() -> { + + final String[] split = StringUtils.split(versionAttributeIds, Constants.LIST_SEPARATOR_CHAR); + final List config_attrs_ids = Arrays.stream(split).map(s -> { + try { + return Long.valueOf(s.trim()); + } catch (final Exception e) { + return 0L; + } + }).collect(Collectors.toList()); + + final List attributeIds = orientationRecordMapper.selectByExample() + .where(OrientationRecordDynamicSqlSupport.templateId, SqlBuilder.isEqualTo(0L)) + .and(OrientationRecordDynamicSqlSupport.configAttributeId, SqlBuilder.isNotIn(config_attrs_ids)) + .build() + .execute() + .stream() + .map(OrientationRecord::getConfigAttributeId) + .collect(Collectors.toList()); + + if (attributeIds.isEmpty()) { + return "No additional SEB Settings orientations for downgrading found."; + } + + final Set allNames = configurationAttributeRecordMapper + .selectByExample() + .where(ConfigurationAttributeRecordDynamicSqlSupport.id, SqlBuilder.isIn(attributeIds)) + .build() + .execute() + .stream() + .map(ConfigurationAttributeRecord::getName) + .collect(Collectors.toSet()); + + if (!fixDowngrade) { + INIT_LOGGER.error(" ---> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + INIT_LOGGER.error(" ---> !!! Detected a Database version integrity violation, probably due to SEB Server version downgrade."); + INIT_LOGGER.error(" ---> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + INIT_LOGGER.error(" ---> !!!! Please check the following correction and set 'sebserver.init.database.integrity.fix.downgrade'"); + INIT_LOGGER.error(" ---> !!!! to true to apply repair with next startup. Then SEB Server will apply the repair task"); + INIT_LOGGER.error(" ---> !!!! After successfully repair you can set 'sebserver.init.database.integrity.fix.downgrade' back to false "); + INIT_LOGGER.error(" ---> !!!! NOTE: Repair will delete the following SEB Settings orientation for Exam Configuration default Views"); + INIT_LOGGER.error(" ---> !!!! Exam Configurations built from Configuration Template will stay the same and might have incorrect View Tabs"); + INIT_LOGGER.error(" ---> !!!! Repair will remove following SEB Settings from default view:\n {}", allNames); + INIT_LOGGER.error(" ---> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + throw new WebserviceInitException("Detected a Database version integrity violation, probably due to SEB Server version downgrade. See logs above"); + //return "Downgrade SEB Settings correction would delete the following SEB Settings: " + allNames; + } else { + // TODO delete orientations + + try { + final Integer deletedOrientation = orientationRecordMapper + .deleteByExample() + .where(OrientationRecordDynamicSqlSupport.configAttributeId, SqlBuilder.isIn(attributeIds)) + .and(OrientationRecordDynamicSqlSupport.templateId, SqlBuilder.isEqualTo(0L)) + .build() + .execute(); + + INIT_LOGGER.info(" ---> Deleted {} entries from table orientation", deletedOrientation); + + return "Successfully deleted SEB Settings attributes: " + allNames; + } catch (final Exception e) { + INIT_LOGGER.error("Failed to delete SEB Settings attributes: ", e); + return "Failed to delete SEB Settings attributes: " + allNames; + } + } + }); + } +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java index 8eb1eba3..b453def9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java @@ -14,12 +14,8 @@ import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; -import ch.ethz.seb.sebserver.gbl.Constants; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; import org.mybatis.dynamic.sql.SqlBuilder; import org.springframework.context.annotation.Lazy; -import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -50,7 +46,6 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper; private final ConfigurationValueRecordMapper configurationValueRecordMapper; private final OrientationRecordMapper orientationRecordMapper; - private final Set config_attrs_ids; protected ConfigurationAttributeDAOImpl( final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper, @@ -60,25 +55,6 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO this.configurationAttributeRecordMapper = configurationAttributeRecordMapper; this.configurationValueRecordMapper = configurationValueRecordMapper; this.orientationRecordMapper = orientationRecordMapper; - - Set _config_attrs_ids = null; - try { - final ClassPathResource configFileResource = new ClassPathResource("config/examConfigAttrVersionTable"); - final String ids_comma_separated = IOUtils.toString(configFileResource.getInputStream()); - final String[] split = StringUtils.split(ids_comma_separated, Constants.LIST_SEPARATOR_CHAR); - _config_attrs_ids = Arrays.stream(split).map(s -> { - try { - return Long.valueOf(s.trim()); - } catch (Exception e) { - return 0L; - } - }).collect(Collectors.toSet()); - } catch (final Exception e) { - log.error("Failed to get exam config attribute version infos: ", e); - _config_attrs_ids = null; - } - - config_attrs_ids = _config_attrs_ids; } @Override @@ -176,16 +152,11 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO .build() .execute() .stream() - .filter(this::settingsVersionFilter) .map(ConfigurationAttributeDAOImpl::toDomainModel) .flatMap(DAOLoggingSupport::logAndSkipOnError) .collect(Collectors.toList())); } - private boolean settingsVersionFilter(final ConfigurationAttributeRecord record) { - return config_attrs_ids == null || config_attrs_ids.contains(record.getId()); - } - @Override @Transactional public Result createNew(final ConfigurationAttribute data) { diff --git a/src/main/resources/config/application-dev-ws.properties b/src/main/resources/config/application-dev-ws.properties index d2a040b4..24b3e649 100644 --- a/src/main/resources/config/application-dev-ws.properties +++ b/src/main/resources/config/application-dev-ws.properties @@ -61,4 +61,6 @@ springdoc.swagger-ui.enabled=true management.server.port=${server.port} management.endpoints.web.base-path=/management management.endpoints.web.exposure.include=logfile,loggers,jolokia -management.endpoints.web.path-mapping.jolokia=jmx \ No newline at end of file +management.endpoints.web.path-mapping.jolokia=jmx + +sebserver.init.database.integrity.fix.downgrade=false \ No newline at end of file diff --git a/src/main/resources/config/examConfigAttrVersionTable b/src/main/resources/config/examConfigAttrVersionTable deleted file mode 100644 index 6bc36b97..00000000 --- a/src/main/resources/config/examConfigAttrVersionTable +++ /dev/null @@ -1,348 +0,0 @@ -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -70, -71, -72, -73, -91, -92, -93, -200, -201, -202, -210, -220, -300, -301, -302, -303, -304, -305, -306, -307, -308, -309, -310, -311, -312, -313, -314, -315, -316, -317, -318, -319, -320, -321, -322, -400, -401, -402, -403, -404, -405, -406, -407, -408, -500, -501, -502, -503, -504, -505, -506, -507, -508, -509, -510, -511, -512, -513, -514, -515, -516, -517, -518, -519, -520, -800, -801, -802, -803, -804, -805, -806, -807, -808, -809, -810, -812, -813, -900, -901, -902, -903, -904, -905, -906, -907, -908, -909, -910, -911, -912, -913, -914, -915, -917, -918, -919, -920, -921, -922, -923, -924, -925, -926, -927, -928, -929, -930, -931, -932, -933, -940, -941, -942, -943, -944, -945, -946, -947, -948, -950, -951, -952, -953, -960, -961, -970, -971, -972, -973, -974, -975, -1000, -1001, -1100, -1101, -1102, -1103, -1104, -1105, -1106, -1107, -1108, -1109, -1110, -1111, -1112, -1113, -1114, -1115, -1116, -1120, -1121, -1122, -1123, -1124, -1125, -1126, -1127, -1128, -1129, -1130, -1131, -1132, -1133, -1500, -1501, -1502, -1503, -1504, -1505, -1506, -1507, -1508, -1509, -1510, -1511, -1512, -1513, -1514, -1515, -1516, -1530, -1531, -1532, -1533, -1550, -1551, -1552, -1553, -1554, -1555, -1556, -1557, -1558, -1559, -1560, -1561, -1562, -1563, -1564, -1565, -1566, -1567, -1568, -1569, -1570, -1571, -1572, -1573, -1574, -1575, -1576, -1578, -74, -75, -76, -77, -78, -79, -81, -82, -85, -86, -87, -88, -89, -90, -94, -95, -96, -97, -98, -99, -100, -101, -102, -1577, -203, -204, -205, -206, -221, -222, -223, -231, -233, -234, -235, -236, -237, -238, -239, -240, -241, -242, -243, -244, -245, -246, -247, -248, -249, -250, -251, -252, -253, -254, -255, -256, -257, -258, -259, -260, -261, -262, -263, -264, -265 \ No newline at end of file