eionet.cr.web.action.UploadCSVActionBean.java Source code

Java tutorial

Introduction

Here is the source code for eionet.cr.web.action.UploadCSVActionBean.java

Source

/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * The Original Code is Content Registry 2.0.
 *
 * The Initial Owner of the Original Code is European Environment
 * Agency.  Portions created by Tieto Eesti are Copyright
 * (C) European Environment Agency.  All Rights Reserved.
 *
 * Contributor(s):
 * Risto Alt
 */
package eionet.cr.web.action;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import net.sourceforge.stripes.action.Before;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.FileBean;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.validation.ValidationMethod;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import au.com.bytecode.opencsv.CSVReader;
import eionet.cr.common.Predicates;
import eionet.cr.dao.DAOException;
import eionet.cr.dao.DAOFactory;
import eionet.cr.dao.FolderDAO;
import eionet.cr.dao.HarvestSourceDAO;
import eionet.cr.dao.HelperDAO;
import eionet.cr.dao.helpers.CsvImportHelper;
import eionet.cr.dto.ScriptTemplateDTO;
import eionet.cr.dto.SubjectDTO;
import eionet.cr.filestore.FileStore;
import eionet.cr.filestore.ScriptTemplateDaoImpl;
import eionet.cr.util.FolderUtil;
import eionet.cr.web.action.factsheet.FolderActionBean;
import eionet.cr.web.security.CRUser;

/**
 * CSV upload action bean.
 *
 * @author Jaanus Heinlaid
 */
@UrlBinding("/uploadCSV.action")
public class UploadCSVActionBean extends AbstractActionBean {

    /** */
    private static final Logger LOGGER = Logger.getLogger(UploadCSVActionBean.class);

    /** */
    private static final String JSP_PAGE = "/pages/home/uploadCSV.jsp";

    /** */
    private static final String UPLOAD_EVENT = "upload";
    private static final String SAVE_EVENT = "save";

    /** */
    private static final String PARAM_DISPLAY_WIZARD = "displayWizard";

    /** Enum for uploaded files' types. */
    public enum FileType {
        CSV, TSV;
    }

    /** URI of the folder where the file will be uploaded. */
    private String folderUri;

    /** Uploaded file's bean object. */
    private FileBean fileBean;

    /** Uploaded file's type. */
    private FileType fileType;

    /** Uploaded file's name. */
    private String fileName;

    /** The URI that will be assigned to the resource representing the file. */
    private String fileUri;

    /** User can specify rdf:label for the file. */
    private String fileLabel;

    /** Stored file's relative path in the user's file-store. */
    private String relativeFilePath;

    /** The type of objects contained in the file (user-given free text). */
    private String objectsType;

    /** The column (i.e. column title) representing the contained objects' labels. */
    // private String labelColumn;

    /** The columns (i.e. column titles) forming the contained objects' unique identifiers. */
    private List<String> uniqueColumns;

    /** True, when upload is meant for overwriting existing file. */
    private boolean overwrite;

    /** Publisher of uploaded material. */
    private String publisher;

    /** License of uploaded material. */
    private String license;

    /** Attribution. */
    private String attribution;

    /** Source of the uploaded material. */
    private String source;

    /** Form parameter, when true, data linking scripts are added. */
    private boolean addDataLinkingScripts;

    /** Selected scripts/columns data. */
    private List<DataLinkingScript> dataLinkingScripts;

    /** Available scripts. */
    private List<ScriptTemplateDTO> scriptTemplates;

    /** Column labels detected in the uploaded file (titles without type and language code). */
    private List<String> columnLabels;

    /**
     * @return
     */
    @DefaultHandler
    public Resolution init() {
        return new ForwardResolution(JSP_PAGE);
    }

