eu.scidipes.toolkits.pawebapp.web.ItemsController.java Source code

Java tutorial

Introduction

Here is the source code for eu.scidipes.toolkits.pawebapp.web.ItemsController.java

Source

/*
 * Copyright (c) 2011-2014 Alliance for Permanent Access (APA) and its
 * contributors. See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 * The APA licenses this file to You under the Apache License, Version 2.0
 * (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.scidipes.toolkits.pawebapp.web;

import static eu.scidipes.toolkits.palibrary.interfaces.CoreFieldMetadata.FILE_MIMETYPE;
import static eu.scidipes.toolkits.palibrary.interfaces.CoreFieldMetadata.FILE_NAME;
import static eu.scidipes.toolkits.palibrary.interfaces.CoreFieldMetadata.FILE_SIZE;
import static eu.scidipes.toolkits.palibrary.interfaces.FormFieldType.BYTESTREAM;
import static eu.scidipes.toolkits.palibrary.interfaces.FormFieldType.URI;
import static eu.scidipes.toolkits.pawebapp.web.SaveAction.ADD_NEW;
import static eu.scidipes.toolkits.pawebapp.web.SaveAction.EDIT;
import info.digitalpreserve.interfaces.CurationPersistentIdentifier;
import info.digitalpreserve.interfaces.RepInfoGroup;
import info.digitalpreserve.interfaces.RepresentationInformation;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import eu.scidipes.toolkits.palibrary.exceptions.PreservationException;
import eu.scidipes.toolkits.palibrary.impl.DatasetRIL;
import eu.scidipes.toolkits.palibrary.impl.FormImpl;
import eu.scidipes.toolkits.palibrary.impl.FormsBundleImpl;
import eu.scidipes.toolkits.palibrary.impl.UploadRepInfoLabel.CoreRIType;
import eu.scidipes.toolkits.palibrary.interfaces.Form;
import eu.scidipes.toolkits.palibrary.interfaces.FormsBundle;
import eu.scidipes.toolkits.palibrary.interfaces.LibraryAPI;
import eu.scidipes.toolkits.pawebapp.repository.DataSetRepository;
import eu.scidipes.toolkits.pawebapp.util.Base64MultipartFileEditor;
import eu.scidipes.toolkits.pawebapp.web.validation.FormValidator;

/**
 * {@link Controller} encapsulating operations on data set items (instances of {@link Form})
 * 
 * @author Tom Bunting
 * 
 */
@Controller
@SessionAttributes({ "form", "saveAction" })
@RequestMapping("/datasets/{datasetName}/items")
public class ItemsController {

    private static final Logger LOG = LoggerFactory.getLogger(ItemsController.class);

    @Autowired
    private DataSetRepository datasetRepo;

    @Autowired
    private LibraryAPI libraryAPI;

    @Autowired
    private FormValidator formValidator;

    /**
     * Configures the {@link WebDataBinder} instance provided by Spring
     * 
     * @param binder
     */
    @InitBinder
    public void initBinder(final WebDataBinder binder) {
        binder.registerCustomEditor(String.class, new Base64MultipartFileEditor());

        /* Prevent malicious attempts to bind certain fields */
        binder.setDisallowedFields("formID", "name", "displayName", "introText", "group", "groupOrder");
    }

    @ModelAttribute("datasetPath")
    public String getDatasetPath(@PathVariable final String datasetName) {
        return "/datasets/" + datasetName;
    }

    @ModelAttribute("dsRILs")
    public Set<DatasetRIL> getDatasetRILs(@PathVariable final String datasetName) {
        final FormsBundle dataset = datasetRepo.findOne(datasetName);
        return dataset.getRils();
    }

