SEBSERV-138 ARIA plugin integration
+ Database integrity checks
This commit is contained in:
parent
9a788cc495
commit
bcb21da221
10 changed files with 349 additions and 1 deletions
12
pom.xml
12
pom.xml
|
@ -322,6 +322,18 @@
|
|||
<artifactId>org.eclipse.rap.fileupload</artifactId>
|
||||
<version>3.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xeustechnologies</groupId>
|
||||
<artifactId>jcl-core</artifactId>
|
||||
<version>2.8</version>
|
||||
</dependency>
|
||||
<!-- <dependency> -->
|
||||
<!-- <groupId>com.eclipsesource.rap.aria</groupId> -->
|
||||
<!-- <artifactId>aria</artifactId> -->
|
||||
<!-- <version>1.0</version> -->
|
||||
<!-- <scope>system</scope> -->
|
||||
<!-- <systemPath>C:\dev\workspaces\sebserver\externalResources\lib\com.eclipsesource.rap.aria_0.4.0.20210614-0915.jar</systemPath> -->
|
||||
<!-- </dependency> -->
|
||||
|
||||
<!-- Misc -->
|
||||
<dependency>
|
||||
|
|
|
@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.gui;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -17,6 +18,7 @@ import javax.servlet.ServletContext;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.application.AbstractEntryPoint;
|
||||
import org.eclipse.rap.rwt.application.Application;
|
||||
|
@ -33,6 +35,9 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.xeustechnologies.jcl.JarClassLoader;
|
||||
|
||||
//import com.eclipsesource.rap.aria.Aria;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
|
@ -72,6 +77,7 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
|
||||
application.addEntryPoint(guiEntrypoint, new RAPSpringEntryPointFactory(), properties);
|
||||
application.addEntryPoint(proctoringEntrypoint, new RAPRemoteProcotringEntryPointFactory(), properties);
|
||||
|
||||
} catch (final RuntimeException re) {
|
||||
throw re;
|
||||
} catch (final Exception e) {
|
||||
|
@ -99,6 +105,7 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
|
||||
@Override
|
||||
protected void createContents(final Composite parent) {
|
||||
|
||||
final HttpSession httpSession = RWT
|
||||
.getUISession(parent.getDisplay())
|
||||
.getHttpSession();
|
||||
|
@ -120,6 +127,7 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
|
||||
public static final class RAPSpringEntryPointFactory implements EntryPointFactory {
|
||||
|
||||
private final JarClassLoader jcl = new JarClassLoader();
|
||||
private boolean initialized = false;
|
||||
|
||||
@Override
|
||||
|
@ -154,6 +162,28 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
final WebApplicationContext webApplicationContext = getWebApplicationContext(httpSession);
|
||||
initSpringBasedRAPServices(webApplicationContext);
|
||||
|
||||
final String ariaPluginPath = ariaPluginPath(webApplicationContext);
|
||||
if (StringUtils.isNotBlank(ariaPluginPath)) {
|
||||
|
||||
log.debug("Try to initialize com.eclipsesource.rap.aria.Aria plugin...");
|
||||
|
||||
try {
|
||||
|
||||
final Class<?> forName = Class.forName(
|
||||
"com.eclipsesource.rap.aria.Aria",
|
||||
false,
|
||||
RAPSpringEntryPointFactory.this.jcl);
|
||||
|
||||
final Method method = forName.getMethod("activate");
|
||||
method.invoke(null);
|
||||
|
||||
log.info("Initialization of com.eclipsesource.rap.aria.Aria plugin was successful");
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to initialize com.eclipsesource.rap.aria.Aria plugin: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
final EntryPointService entryPointService = webApplicationContext
|
||||
.getBean(EntryPointService.class);
|
||||
|
||||
|
@ -172,12 +202,25 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
final ServiceManager manager = RWT.getServiceManager();
|
||||
final DownloadService downloadService = webApplicationContext.getBean(DownloadService.class);
|
||||
manager.registerServiceHandler(DownloadService.DOWNLOAD_SERVICE_NAME, downloadService);
|
||||
|
||||
final String ariaPluginPath = ariaPluginPath(webApplicationContext);
|
||||
if (StringUtils.isNotBlank(ariaPluginPath)) {
|
||||
this.jcl.add(ariaPluginPath);
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
} catch (final IllegalArgumentException iae) {
|
||||
log.warn("Failed to register DownloadService on ServiceManager. Already registered: ", iae);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String ariaPluginPath(final WebApplicationContext webApplicationContext) {
|
||||
return webApplicationContext
|
||||
.getEnvironment()
|
||||
.getProperty("sebserver.gui.external.lib.aria.plugin.path", "");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAuthenticated(
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
public interface DBIntegrityCheck {
|
||||
|
||||
String name();
|
||||
|
||||
String description();
|
||||
|
||||
Result<String> applyCheck(boolean tryFix);
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
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;
|
||||
|
||||
import ch.ethz.seb.sebserver.SEBServerInit;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class DBIntegrityChecker {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DBIntegrityChecker.class);
|
||||
|
||||
private final Collection<DBIntegrityCheck> checkers;
|
||||
private final boolean runIntegrityChecks;
|
||||
private final boolean tryFix;
|
||||
|
||||
public DBIntegrityChecker(
|
||||
final Collection<DBIntegrityCheck> checkers,
|
||||
@Value("${sebserver.init.database.integrity.checks:true}") final boolean runIntegrityChecks,
|
||||
@Value("${sebserver.init.database.integrity.try-fix:true}") final boolean tryFix) {
|
||||
|
||||
this.checkers = checkers;
|
||||
this.runIntegrityChecks = runIntegrityChecks;
|
||||
this.tryFix = tryFix;
|
||||
}
|
||||
|
||||
public void checkIntegrity() {
|
||||
if (this.runIntegrityChecks && !this.checkers.isEmpty()) {
|
||||
|
||||
SEBServerInit.INIT_LOGGER.info("---->");
|
||||
SEBServerInit.INIT_LOGGER.info("----> **** Run data-base integrity checks ****");
|
||||
SEBServerInit.INIT_LOGGER.info("---->");
|
||||
|
||||
this.checkers.stream().forEach(this::doCheck);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCheck(final DBIntegrityCheck dbIntegrityCheck) {
|
||||
try {
|
||||
|
||||
SEBServerInit.INIT_LOGGER.info("------> Apply check: {} / {}", dbIntegrityCheck.name(),
|
||||
dbIntegrityCheck.description());
|
||||
|
||||
final Result<String> applyCheck = dbIntegrityCheck.applyCheck(this.tryFix);
|
||||
if (applyCheck.hasError()) {
|
||||
SEBServerInit.INIT_LOGGER.info("--------> Unexpected Error: {}", applyCheck.getError().getMessage());
|
||||
} else {
|
||||
SEBServerInit.INIT_LOGGER.info("--------> Result: {}", applyCheck.get());
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to apply data base integrity check: {}", dbIntegrityCheck);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -37,6 +37,7 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
private final AdminUserInitializer adminUserInitializer;
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
private final WebserviceInfoDAO webserviceInfoDAO;
|
||||
private final DBIntegrityChecker dbIntegrityChecker;
|
||||
|
||||
protected WebserviceInit(
|
||||
final SEBServerInit sebServerInit,
|
||||
|
@ -44,7 +45,8 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
final WebserviceInfo webserviceInfo,
|
||||
final AdminUserInitializer adminUserInitializer,
|
||||
final ApplicationEventPublisher applicationEventPublisher,
|
||||
final WebserviceInfoDAO webserviceInfoDAO) {
|
||||
final WebserviceInfoDAO webserviceInfoDAO,
|
||||
final DBIntegrityChecker dbIntegrityChecker) {
|
||||
|
||||
this.sebServerInit = sebServerInit;
|
||||
this.environment = environment;
|
||||
|
@ -52,6 +54,7 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
this.adminUserInitializer = adminUserInitializer;
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
this.webserviceInfoDAO = webserviceInfoDAO;
|
||||
this.dbIntegrityChecker = dbIntegrityChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,6 +111,9 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
SEBServerInit.INIT_LOGGER.info("---->");
|
||||
SEBServerInit.INIT_LOGGER.info("----> Property Override Test: {}", this.webserviceInfo.getTestProperty());
|
||||
|
||||
// Run the data base integrity checks and fixes if configured
|
||||
this.dbIntegrityChecker.checkIntegrity();
|
||||
|
||||
// Create an initial admin account if requested and not already in the data-base
|
||||
this.adminUserInitializer.initAdminAccount();
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.datalayer.checks;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
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.datalayer.batis.mapper.OrientationRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.OrientationRecord;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class OrientationTableDuplicatesCheck implements DBIntegrityCheck {
|
||||
|
||||
private final OrientationRecordMapper orientationRecordMapper;
|
||||
|
||||
public OrientationTableDuplicatesCheck(final OrientationRecordMapper orientationRecordMapper) {
|
||||
this.orientationRecordMapper = orientationRecordMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "OrientationTableDuplicatesCheck";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Checks if there are duplicate entries in the orientation table by using the config_attribute_id and template_id to identify duplicates.";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<String> applyCheck(final boolean tryFix) {
|
||||
return Result.tryCatch(() -> {
|
||||
final List<OrientationRecord> records = this.orientationRecordMapper
|
||||
.selectByExample()
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
final Set<String> once = new HashSet<>();
|
||||
final Set<Long> toDelete = new HashSet<>();
|
||||
for (final OrientationRecord record : records) {
|
||||
final String id = record.getConfigAttributeId().toString() + record.getTemplateId().toString();
|
||||
if (once.contains(id)) {
|
||||
toDelete.add(record.getId());
|
||||
} else {
|
||||
once.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (toDelete.isEmpty()) {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
if (tryFix) {
|
||||
toDelete
|
||||
.stream()
|
||||
.forEach(this.orientationRecordMapper::deleteByPrimaryKey);
|
||||
return "Fixed duplicates by deletion: " + toDelete;
|
||||
} else {
|
||||
return "Found duplicates: " + toDelete;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("OrientationTableDuplicatesCheck [name()=");
|
||||
builder.append(name());
|
||||
builder.append(", description()=");
|
||||
builder.append(description());
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.datalayer.checks;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
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.datalayer.batis.mapper.ViewRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ViewRecord;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class ViewTableDuplicatesCheck implements DBIntegrityCheck {
|
||||
|
||||
private final ViewRecordMapper viewRecordMapper;
|
||||
|
||||
public ViewTableDuplicatesCheck(final ViewRecordMapper viewRecordMapper) {
|
||||
this.viewRecordMapper = viewRecordMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "ViewTableDuplicatesCheck";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Checks if there are duplicate entries in the view table by using the name and template_id to identify duplicates.";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<String> applyCheck(final boolean tryFix) {
|
||||
return Result.tryCatch(() -> {
|
||||
final List<ViewRecord> records = this.viewRecordMapper
|
||||
.selectByExample()
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
final Set<String> once = new HashSet<>();
|
||||
final Set<Long> toDelete = new HashSet<>();
|
||||
for (final ViewRecord record : records) {
|
||||
final String id = record.getName() + record.getTemplateId().toString();
|
||||
if (once.contains(id)) {
|
||||
toDelete.add(record.getId());
|
||||
} else {
|
||||
once.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (toDelete.isEmpty()) {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
if (tryFix) {
|
||||
toDelete
|
||||
.stream()
|
||||
.forEach(this.viewRecordMapper::deleteByPrimaryKey);
|
||||
return "Fixed duplicates by deletion: " + toDelete;
|
||||
} else {
|
||||
return "Found duplicates: " + toDelete;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("ViewTableDuplicatesCheck [name()=");
|
||||
builder.append(name());
|
||||
builder.append(", description()=");
|
||||
builder.append(description());
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
spring.profiles.include=dev-ws,dev-gui
|
||||
|
||||
sebserver.test.property=This is the development Setup
|
||||
|
||||
server.address=localhost
|
||||
server.port=8080
|
||||
server.servlet.context-path=/
|
||||
|
|
|
@ -38,6 +38,9 @@ sebserver.gui.filter.date.from.years=2
|
|||
sebserver.gui.remote.proctoring.entrypoint=/remote-proctoring
|
||||
sebserver.gui.remote.proctoring.api-servler.endpoint=/remote-view-servlet
|
||||
|
||||
# external libs / plugins
|
||||
sebserver.gui.external.lib.aria.plugin.path=
|
||||
|
||||
# Webservice connection details
|
||||
sebserver.webservice.api.exam.endpoint=/exam-api
|
||||
sebserver.webservice.api.exam.endpoint.discovery=${sebserver.webservice.api.exam.endpoint}/discovery
|
||||
|
|
|
@ -7,6 +7,8 @@ sebserver.test.property=This is the default/root configuration
|
|||
sebserver.init.adminaccount.gen-on-init=true
|
||||
sebserver.init.organisation.name=SEB Server
|
||||
sebserver.init.adminaccount.username=sebserver-admin
|
||||
sebserver.init.database.integrity.checks=true
|
||||
sebserver.init.database.integrity.try-fix=true
|
||||
|
||||
### webservice caching
|
||||
spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
|
||||
|
|
Loading…
Reference in a new issue