org.olat.course.assessment.bulk.DataStepForm.java Source code

Java tutorial

Introduction

Here is the source code for org.olat.course.assessment.bulk.DataStepForm.java

Source

/**
 * <a href="http://www.openolat.org">
 * OpenOLAT - Online Learning and Training</a><br>
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); <br>
 * you may not use this file except in compliance with the License.<br>
 * You may obtain a copy of the License at the
 * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
 * <p>
 * Unless required by applicable law or agreed to in writing,<br>
 * software distributed under the License is distributed on an "AS IS" BASIS, <br>
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
 * See the License for the specific language governing permissions and <br>
 * limitations under the License.
 * <p>
 * Initial code contributed and copyrighted by<br>
 * frentix GmbH, http://www.frentix.com
 * <p>
 */
package org.olat.course.assessment.bulk;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.IOUtils;
import org.olat.core.commons.modules.bc.vfs.OlatRootFileImpl;
import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.FileElement;
import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
import org.olat.core.gui.components.form.flexible.elements.TextElement;
import org.olat.core.gui.components.form.flexible.impl.Form;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.wizard.StepFormBasicController;
import org.olat.core.gui.control.generic.wizard.StepsEvent;
import org.olat.core.gui.control.generic.wizard.StepsRunContext;
import org.olat.core.util.FileUtils;
import org.olat.core.util.StringHelper;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.vfs.LocalImpl;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSManager;
import org.olat.course.assessment.model.BulkAssessmentDatas;
import org.olat.course.assessment.model.BulkAssessmentRow;
import org.olat.course.assessment.model.BulkAssessmentSettings;
import org.olat.course.nodes.AssessableCourseNode;

/**
 * 
 * Initial date: 18.11.2013<br>
 * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
 *
 */
public class DataStepForm extends StepFormBasicController {

    private static final String[] keys = new String[] { "tab", "comma" };

    private TextElement dataEl;
    private FileElement returnFileEl;
    private SingleSelection delimiter;

    private OlatRootFileImpl targetArchive;
    private BulkAssessmentDatas savedDatas;
    private final AssessableCourseNode courseNode;
    private OlatRootFolderImpl bulkAssessmentTmpDir;

    public DataStepForm(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form rootForm) {
        super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);

        courseNode = (AssessableCourseNode) getFromRunContext("courseNode");

