package de.uni_passau.fim.infosun.prophet.plugin.plugins; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.CharsetDecoder; import java.nio.charset.StandardCharsets; import java.util.Scanner; import de.uni_passau.fim.infosun.prophet.Constants; import de.uni_passau.fim.infosun.prophet.experimentViewer.EViewer; import de.uni_passau.fim.infosun.prophet.plugin.Plugin; import de.uni_passau.fim.infosun.prophet.util.language.UIElementNames; import de.uni_passau.fim.infosun.prophet.util.qTree.Attribute; import de.uni_passau.fim.infosun.prophet.util.qTree.QTreeNode; import de.uni_passau.fim.infosun.prophet.util.settings.Setting; import de.uni_passau.fim.infosun.prophet.util.settings.SettingsList; import de.uni_passau.fim.infosun.prophet.util.settings.components.CheckBoxSetting; import de.uni_passau.fim.infosun.prophet.util.settings.components.PathChooserSetting; import de.uni_passau.fim.infosun.prophet.util.settings.components.TextAreaSetting; import static de.uni_passau.fim.infosun.prophet.util.qTree.QTreeNode.Type.EXPERIMENT; /** * <code>Plugin</code> that is used to check the subject code the user input against a list of valid codes. * Will only allow advancing past the first node of the experiment if the code matches one of the valid codes. */ public class ValidSubjectCodePlugin implements Plugin { private static final String KEY = "valid_code"; private static final String KEY_CODES = "codes"; private static final String KEY_PATH = "path"; private static final String KEY_IGNORE_CASE = "ignorecase"; @Override public Setting getSetting(QTreeNode node) { if (node.getType() != EXPERIMENT) { return null; } Attribute mainAttribute = node.getAttribute(KEY); SettingsList settingsList = new SettingsList(mainAttribute, getClass().getSimpleName(), true); settingsList.setCaption(UIElementNames.getLocalized("SUBJECT_CODE_CHECK_SUBJECT_CODE")); TextAreaSetting textAreaSetting = new TextAreaSetting(mainAttribute.getSubAttribute(KEY_CODES), null); textAreaSetting.setCaption(UIElementNames.getLocalized("SUBJECT_CODE_VALID_CODES")); settingsList.addSetting(textAreaSetting); PathChooserSetting filePathChooser = new PathChooserSetting(mainAttribute.getSubAttribute(KEY_PATH), null); filePathChooser.setCaption(UIElementNames.getLocalized("SUBJECT_CODE_CODE_FILE")); settingsList.addSetting(filePathChooser); CheckBoxSetting checkBoxSetting = new CheckBoxSetting(mainAttribute.getSubAttribute(KEY_IGNORE_CASE), null); checkBoxSetting.setCaption(UIElementNames.getLocalized("SUBJECT_CODE_IGNORE_CASE")); settingsList.addSetting(checkBoxSetting); return settingsList; } @Override public void experimentViewerRun(EViewer experimentViewer) { } @Override public boolean denyEnterNode(QTreeNode node) { return false; } @Override public void enterNode(QTreeNode node) { } @Override public String denyNextNode(QTreeNode currentNode) { Attribute mainAttribute = currentNode.getAttribute(KEY); if (currentNode.getType() != EXPERIMENT || !Boolean.parseBoolean(mainAttribute.getValue())) { return null; } String[] answers = currentNode.getAnswers(Constants.KEY_SUBJECT_CODE); if (answers == null || answers.length < 1) { return UIElementNames.getLocalized("SUBJECT_CODE_MESSAGE_CODE_NOT_FOUND"); } String subjectCode = answers[0]; boolean ignoreCase = Boolean.parseBoolean(mainAttribute.getSubAttribute(KEY_IGNORE_CASE).getValue()); String codes = mainAttribute.getSubAttribute(KEY_CODES).getValue(); if (codes != null && !codes.isEmpty()) { if (contains(subjectCode, new Scanner(codes), ignoreCase)) { return null; } } String path = mainAttribute.getSubAttribute(KEY_PATH).getValue(); if (path != null && !path.isEmpty()) { CharsetDecoder dec = StandardCharsets.UTF_8.newDecoder(); try (Reader reader = new InputStreamReader(new FileInputStream(path), dec)) { if (contains(subjectCode, new Scanner(reader), ignoreCase)) { return null; } } catch (FileNotFoundException e) { return UIElementNames.getLocalized("SUBJECT_CODE_MESSAGE_FILE_NOT_FOUND"); } catch (IOException e) { // may occur when trying to close the FileReader } } return UIElementNames.getLocalized("SUBJECT_CODE_MESSAGE_CODE_NOT_FOUND"); } /** * Checks whether any <code>String</code> returned by the given <code>Scanner</code> matches the given * <code>subjectCode</code>. * * @param subjectCode the subject code to search for * @param sc the <code>Scanner</code> to search through * @param ignoreCase whether to ignore case considerations * @return true iff the <code>Scanner</code> returned the <code>subjectCode</code> */ private boolean contains(String subjectCode, Scanner sc, boolean ignoreCase) { while (sc.hasNext()) { String line = sc.next(); if (ignoreCase) { if (line.equalsIgnoreCase(subjectCode)) { return true; } } else { if (line.equals(subjectCode)) { return true; } } } return false; } @Override public void exitNode(QTreeNode node) { } @Override public String finishExperiment() { return null; } }