    /**
     *
     * @return
     * @throws DAOException
     */
    public Resolution upload() throws DAOException {

        // Prepare resolution.
        ForwardResolution resolution = new ForwardResolution(JSP_PAGE);

        fileName = fileBean.getFileName();

        FolderDAO folderDAO = DAOFactory.get().getDao(FolderDAO.class);
        if (overwrite) {

            // If doing overwrite, load wizard inputs from previous upload
            loadWizardInputsFromPreviousUpload();

            if (folderDAO.fileOrFolderExists(folderUri, StringUtils.replace(fileName, " ", "%20"))) {
                String oldFileUri = folderUri + "/" + StringUtils.replace(fileName, " ", "%20");
                // Delete existing data
                FileStore fileStore = FileStore.getInstance(FolderUtil.getUserDir(folderUri, getUserName()));
                folderDAO.deleteFileOrFolderUris(folderUri, Collections.singletonList(oldFileUri));
                DAOFactory.get().getDao(HarvestSourceDAO.class)
                        .removeHarvestSources(Collections.singletonList(oldFileUri));
                fileStore.delete(FolderUtil.extractPathInUserHome(folderUri + "/" + fileName));
            }
        } else {
            if (folderDAO.fileOrFolderExists(folderUri, StringUtils.replace(fileName, " ", "%20"))) {
                addCautionMessage("File or folder with the same name already exists.");
                return new RedirectResolution(UploadCSVActionBean.class).addParameter("folderUri", folderUri);
            }
        }

        try {
            // Save the file into user's file-store.
            long fileSize = fileBean.getSize();
            relativeFilePath = FolderUtil.extractPathInUserHome(folderUri + "/" + fileName);
            // FileStore fileStore = FileStore.getInstance(getUserName());
            FileStore fileStore = FileStore.getInstance(FolderUtil.getUserDir(folderUri, getUserName()));
            fileStore.addByMoving(relativeFilePath, true, fileBean);

            CsvImportHelper helper = new CsvImportHelper(uniqueColumns, fileUri, fileLabel, fileType, objectsType,
                    publisher, license, attribution, source);

            // Store file as new source, but don't harvest it
            helper.insertFileMetadataAndSource(fileSize, getUserName());

            // Add metadata about user folder update
            helper.linkFileToFolder(folderUri, getUserName());

            // Prepare data linkins scripts dropdown
            dataLinkingScripts = new ArrayList<DataLinkingScript>();
            dataLinkingScripts.add(new DataLinkingScript());

            // If not given, the file's label equals the file's name
            if (StringUtils.isEmpty(fileLabel)) {
                fileLabel = fileName;
            }

            // Tell the JSP page that it should display the wizard.
            resolution.addParameter(PARAM_DISPLAY_WIZARD, "");

        } catch (Exception e) {
            LOGGER.error("Error while reading the file: ", e);
            addWarningMessage(e.getMessage());
        }

        return resolution;
    }

    /**
     *
     * @return
     */
    public Resolution save() {

        CSVReader csvReader = null;
        CsvImportHelper helper = new CsvImportHelper(uniqueColumns, fileUri, fileLabel, fileType, objectsType,
                publisher, license, attribution, source);
        try {
            csvReader = helper.createCSVReader(folderUri, relativeFilePath, getUserName(), true);
            helper.extractObjects(csvReader);
            helper.saveWizardInputs();

            // Save data-linking scripts, if any added.
            if (addDataLinkingScripts) {
                try {
                    LOGGER.debug("Saving data-linking scripts for " + fileUri);
                    helper.saveDataLinkingScripts(dataLinkingScripts);
                } catch (DAOException e) {
                    LOGGER.error("Failed to add data linking script", e);
                    addWarningMessage("Failed to add data linking script: " + e.getMessage());
                }
            }

            // Run all post-harvest scripts specific to this source (i.e. the uploaded file).
            // This will run both the data data-linking scripts saved in the previous block, plus any that existed already.
            try {
                LOGGER.debug("Running all source-specific post-harvest scripts of " + fileUri);
                List<String> warnings = helper.runScripts();
                if (warnings.size() > 0) {
                    for (String w : warnings) {
                        addWarningMessage(w);
                    }
                }
            } catch (Exception e) {
                LOGGER.error("Failed to run data linking scripts", e);
                addWarningMessage("Failed to run data linking scripts: " + e.getMessage());
            }

        } catch (Exception e) {
            LOGGER.error("Exception while reading uploaded file:", e);
            addWarningMessage(e.toString());
            return new ForwardResolution(JSP_PAGE);
        } finally {
            CsvImportHelper.close(csvReader);
        }

        // If everything went successfully then redirect to the folder items list
        return new RedirectResolution(FolderActionBean.class).addParameter("uri", folderUri);
    }

    /**
     * Form action, that adds aditional input for data linking scripts.
     *
     * @return
     */
    public Resolution addScript() {
        dataLinkingScripts.add(new DataLinkingScript());

        ForwardResolution resolution = new ForwardResolution(JSP_PAGE);
        resolution.addParameter(PARAM_DISPLAY_WIZARD, "");
        return resolution;
    }

    /**
     * Form action, that removes the last input for data linking scripts.
     *
     * @return
     */
    public Resolution removeScript() {
        dataLinkingScripts.remove(dataLinkingScripts.size() - 1);
        ForwardResolution resolution = new ForwardResolution(JSP_PAGE);
        resolution.addParameter(PARAM_DISPLAY_WIZARD, "");
        return resolution;
    }