    @RequestMapping("/{formID}/delete")
    public String deleteItem(@PathVariable final String datasetName, @PathVariable final Integer formID,
            final RedirectAttributes redirectAttrs) {

        final FormsBundleImpl dataset = datasetRepo.findOne(datasetName);
        final FormImpl form = datasetRepo.findOneForm(formID);
        final Form currentForm = dataset.getForms().get(dataset.getForms().indexOf(form));

        final List<Form> formsByName = datasetRepo.findAllByName(datasetName, form.getName());

        /* Reset rather than delete if this is the only form item with this name */
        if (formsByName.size() > 1) {
            LOG.debug("Deletion of form: {} was {}", form,
                    dataset.deleteForm(currentForm) ? "successful" : "unsuccessful");
        } else {
            LOG.debug("Resetting form: {}", form);
            ((FormImpl) currentForm).reset();
            dataset.setForm(currentForm);
        }

        LOG.debug("Saving dataset: {}", dataset);
        datasetRepo.save(dataset);

        redirectAttrs.addFlashAttribute("msgKey", "items.edit.messages.deleted");
        return "redirect:/datasets/" + datasetName;
    }

    @RequestMapping(value = "/new", method = RequestMethod.GET)
    public String addNew(@PathVariable final String datasetName, @MatrixVariable("fn") final String formName,
            final Model model, final RedirectAttributes redirectAttrs) {

        final FormsBundle dataset = datasetRepo.findOne(datasetName);

        /* Get a new 'blank' template from the LibraryAPI */
        try {
            final FormsBundle emptyBundle = libraryAPI.getEmptyStructureForBundle(dataset.getBundleName());

            for (final Form templateForm : emptyBundle.getForms()) {

                if (formName.equals(templateForm.getName())) {
                    final Form newForm = FormImpl.copy((FormImpl) templateForm, dataset);

                    model.addAttribute("form", newForm);
                    model.addAttribute("saveAction", ADD_NEW);
                    return "datasets/items/edit";
                }

            }
        } catch (final PreservationException e) {
            LOG.error(e.getMessage(), e);
        }
        /* TODO: add error message */
        return "redirect:/datasets/" + datasetName;
    }

    /**
     * Edit the first (initially only) item found by formName. Next/previous list IS filtered by formName supplied via
     * matrix var on datasetName.
     * 
     * @param datasetName
     * @param formName
     * @param model
     * @param redirectAttrs
     * @return
     */
    @RequestMapping(value = "/edit", method = RequestMethod.GET)
    public String editItemsByName(@PathVariable final String datasetName,
            @MatrixVariable("fn") final String formName, final Model model,
            final RedirectAttributes redirectAttrs) {
        final List<Form> forms = datasetRepo.findAllByName(datasetName, formName);
        model.addAttribute("formName", formName);
        return editItemHelper(forms, forms.get(0), model, redirectAttrs);
    }

    /**
     * Edit the item identified by the formID. Next/previous MAY be filtered by formName supplied via matrix var on
     * datasetName
     * 
     * @param datasetName
     * @param formID
     * @param formName
     * @param model
     * @param redirectAttrs
     * @return
     */
    @RequestMapping(value = "/{formID}/edit", method = RequestMethod.GET)
    public String editItem(@PathVariable final String datasetName, @PathVariable final int formID,
            @MatrixVariable(value = "fn", required = false, pathVar = "datasetName") final String formName,
            final Model model, final RedirectAttributes redirectAttrs) {

        final Form form = datasetRepo.findOneForm(Integer.valueOf(formID));
        final List<Form> formSubset;

        if (StringUtils.isEmpty(formName)) {
            /* No filtering of list by formName */
            formSubset = datasetRepo.findAllOrderByGrpItemName(datasetName);
        } else {
            model.addAttribute("formName", formName);
            formSubset = datasetRepo.findAllByName(datasetName, formName);
        }

        return editItemHelper(formSubset, form, model, redirectAttrs);
    }