        initForm(ureq);
    }

    public DataStepForm(UserRequest ureq, WindowControl wControl, AssessableCourseNode courseNode,
            BulkAssessmentDatas savedDatas, StepsRunContext runContext, Form rootForm) {
        super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);

        this.savedDatas = savedDatas;
        this.courseNode = courseNode;
        addToRunContext("courseNode", courseNode);
        initForm(ureq);
    }

    @Override
    protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
        // hide data input field in case the element does not have any score, passed or comment field enabled
        BulkAssessmentSettings settings = new BulkAssessmentSettings(courseNode);
        boolean onlyReturnFiles = (!settings.isHasScore() && !settings.isHasPassed()
                && !settings.isHasUserComment());

        setFormTitle("data.title");
        if (!onlyReturnFiles) {
            setFormDescription("data.description");
        }
        setFormContextHelp("org.olat.course.assessment.bulk", "bulkassessment_data.html",
                "help.hover.bulkassessment_data");

        String dataVal = "";
        if (savedDatas != null && StringHelper.containsNonWhitespace(savedDatas.getDataBackupFile())) {
            OlatRootFileImpl file = new OlatRootFileImpl(savedDatas.getDataBackupFile(), null);
            InputStream in = file.getInputStream();
            try {
                dataVal = IOUtils.toString(in);
            } catch (IOException e) {
                logError("", e);
            } finally {
                IOUtils.closeQuietly(in);
            }
        }

        dataEl = uifactory.addTextAreaElement("data", "data", -1, 6, 60, true, dataVal, formLayout);
        dataEl.showLabel(false);

        String[] values = new String[] { translate("form.step3.delimiter.tab"),
                translate("form.step3.delimiter.comma") };
        delimiter = uifactory.addRadiosVertical("delimiter", "form.step3.delimiter", formLayout, keys, values);
        // preset delimiter type to first appearance of either tab or comma when data is available, default to tab for no data
        int firstComma = dataVal.indexOf(",");
        int firstTab = dataVal.indexOf("\t");
        if (firstComma > -1 && (firstTab == -1 || firstTab > firstComma)) {
            delimiter.select("comma", true);
        } else {
            delimiter.select("tab", true);
        }

        // hide data input field in case the element does not have any score, passed or comment field enabled
        if (onlyReturnFiles) {
            dataEl.setVisible(false);
            delimiter.setVisible(false);
        }

        // return files only when configured
        if (settings.isHasReturnFiles()) {
            returnFileEl = uifactory.addFileElement("returnfiles", "return.files", formLayout);
            Set<String> mimes = new HashSet<String>();
            mimes.add(WebappHelper.getMimeType("file.zip"));
            returnFileEl.limitToMimeType(mimes, "return.mime", null);
            if (savedDatas != null && StringHelper.containsNonWhitespace(savedDatas.getReturnFiles())) {
                targetArchive = new OlatRootFileImpl(savedDatas.getReturnFiles(), null);
                if (targetArchive.exists()) {
                    returnFileEl.setInitialFile(targetArchive.getBasefile());
                }
            }
        }
    }

    @Override
    protected void doDispose() {
        //
    }

    @Override
    protected void formOK(UserRequest ureq) {
        String val = dataEl.getValue();
        if (!StringHelper.containsNonWhitespace(val)
                && (returnFileEl != null ? !returnFileEl.isUploadSuccess() : true)) {
            // do not proceed when nothin in input field and no file uploaded
            setFormWarning("form.step2.error");
            return;
        }
        setFormWarning(null); // reset error
        BulkAssessmentDatas datas = (BulkAssessmentDatas) getFromRunContext("datas");
        if (datas == null) {
            datas = new BulkAssessmentDatas();
        }

        if (bulkAssessmentTmpDir == null) {
            OlatRootFolderImpl bulkAssessmentDir = new OlatRootFolderImpl("/bulkassessment/", null);
            bulkAssessmentTmpDir = bulkAssessmentDir.createChildContainer(UUID.randomUUID().toString());
        }

        backupInputDatas(val, datas, bulkAssessmentTmpDir);
        List<String[]> splittedRows = splitRawData(val);
        addToRunContext("splittedRows", splittedRows);
        List<BulkAssessmentRow> rows = new ArrayList<>(100);
        if (returnFileEl != null) {
            processReturnFiles(datas, rows, bulkAssessmentTmpDir);
        }
        datas.setRows(rows);
        addToRunContext("datas", datas);
        fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
    }

    private List<String[]> splitRawData(String idata) {
        String[] lines = idata.split("\r?\n");
        int numOfLines = lines.length;

        List<String[]> rows = new ArrayList<String[]>(numOfLines);

        String d;
        if (delimiter.getSelectedKey().startsWith("t")) {
            d = "\t";
        } else {
            d = ",";
        }

        for (int i = 0; i < numOfLines; i++) {
            String line = lines[i];
            if (StringHelper.containsNonWhitespace(line)) {
                String[] values = line.split(d, -1);
                rows.add(values);
            }
        }
        return rows;
    }

    /**
     * Backup the input field for later editing purpose
     * @param val
     * @param datas
     */
    private void backupInputDatas(String val, BulkAssessmentDatas datas, OlatRootFolderImpl tmpDir) {
        OlatRootFileImpl inputFile = null;
        if (StringHelper.containsNonWhitespace(datas.getDataBackupFile())) {
            inputFile = new OlatRootFileImpl(datas.getDataBackupFile(), null);
        }
        if (inputFile == null) {
            String inputFilename = UUID.randomUUID().toString() + ".csv";
            inputFile = tmpDir.createChildLeaf(inputFilename);
        }
        OutputStream out = inputFile.getOutputStream(false);

        try {
            IOUtils.write(val, out);
            datas.setDataBackupFile(inputFile.getRelPath());
        } catch (IOException e) {
            logError("", e);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    private void processReturnFiles(BulkAssessmentDatas datas, List<BulkAssessmentRow> rows,
            OlatRootFolderImpl tmpDir) {
        File uploadedFile = returnFileEl.getUploadFile();
        if (uploadedFile == null) {
            File initialFile = returnFileEl.getInitialFile();
            if (initialFile != null && initialFile.exists()) {
                datas.setReturnFiles(targetArchive.getRelPath());
                processReturnFiles(targetArchive, rows);
            }
        } else if (uploadedFile.exists()) {
            //transfer to secured
            try {
                String uploadedFilename = returnFileEl.getUploadFileName();
                if (!StringHelper.containsNonWhitespace(uploadedFilename)) {
                    uploadedFilename = "bulkAssessment.zip";
                }

                VFSItem currentTarget = tmpDir.resolve(uploadedFilename);
                if (!isSame(currentTarget, uploadedFile)) {
                    if (currentTarget != null && currentTarget.exists()) {
                        currentTarget.deleteSilently();
                    }

                    targetArchive = tmpDir.createChildLeaf(uploadedFilename);
                    FileInputStream inStream = new FileInputStream(uploadedFile);
                    if (VFSManager.copyContent(inStream, targetArchive)) {
                        datas.setReturnFiles(targetArchive.getRelPath());
                        processReturnFiles(targetArchive, rows);
                    }
                } else {
                    datas.setReturnFiles(targetArchive.getRelPath());
                    processReturnFiles(targetArchive, rows);
                }
            } catch (FileNotFoundException e) {
                logError("", e);
            }
        }
    }

    private boolean isSame(VFSItem currentTarget, File uploadedFile) {
        if (currentTarget instanceof LocalImpl) {
            LocalImpl local = (LocalImpl) currentTarget;
            File currentFile = local.getBasefile();
            if (currentFile.length() == uploadedFile.length()) {
                try {
                    return org.apache.commons.io.FileUtils.contentEquals(currentFile, uploadedFile);
                } catch (IOException e) {
                    logError("", e);
                    //do nothing -> return false at the end
                }
            }
        }
        return false;
    }

    private void processReturnFiles(VFSLeaf target, List<BulkAssessmentRow> rows) {
        Map<String, BulkAssessmentRow> assessedIdToRow = new HashMap<>();
        for (BulkAssessmentRow row : rows) {
            assessedIdToRow.put(row.getAssessedId(), row);
        }

        if (target.exists()) {
            InputStream is = target.getInputStream();
            File parentTarget = ((LocalImpl) target).getBasefile().getParentFile();
            ZipInputStream zis = new ZipInputStream(is);

            ZipEntry entry;
            try {
                byte[] b = new byte[FileUtils.BSIZE];
                while ((entry = zis.getNextEntry()) != null) {
                    if (!entry.isDirectory()) {
                        while (zis.read(b) > 0) {
                            //continue
                        }

                        Path op = new File(parentTarget, entry.getName()).toPath();
                        if (!Files.isHidden(op) && !Files.isDirectory(op)) {
                            Path parentDir = op.getParent();
                            String assessedId = parentDir.getFileName().toString();
                            String filename = op.getFileName().toString();

                            BulkAssessmentRow row;
                            if (assessedIdToRow.containsKey(assessedId)) {
                                row = assessedIdToRow.get(assessedId);
                            } else {
                                row = new BulkAssessmentRow();
                                row.setAssessedId(assessedId);
                                assessedIdToRow.put(assessedId, row);
                                rows.add(row);
                            }

                            if (row.getReturnFiles() == null) {
                                row.setReturnFiles(new ArrayList<String>(2));
                            }
                            row.getReturnFiles().add(filename);
                        }
                    }
                }
            } catch (Exception e) {
                logError("", e);
            } finally {
                IOUtils.closeQuietly(is);
                IOUtils.closeQuietly(zis);
            }
        }
    }
}