    /**
     * Actions to be performed before starting any event handling.
     */
    @Before(stages = LifecycleStage.EventHandling)
    public void beforeEventHandling() {

        if (fileName == null && fileBean != null) {
            fileName = fileBean.getFileName();
        }
        fileUri = folderUri + "/" + StringUtils.replace(fileName, " ", "%20");
    }

    /**
     *
     * @throws DAOException
     */
    @ValidationMethod(on = { UPLOAD_EVENT, SAVE_EVENT })
    public void validatePostEvent() throws DAOException {

        // the below validation is relevant only when the event is requested through POST method
        if (!isPostRequest()) {
            return;
        }

        // for all the above POST events, user must be authorized
        String aclPath = FolderUtil.extractAclPath(folderUri);
        boolean actionAllowed = CRUser.hasPermission(aclPath, getUser(), "i", false);

        if (!actionAllowed) {
            addGlobalValidationError("You are not authorised for this operation!");
            return;
        }

        // if upload event, make sure the file bean is not null
        String eventName = getContext().getEventName();
        if (eventName.equals(UPLOAD_EVENT) && fileBean == null) {
            addGlobalValidationError("No file specified!");
        }

        // if insert event, make sure unique columns and object type are not null
        if (eventName.equals(SAVE_EVENT)) {

            if (StringUtils.isBlank(relativeFilePath)) {
                addGlobalValidationError("No file specified!");
            }

            if (StringUtils.isBlank(fileName)) {
                addGlobalValidationError("No file name specified!");
            }

            // File file = FileStore.getInstance(getUserName()).getFile(relativeFilePath);
            File file = FileStore.getInstance(FolderUtil.getUserDir(folderUri, getUserName()))
                    .getFile(relativeFilePath);
            if (file == null || !file.exists()) {
                addGlobalValidationError("Could not find stored file!");
            }

            if (StringUtils.isBlank(objectsType)) {
                addGlobalValidationError("No object type specified!");
            }

            if (StringUtils.isBlank(publisher)) {
                addGlobalValidationError("No original publisher specified!");
            }

            if (StringUtils.isBlank(attribution)) {
                addGlobalValidationError("No copyright attribution specified!");
            }

            if (StringUtils.isBlank(source)) {
                addGlobalValidationError("No source specified!");
            }
        }

        // if any validation errors were set above, make sure the right resolution is returned
        if (hasValidationErrors()) {
            ForwardResolution resolution = new ForwardResolution(JSP_PAGE);
            if (eventName.equals(SAVE_EVENT)) {
                resolution.addParameter(PARAM_DISPLAY_WIZARD, "");
            }
            getContext().setSourcePageResolution(resolution);
        }
    }

    /**
     * True, if there is more than one script bean available.
     *
     * @return
     */
    public boolean isRemoveScriptsAvailable() {
        return dataLinkingScripts.size() > 1;
    }

    /**
     *
     * @throws DAOException
     */
    private void loadWizardInputsFromPreviousUpload() throws DAOException {

        // If, for some reason, all inputs already have a value, do nothing and return
        if (!StringUtils.isBlank(objectsType) && !uniqueColumns.isEmpty()) {
            return;
        }

        SubjectDTO fileSubject = DAOFactory.get().getDao(HelperDAO.class).getSubject(fileUri);
        if (fileSubject != null) {

            if (StringUtils.isBlank(fileLabel)) {
                fileLabel = fileSubject.getObjectValue(Predicates.RDFS_LABEL);
            }

            if (StringUtils.isBlank(objectsType)) {
                objectsType = fileSubject.getObjectValue(Predicates.CR_OBJECTS_TYPE);
            }

            if (uniqueColumns == null || uniqueColumns.isEmpty()) {
                Collection<String> coll = fileSubject.getObjectValues(Predicates.CR_OBJECTS_UNIQUE_COLUMN);
                if (coll != null && !coll.isEmpty()) {
                    uniqueColumns = new ArrayList<String>();
                    uniqueColumns.addAll(coll);
                }
            }

            if (StringUtils.isBlank(publisher)) {
                publisher = fileSubject.getObjectValue(Predicates.DCTERMS_PUBLISHER);
            }

            if (StringUtils.isBlank(license)) {
                license = fileSubject.getObjectValue(Predicates.DCTERMS_LICENSE);
                if (StringUtils.isBlank(license)) {
                    license = fileSubject.getObjectValue(Predicates.DCTERMS_RIGHTS);
                }
            }

            if (StringUtils.isBlank(attribution)) {
                attribution = fileSubject.getObjectValue(Predicates.DCTERMS_BIBLIOGRAPHIC_CITATION);
            }

            if (StringUtils.isBlank(source)) {
                source = fileSubject.getObjectValue(Predicates.DCTERMS_SOURCE);
            }
        }
    }