    public String editItemHelper(final List<Form> formSubset, final Form form, final Model model,
            final RedirectAttributes redirectAttrs) {
        final ListIterator<Form> formIterator = formSubset.listIterator();

        while (formIterator.hasNext()) {
            final Form theForm = formIterator.next();
            if (theForm.equals(form)) {
                /* Jump back: */
                formIterator.previous();
                if (formIterator.hasPrevious()) {
                    model.addAttribute("previous",
                            Integer.valueOf(formSubset.get(formIterator.previousIndex()).getFormID().intValue()));
                }
                /* Jump forward: */
                formIterator.next();
                if (formIterator.hasNext()) {
                    model.addAttribute("next",
                            Integer.valueOf(formSubset.get(formIterator.nextIndex()).getFormID().intValue()));
                }
            }
        }
        model.addAttribute("saveAction", EDIT);

        final CurationPersistentIdentifier manifestCPID = form.getManifestCPID();
        final Map<DatasetRIL, Set<CoreRIType>> rilMembership = new HashMap<>();

        /* Fetch the current RIL membership for this form instance: */
        for (final DatasetRIL dsRIL : form.getParentBundle().getRils()) {

            final RepresentationInformation[] repInfo = dsRIL.getRil().getRepresentationInformationChildren();

            for (final RepresentationInformation coreRI : repInfo) {

                if (coreRI.getRepresentationInformation() instanceof RepInfoGroup) {
                    final RepInfoGroup repInfoGroup = (RepInfoGroup) coreRI.getRepresentationInformation();

                    for (final RepresentationInformation ri : repInfoGroup.getRepresentationInformationChildren()) {

                        if (ri.getCpid().equals(manifestCPID)) {

                            if (!rilMembership.containsKey(dsRIL)) {
                                rilMembership.put(dsRIL, new HashSet<CoreRIType>());
                            }
                            rilMembership.get(dsRIL).add(CoreRIType.fromClass(coreRI.getClass()));
                        }

                    }

                }
            }
        }
        model.addAttribute("rilMembership", rilMembership);

        model.addAttribute("form", form);
        return "datasets/items/edit";
    }

    @RequestMapping(value = { "/edit", "/{formID}/edit", "/new" }, method = RequestMethod.POST)
    public String saveItem(@ModelAttribute final SaveAction saveAction, @ModelAttribute final Form form,
            final BindingResult result, final SessionStatus status, final RedirectAttributes redirectAttrs,
            @RequestPart(value = "dataHolder", required = false) final MultipartFile dataFile,
            @MatrixVariable(value = "fn", required = false, pathVar = "datasetName") final String formName) {

        formValidator.validate(form, result);
        if (result.hasErrors()) {
            boolean fixErrors = true;

            final List<FieldError> dataHolderErrors = result.getFieldErrors("dataHolder");

            /*
             * Only ignore errors under very specific conditions, i.e. when there is a single no-file-supplied error and
             * a current file exists
             */
            if (result.getErrorCount() == 1 && dataHolderErrors != null && dataHolderErrors.size() == 1) {

                final FieldError dataHolderError = dataHolderErrors.get(0);
                if (FormValidator.FILE_REQ_ERR_CODE.equals(dataHolderError.getCode())
                        && !form.getDataHolderMetadata().isEmpty() && form.getDataHolderType() == BYTESTREAM) {
                    fixErrors = false;
                }

            }

            if (fixErrors) {
                return "datasets/items/edit";
            }
        }

        /* Ensure that the dataHolder field is not overwritten when its an empty upload (i.e. re-save) */
        if (form.getDataHolderType() == BYTESTREAM && dataFile != null && !dataFile.isEmpty()) {
            LOG.debug("incoming dataFile: {}", dataFile);
            form.getDataHolderMetadata().put(FILE_NAME, dataFile.getOriginalFilename());
            form.getDataHolderMetadata().put(FILE_SIZE, String.valueOf(dataFile.getSize()));
            form.getDataHolderMetadata().put(FILE_MIMETYPE, dataFile.getContentType());
        } else if (form.getDataHolderType() == URI && !StringUtils.isEmpty(form.getDataHolder())) {
            LOG.debug("incoming dataHolder: {}", form.getDataHolder());
            form.getDataHolderMetadata().clear();
        }

        final FormsBundleImpl dataset = datasetRepo.findOne(form.getParentBundle().getDatasetName());

        if (saveAction == ADD_NEW) {
            dataset.addForm(form);
        } else {
            dataset.setForm(form);
        }

        final FormsBundle savedDataset = datasetRepo.save(dataset);
        final Form savedForm = savedDataset.getForms().get(savedDataset.getForms().indexOf(form));

        status.setComplete();
        redirectAttrs.addFlashAttribute("msgKey", "items.edit.messages.savesuccess");

        final String formNameMatrixVar = StringUtils.isEmpty(formName) ? "" : ";fn=" + formName;
        return "redirect:/datasets/" + savedDataset.getDatasetName() + formNameMatrixVar + "/items/"
                + savedForm.getFormID() + "/edit";
    }
}