SEBSERV-46 fixed some stuff in back-end, more logging

This commit is contained in:
anhefti 2019-10-08 11:08:33 +02:00
parent 526b97d47b
commit 4d9f4faf09
17 changed files with 146 additions and 57 deletions

View file

@ -67,6 +67,7 @@ public final class Constants {
public static final String XML_PLIST_BOOLEAN_TRUE = "true"; public static final String XML_PLIST_BOOLEAN_TRUE = "true";
public static final String XML_PLIST_BOOLEAN_FALSE = "false"; public static final String XML_PLIST_BOOLEAN_FALSE = "false";
public static final String XML_PLIST_STRING = "string"; public static final String XML_PLIST_STRING = "string";
public static final String XML_PLIST_DATA = "data";
public static final String XML_PLIST_INTEGER = "integer"; public static final String XML_PLIST_INTEGER = "integer";
public static final String OAUTH2_GRANT_TYPE_PASSWORD = "password"; public static final String OAUTH2_GRANT_TYPE_PASSWORD = "password";

View file

@ -121,6 +121,8 @@ public final class API {
public static final String CONFIGURATION_ATTRIBUTE_ENDPOINT = "/configuration_attribute"; public static final String CONFIGURATION_ATTRIBUTE_ENDPOINT = "/configuration_attribute";
public static final String CONFIGURATION_PLAIN_XML_DOWNLOAD_PATH_SEGMENT = "/downloadxml"; public static final String CONFIGURATION_PLAIN_XML_DOWNLOAD_PATH_SEGMENT = "/downloadxml";
public static final String CONFIGURATION_IMPORT_PATH_SEGMENT = "/import"; public static final String CONFIGURATION_IMPORT_PATH_SEGMENT = "/import";
public static final String IMPORT_PASSWORD_ATTR_NAME = "importFilePassword";
public static final String IMPORT_FILE_ATTR_NAME = "importFile";
public static final String ORIENTATION_ENDPOINT = "/orientation"; public static final String ORIENTATION_ENDPOINT = "/orientation";
public static final String VIEW_ENDPOINT = ORIENTATION_ENDPOINT + "/view"; public static final String VIEW_ENDPOINT = ORIENTATION_ENDPOINT + "/view";

View file

@ -18,6 +18,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError; import org.springframework.validation.FieldError;
import org.springframework.web.util.HtmlUtils;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
@ -189,18 +190,19 @@ public class APIMessage implements Serializable {
public static String toHTML(final Collection<APIMessage> messages) { public static String toHTML(final Collection<APIMessage> messages) {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
builder.append("<b>Messages:</b><br/><br/>"); builder.append("<b>Messages:</b><br/><br/>");
messages.stream().forEach(message -> { messages.stream()
builder .forEach(message -> {
.append("&nbsp;&nbsp;code&nbsp;:&nbsp;") builder
.append(message.messageCode) .append("&nbsp;&nbsp;code&nbsp;:&nbsp;")
.append("<br/>") .append(message.messageCode)
.append("&nbsp;&nbsp;system message&nbsp;:&nbsp;") .append("<br/>")
.append(message.systemMessage) .append("&nbsp;&nbsp;system message&nbsp;:&nbsp;")
.append("<br/>") .append(HtmlUtils.htmlEscape(message.systemMessage))
.append("&nbsp;&nbsp;details&nbsp;:&nbsp;") .append("<br/>")
.append(StringUtils.abbreviate(message.details, 100)) .append("&nbsp;&nbsp;details&nbsp;:&nbsp;")
.append("<br/><br/>"); .append(HtmlUtils.htmlEscape(StringUtils.abbreviate(message.details, 100)))
}); .append("<br/><br/>");
});
return builder.toString(); return builder.toString();
} }

View file

@ -18,10 +18,6 @@ public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(AsyncExceptionHandler.class); private static final Logger log = LoggerFactory.getLogger(AsyncExceptionHandler.class);
public AsyncExceptionHandler() {
// TODO Auto-generated constructor stub
}
@Override @Override
public void handleUncaughtException(final Throwable ex, final Method method, final Object... params) { public void handleUncaughtException(final Throwable ex, final Method method, final Object... params) {
log.error("Unexpected error while async processing. method: {}", method, ex); log.error("Unexpected error while async processing. method: {}", method, ex);

View file

@ -28,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
@ -66,8 +67,6 @@ public class SebExamConfigPropForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPropForm.class); private static final Logger log = LoggerFactory.getLogger(SebExamConfigPropForm.class);
private static final String PASSWORD_ATTR_NAME = "importFilePassword";
private static final String IMPORT_FILE_ATTR_NAME = "importFile";
private static final LocTextKey FORM_TITLE_NEW = private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.examconfig.form.title.new"); new LocTextKey("sebserver.examconfig.form.title.new");
private static final LocTextKey FORM_TITLE = private static final LocTextKey FORM_TITLE =
@ -86,6 +85,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
new LocTextKey("sebserver.examconfig.action.import-file-password"); new LocTextKey("sebserver.examconfig.action.import-file-password");
private static final LocTextKey CONFIG_KEY_TITLE_TEXT_KEY = private static final LocTextKey CONFIG_KEY_TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.config-key.title"); new LocTextKey("sebserver.examconfig.form.config-key.title");
private static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY =
new LocTextKey("sebserver.examconfig.action.import-config.confirm");
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
@ -298,16 +299,21 @@ public class SebExamConfigPropForm implements TemplateComposer {
final Form form = formHandle.getForm(); final Form form = formHandle.getForm();
final EntityKey entityKey = formHandle.getContext().getEntityKey(); final EntityKey entityKey = formHandle.getContext().getEntityKey();
final Control fieldControl = form.getFieldControl(IMPORT_FILE_ATTR_NAME); final Control fieldControl = form.getFieldControl(API.IMPORT_FILE_ATTR_NAME);
final PageContext context = formHandle.getContext();
if (fieldControl != null && fieldControl instanceof FileUploadSelection) { if (fieldControl != null && fieldControl instanceof FileUploadSelection) {
final InputStream inputStream = ((FileUploadSelection) fieldControl).getInputStream(); final InputStream inputStream = ((FileUploadSelection) fieldControl).getInputStream();
if (inputStream != null) { if (inputStream != null) {
pageService.getRestService() final Configuration configuration = pageService.getRestService()
.getBuilder(ImportExamConfig.class) .getBuilder(ImportExamConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withBody(inputStream) .withBody(inputStream)
.call() .call()
.getOrThrow(); .get(context::notifyError);
if (configuration != null) {
context.publishInfo(FORM_IMPORT_CONFIRM_TEXT_KEY);
}
} else { } else {
formHandle.getContext().publishPageMessage( formHandle.getContext().publishPageMessage(
new LocTextKey("sebserver.error.unexpected"), new LocTextKey("sebserver.error.unexpected"),
@ -333,12 +339,12 @@ public class SebExamConfigPropForm implements TemplateComposer {
this.pageContext.copyOf(parent), 4) this.pageContext.copyOf(parent), 4)
.readonly(false) .readonly(false)
.addField(FormBuilder.fileUpload( .addField(FormBuilder.fileUpload(
IMPORT_FILE_ATTR_NAME, API.IMPORT_FILE_ATTR_NAME,
FORM_IMPORT_SELECT_TEXT_KEY, FORM_IMPORT_SELECT_TEXT_KEY,
null, null,
API.SEB_FILE_EXTENSION)) API.SEB_FILE_EXTENSION))
.addField(FormBuilder.text( .addField(FormBuilder.text(
PASSWORD_ATTR_NAME, API.IMPORT_PASSWORD_ATTR_NAME,
FORM_IMPORT_PASSWORD_TEXT_KEY, FORM_IMPORT_PASSWORD_TEXT_KEY,
"").asPasswordField()) "").asPasswordField())
.build(); .build();

View file

@ -19,6 +19,7 @@ import java.util.function.Function;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@ -334,7 +335,7 @@ public abstract class RestCall<T> {
public HttpEntity<?> buildRequestEntity() { public HttpEntity<?> buildRequestEntity() {
if (this.streamingBody != null) { if (this.streamingBody != null) {
return new HttpEntity<>(this.streamingBody, this.httpHeaders); return new HttpEntity<>(new InputStreamResource(this.streamingBody), this.httpHeaders);
} else if (this.body != null) { } else if (this.body != null) {
return new HttpEntity<>(this.body, this.httpHeaders); return new HttpEntity<>(this.body, this.httpHeaders);
} else { } else {

View file

@ -33,7 +33,7 @@ public class ImportExamConfig extends RestCall<Configuration> {
new TypeReference<Configuration>() { new TypeReference<Configuration>() {
}), }),
HttpMethod.POST, HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_OCTET_STREAM,
API.CONFIGURATION_NODE_ENDPOINT API.CONFIGURATION_NODE_ENDPOINT
+ API.MODEL_ID_VAR_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT
+ API.CONFIGURATION_IMPORT_PATH_SEGMENT); + API.CONFIGURATION_IMPORT_PATH_SEGMENT);

View file

@ -10,11 +10,14 @@ package ch.ethz.seb.sebserver.gui.widget;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.apache.commons.io.IOUtils;
import org.eclipse.rap.fileupload.FileDetails; import org.eclipse.rap.fileupload.FileDetails;
import org.eclipse.rap.fileupload.FileUploadHandler; import org.eclipse.rap.fileupload.FileUploadHandler;
import org.eclipse.rap.fileupload.FileUploadReceiver; import org.eclipse.rap.fileupload.FileUploadReceiver;
@ -77,6 +80,11 @@ public class FileUploadSelection extends Composite {
this.fileUpload.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); this.fileUpload.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
this.fileUpload.setToolTipText(this.i18nSupport.getText(PLEASE_SELECT_TEXT)); this.fileUpload.setToolTipText(this.i18nSupport.getText(PLEASE_SELECT_TEXT));
final FileUploadHandler uploadHandler = new FileUploadHandler(new InputReceiver()); final FileUploadHandler uploadHandler = new FileUploadHandler(new InputReceiver());
this.fileName = new Label(this, SWT.NONE);
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
this.fileName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
this.fileUpload.addListener(SWT.Selection, event -> { this.fileUpload.addListener(SWT.Selection, event -> {
final String fileName = FileUploadSelection.this.fileUpload.getFileName(); final String fileName = FileUploadSelection.this.fileUpload.getFileName();
if (fileName == null || !fileSupported(fileName)) { if (fileName == null || !fileSupported(fileName)) {
@ -90,11 +98,10 @@ public class FileUploadSelection extends Composite {
return; return;
} }
FileUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl()); FileUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl());
FileUploadSelection.this.fileName.setText(fileName);
FileUploadSelection.this.errorHandler.accept(null);
}); });
this.fileName = new Label(this, SWT.NONE);
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
this.fileName.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
} }
} }
@ -148,7 +155,18 @@ public class FileUploadSelection extends Composite {
private final class InputReceiver extends FileUploadReceiver { private final class InputReceiver extends FileUploadReceiver {
@Override @Override
public void receive(final InputStream stream, final FileDetails details) throws IOException { public void receive(final InputStream stream, final FileDetails details) throws IOException {
FileUploadSelection.this.inputStream = stream; final PipedInputStream pIn = new PipedInputStream();
final PipedOutputStream pOut = new PipedOutputStream(pIn);
FileUploadSelection.this.inputStream = pIn;
try {
IOUtils.copyLarge(stream, pOut);
} catch (final Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(pOut);
}
} }
} }

View file

@ -19,7 +19,12 @@ public final class Message extends MessageBox {
private static final int NORMAL_WIDTH = 400; private static final int NORMAL_WIDTH = 400;
private static final long serialVersionUID = 6973272221493264432L; private static final long serialVersionUID = 6973272221493264432L;
public Message(final Shell parent, final String title, final String message, final int type) { public Message(
final Shell parent,
final String title,
final String message,
final int type) {
super(parent, type); super(parent, type);
super.setText(title); super.setText(title);
super.setMessage(message); super.setMessage(message);

View file

@ -234,7 +234,7 @@ class ConfigurationDAOBatchService {
.forEach(newValRec -> this.batchConfigurationValueRecordMapper.insert(newValRec)); .forEach(newValRec -> this.batchConfigurationValueRecordMapper.insert(newValRec));
return this.batchConfigurationRecordMapper return this.batchConfigurationRecordMapper
.selectByPrimaryKey(configUpdate.getId()); .selectByPrimaryKey(newFollowup.getId());
}) })
.flatMap(ConfigurationDAOImpl::toDomainModel); .flatMap(ConfigurationDAOImpl::toDomainModel);

View file

@ -24,6 +24,8 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.mybatis.dynamic.sql.SqlBuilder; import org.mybatis.dynamic.sql.SqlBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -53,6 +55,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
@WebServiceProfile @WebServiceProfile
public class ConfigurationValueDAOImpl implements ConfigurationValueDAO { public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
private static final Logger log = LoggerFactory.getLogger(ConfigurationValueDAOImpl.class);
private final ConfigurationValueRecordMapper configurationValueRecordMapper; private final ConfigurationValueRecordMapper configurationValueRecordMapper;
private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper; private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper;
private final ConfigurationRecordMapper configurationRecordMapper; private final ConfigurationRecordMapper configurationRecordMapper;
@ -192,9 +196,9 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
id = getByProperties(data) id = getByProperties(data)
.orElseGet(() -> { .orElseGet(() -> {
log.warn("Missing SEB exam configuration attrribute value for: {}", data); log.debug("Missing SEB exam configuration attrribute value for: {}", data);
log.info("Use self-healing strategy to recover from missing SEB exam configuration " log.debug("Use self-healing strategy to recover from missing SEB exam "
+ "attrribute value\n**** Create new AttributeValue for: {}", + "configuration attrribute value\n**** Create new AttributeValue for: {}",
data); data);
createNew(data); createNew(data);

View file

@ -162,7 +162,7 @@ public class ExamConfigIO {
/** This parses the XML from given InputStream with a SAX parser to avoid keeping the /** This parses the XML from given InputStream with a SAX parser to avoid keeping the
* whole XML file in memory and keep up with the streaming approach of SEB Exam Configuration * whole XML file in memory and keep up with the streaming approach of SEB Exam Configuration
* to avoid trouble with big SEB Exam Configuration in the future. * to avoid trouble with big SEB Exam Configuration in the future.
* *
* @param in The InputString to constantly read the XML from * @param in The InputString to constantly read the XML from
* @param institutionId the institionId of the import * @param institutionId the institionId of the import
* @param configurationId the identifier of the internal configuration to apply the imported values to */ * @param configurationId the identifier of the internal configuration to apply the imported values to */
@ -181,7 +181,9 @@ public class ExamConfigIO {
final ExamConfigImportHandler examConfigImportHandler = new ExamConfigImportHandler( final ExamConfigImportHandler examConfigImportHandler = new ExamConfigImportHandler(
institutionId, institutionId,
configurationId, configurationId,
value -> this.configurationValueDAO.save(value), value -> this.configurationValueDAO
.save(value)
.getOrThrow(),
attributeMap::get); attributeMap::get);
// SAX parsing // SAX parsing

View file

@ -15,6 +15,8 @@ import java.util.Stack;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
@ -25,10 +27,13 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl.ExamConfigIm
public class ExamConfigImportHandler extends DefaultHandler { public class ExamConfigImportHandler extends DefaultHandler {
private static final Logger log = LoggerFactory.getLogger(ExamConfigImportHandler.class);
private static final Set<String> VALUE_ELEMENTS = new HashSet<>(Arrays.asList( private static final Set<String> VALUE_ELEMENTS = new HashSet<>(Arrays.asList(
Constants.XML_PLIST_BOOLEAN_FALSE, Constants.XML_PLIST_BOOLEAN_FALSE,
Constants.XML_PLIST_BOOLEAN_TRUE, Constants.XML_PLIST_BOOLEAN_TRUE,
Constants.XML_PLIST_STRING, Constants.XML_PLIST_STRING,
Constants.XML_PLIST_DATA,
Constants.XML_PLIST_INTEGER)); Constants.XML_PLIST_INTEGER));
private final Consumer<ConfigurationValue> valueConsumer; private final Consumer<ConfigurationValue> valueConsumer;
@ -51,6 +56,16 @@ public class ExamConfigImportHandler extends DefaultHandler {
this.configId = configId; this.configId = configId;
} }
@Override
public void startDocument() throws SAXException {
log.debug("Start parsing document");
}
@Override
public void endDocument() throws SAXException {
log.debug("End parsing document");
}
@Override @Override
public void startElement( public void startElement(
final String uri, final String uri,
@ -58,6 +73,8 @@ public class ExamConfigImportHandler extends DefaultHandler {
final String qName, final String qName,
final Attributes attributes) throws SAXException { final Attributes attributes) throws SAXException {
log.debug("start element: {}", qName);
final Type type = Type.getType(qName); final Type type = Type.getType(qName);
final PListNode top = (this.stack.isEmpty()) ? null : this.stack.peek(); final PListNode top = (this.stack.isEmpty()) ? null : this.stack.peek();
@ -77,6 +94,7 @@ public class ExamConfigImportHandler extends DefaultHandler {
case VALUE_BOOLEAN_FALSE: case VALUE_BOOLEAN_FALSE:
case VALUE_BOOLEAN_TRUE: case VALUE_BOOLEAN_TRUE:
case VALUE_STRING: case VALUE_STRING:
case VALUE_DATA:
case VALUE_INTEGER: case VALUE_INTEGER:
startValueElement(type, top); startValueElement(type, top);
break; break;
@ -196,13 +214,30 @@ public class ExamConfigImportHandler extends DefaultHandler {
? parent.name + "." + top.name ? parent.name + "." + top.name
: top.name; : top.name;
this.valueConsumer.accept(new ConfigurationValue( final Long attributeId = this.attributeNameIdResolver.apply(attrName);
null, if (attributeId == null) {
this.institutionId,
this.configId, if (log.isDebugEnabled()) {
this.attributeNameIdResolver.apply(attrName), log.debug("Skip unknown configuration attribute: {}", attrName);
top.listIndex, }
top.value));
} else {
// TODO use AttributeValueConverterService here. Extend the converters with fromXML functionality
final ConfigurationValue configurationValue = new ConfigurationValue(
null,
this.institutionId,
this.configId,
attributeId,
top.listIndex,
top.value);
if (log.isDebugEnabled()) {
log.debug("Save imported value: {} : {}", attrName, configurationValue);
}
this.valueConsumer.accept(configurationValue);
}
} }
} else if (!Constants.XML_PLIST_KEY_NAME.equals(qName)) { } else if (!Constants.XML_PLIST_KEY_NAME.equals(qName)) {
this.stack.pop(); this.stack.pop();
@ -215,13 +250,16 @@ public class ExamConfigImportHandler extends DefaultHandler {
final int start, final int start,
final int length) throws SAXException { final int length) throws SAXException {
final char[] valueChar = new char[length];
System.arraycopy(ch, start, valueChar, 0, length);
final String value = String.valueOf(valueChar);
final PListNode top = this.stack.peek(); final PListNode top = this.stack.peek();
if (top.type == Type.VALUE_STRING) { if (top.type == Type.VALUE_STRING) {
top.value = String.valueOf(ch); top.value = value;
} else if (top.type == Type.VALUE_INTEGER) { } else if (top.type == Type.VALUE_INTEGER) {
top.value = String.valueOf(ch); top.value = value;
} else if (top.type == Type.KEY) { } else if (top.type == Type.KEY) {
top.name = String.valueOf(ch); top.name = value;
} }
} }
@ -235,6 +273,7 @@ public class ExamConfigImportHandler extends DefaultHandler {
VALUE_BOOLEAN_TRUE(true, Constants.XML_PLIST_BOOLEAN_TRUE), VALUE_BOOLEAN_TRUE(true, Constants.XML_PLIST_BOOLEAN_TRUE),
VALUE_BOOLEAN_FALSE(true, Constants.XML_PLIST_BOOLEAN_FALSE), VALUE_BOOLEAN_FALSE(true, Constants.XML_PLIST_BOOLEAN_FALSE),
VALUE_STRING(true, Constants.XML_PLIST_STRING), VALUE_STRING(true, Constants.XML_PLIST_STRING),
VALUE_DATA(true, Constants.XML_PLIST_DATA),
VALUE_INTEGER(true, Constants.XML_PLIST_INTEGER); VALUE_INTEGER(true, Constants.XML_PLIST_INTEGER);
private final boolean isValueType; private final boolean isValueType;

View file

@ -336,12 +336,19 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
final byte[] header = new byte[4]; final byte[] header = new byte[4];
input.read(header); input.read(header);
final Strategy strategy = SebConfigEncryptionService.Strategy.getStrategy(header);
if (strategy == null) { Strategy strategy = null;
try {
strategy = SebConfigEncryptionService.Strategy.getStrategy(header);
} catch (final IllegalArgumentException iae) {
log.info("{} : Trying to import as unzipped plain text configuration", iae.getMessage());
importPlainOnly(input, newConfig, header); importPlainOnly(input, newConfig, header);
} else { return newConfig;
}
if (strategy != null) {
final InputStream cryptIn = this.unzip(input); final InputStream cryptIn = this.unzip(input);
final PipedInputStream plainIn = new PipedInputStream(); final PipedInputStream plainIn = new PipedInputStream();
final PipedOutputStream cryptOut = new PipedOutputStream(plainIn); final PipedOutputStream cryptOut = new PipedOutputStream(plainIn);
@ -369,9 +376,11 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
} catch (final Exception e) { } catch (final Exception e) {
log.error("Unexpected error while trying to import SEB Exam Configuration: ", e); log.error("Unexpected error while trying to import SEB Exam Configuration: ", e);
log.debug("Make an undo on the ConfigurationNode to rollback the changes"); log.debug("Make an undo on the ConfigurationNode to rollback the changes");
return this.configurationDAO this.configurationDAO
.undo(configNodeId) .undo(configNodeId)
.getOrThrow(); .getOrThrow();
throw new RuntimeException("Failed to import SEB configuration. Cause is: " + e.getMessage(), e);
} }
}); });
} }
@ -412,16 +421,18 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
plainIn = new PipedInputStream(); plainIn = new PipedInputStream();
out = new PipedOutputStream(plainIn); out = new PipedOutputStream(plainIn);
this.examConfigIO.importPlainXML(plainIn, newConfig.institutionId, newConfig.id); this.examConfigIO.importPlainXML(
plainIn,
newConfig.institutionId,
newConfig.id);
out.write(header); out.write(header);
IOUtils.copyLarge(input, out); IOUtils.copyLarge(input, out);
IOUtils.closeQuietly(out);
} catch (final Exception e) { } catch (final Exception e) {
log.error("Error while stream plain text SEB Configuration import data: ", e); log.error("Error while stream plain text SEB Configuration import data: ", e);
throw e; throw e;
} finally { } finally {
IOUtils.closeQuietly(out); IOUtils.closeQuietly(out);
IOUtils.closeQuietly(plainIn);
} }
} }

View file

@ -164,11 +164,12 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
@RequestMapping( @RequestMapping(
path = API.MODEL_ID_VAR_PATH_SEGMENT + API.CONFIGURATION_IMPORT_PATH_SEGMENT, path = API.MODEL_ID_VAR_PATH_SEGMENT + API.CONFIGURATION_IMPORT_PATH_SEGMENT,
method = RequestMethod.GET, method = RequestMethod.POST,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Configuration importExamConfig( public Configuration importExamConfig(
@PathVariable final Long modelId, @PathVariable final Long modelId,
@RequestHeader final String password, @RequestHeader(name = API.IMPORT_PASSWORD_ATTR_NAME, required = false) final String password,
@RequestParam( @RequestParam(
name = API.PARAM_INSTITUTION_ID, name = API.PARAM_INSTITUTION_ID,
required = true, required = true,

View file

@ -449,6 +449,7 @@ sebserver.examconfig.action.get-config-key=Export Config-Key
sebserver.examconfig.action.import-config=Import Configuration sebserver.examconfig.action.import-config=Import Configuration
sebserver.examconfig.action.import-file-select=Import From File sebserver.examconfig.action.import-file-select=Import From File
sebserver.examconfig.action.import-file-password=Password sebserver.examconfig.action.import-file-password=Password
sebserver.examconfig.action.import-config.confirm=Configuration successfully imported
sebserver.examconfig.form.title.new=Add Exam Configuration sebserver.examconfig.form.title.new=Add Exam Configuration
sebserver.examconfig.form.title=Exam Configuration sebserver.examconfig.form.title=Exam Configuration

View file

@ -1080,7 +1080,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
assertNotNull(saveHistoryResponse); assertNotNull(saveHistoryResponse);
assertFalse(saveHistoryResponse.hasError()); assertFalse(saveHistoryResponse.hasError());
Configuration configuration = saveHistoryResponse.get(); Configuration configuration = saveHistoryResponse.get();
assertFalse(configuration.followup); assertTrue(configuration.followup);
configHistoryResponse = restService configHistoryResponse = restService
.getBuilder(GetConfigurations.class) .getBuilder(GetConfigurations.class)