    /**
     * Singleton getter for column labels.
     *
     * @return
     */
    public List<String> getColumnLabels() {
        if (columnLabels == null) {
            try {
                columnLabels = CsvImportHelper.extractColumnLabels(folderUri, relativeFilePath, getUserName(),
                        fileType);
            } catch (Exception e) {
                LOGGER.error("Exception while reading uploaded file:", e);
                addWarningMessage(e.toString());
                return new ArrayList<String>();
            }
        }

        return columnLabels;
    }

    /**
     * @param file
     */
    public void setFileBean(FileBean file) {
        this.fileBean = file;
    }

    /**
     * @return
     */
    public FileType getFileType() {
        return fileType;
    }

    /**
     * @param type
     */
    public void setFileType(FileType type) {
        this.fileType = type;
    }

    /**
     * @return
     */
    public String getObjectsType() {
        return objectsType;
    }

    /**
     * @param objectType
     */
    public void setObjectsType(String objectType) {
        this.objectsType = objectType;
    }

    /**
     * @return
     */
    public List<String> getUniqueColumns() {
        return uniqueColumns;
    }

    /**
     * @param uniqueColumns
     */
    public void setUniqueColumns(List<String> uniqueColumns) {
        this.uniqueColumns = uniqueColumns;
    }

    /**
     * @return
     */
    public String getRelativeFilePath() {
        return relativeFilePath;
    }

    /**
     * @param filePath
     */
    public void setRelativeFilePath(String filePath) {
        this.relativeFilePath = filePath;
    }

    /**
     * @return the uri
     */
    public String getFolderUri() {
        return folderUri;
    }

    /**
     * @param uri
     *            the uri to set
     */
    public void setFolderUri(String uri) {
        this.folderUri = uri;
    }

    /**
     * @return
     */
    public String getFileName() {
        return fileName;
    }

    /**
     * @param fileName
     *            the fileName to set
     */
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public boolean isOverwrite() {
        return overwrite;
    }

    public void setOverwrite(boolean overwrite) {
        this.overwrite = overwrite;
    }

    public String getFileLabel() {
        return fileLabel;
    }

    public void setFileLabel(String fileLabel) {
        this.fileLabel = fileLabel;
    }

    /**
     * @return the publisher
     */
    public String getPublisher() {
        return publisher;
    }

    /**
     * @param publisher
     *            the publisher to set
     */
    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    /**
     * @return the license
     */
    public String getLicense() {
        return license;
    }

    /**
     * @param license
     *            the license to set
     */
    public void setLicense(String license) {
        this.license = license;
    }

    /**
     * @return the attribution
     */
    public String getAttribution() {
        return attribution;
    }

    /**
     * @param attribution
     *            the attribution to set
     */
    public void setAttribution(String attribution) {
        this.attribution = attribution;
    }

    /**
     * @return the source
     */
    public String getSource() {
        return source;
    }

    /**
     * @param source
     *            the source to set
     */
    public void setSource(String source) {
        this.source = source;
    }

    public boolean isAddDataLinkingScripts() {
        return addDataLinkingScripts;
    }

    public void setAddDataLinkingScripts(boolean addDataLinkingScripts) {
        this.addDataLinkingScripts = addDataLinkingScripts;
    }

    /**
     * @return the dataLinkingScripts
     */
    public List<DataLinkingScript> getDataLinkingScripts() {
        return dataLinkingScripts;
    }

    /**
     * @param dataLinkingScripts
     *            the dataLinkingScripts to set
     */
    public void setDataLinkingScripts(List<DataLinkingScript> dataLinkingScripts) {
        this.dataLinkingScripts = dataLinkingScripts;
    }

    /**
     * @return the scriptTemplates
     */
    public List<ScriptTemplateDTO> getScriptTemplates() {
        if (scriptTemplates == null) {
            scriptTemplates = new ScriptTemplateDaoImpl().getScriptTemplates();
        }
        return scriptTemplates;
    }

    /**
     * @param scriptTemplates
     *            the scriptTemplates to set
     */
    public void setScriptTemplates(List<ScriptTemplateDTO> scriptTemplates) {
        this.scriptTemplates = scriptTemplates;
    }

}