eionet.webq.web.controller.PublicPageController.java Source code

Java tutorial

Introduction

Here is the source code for eionet.webq.web.controller.PublicPageController.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 Web Questionnaires 2
 *
 * The Initial Owner of the Original Code is European Environment
 * Agency. Portions created by TripleDev are Copyright
 * (C) European Environment Agency.  All Rights Reserved.
 *
 * Contributor(s):
 *        Enriko Ksper
 *        Raptis Dimos
 */
package eionet.webq.web.controller;

import eionet.webq.converter.JsonXMLBidirectionalConverter;
import eionet.webq.converter.UserFileToFileInfoConverter;
import eionet.webq.dao.orm.ProjectFile;
import eionet.webq.dao.orm.UserFile;
import eionet.webq.dto.FileInfo;
import eionet.webq.dto.UploadForm;
import eionet.webq.dto.XmlSaveResult;
import eionet.webq.service.*;
import eionet.webq.web.controller.util.UserFileHelper;
import eionet.webq.web.controller.util.UserFileList;
import eionet.webq.web.controller.util.WebformUrlProvider;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import static org.apache.commons.lang3.StringUtils.isEmpty;

/**
 * Base controller for front page actions.
 *
 * @author Enriko Ksper
 */
@Controller
@RequestMapping
public class PublicPageController {
    /**
     * Logger for this class.
     */
    public static final Logger LOGGER = Logger.getLogger(PublicPageController.class);
    /**
     * Webform URL provider.
     */
    @Autowired
    WebformUrlProvider webformUrlProvider;
    /**
     * Helper web layer service to match request parameters and UserFle object in database.
     */
    @Autowired
    UserFileHelper userFileHelper;
    /**
     * Service for user uploaded files.
     */
    @Autowired
    private UserFileService userFileService;
    /**
     * File conversion service.
     */
    @Autowired
    private ConversionService conversionService;
    /**
     * WebForms storage.
     */
    @Autowired
    @Qualifier("localWebForms")
    private WebFormService webFormService;
    /**
     * Cdr envelope service.
     */
    @Autowired
    private CDREnvelopeService envelopeService;

    @Autowired
    private RequestBasedUserIdProvider requestBasedUserIdProvider;

    /**
     * Converts user xml metadata to file info object.
     */
    @Autowired
    private UserFileToFileInfoConverter fileInfoConverter;
    /**
     * Json to XML converter.
     */
    @Autowired
    private JsonXMLBidirectionalConverter jsonToXMLConverter;

    @Autowired
    private CookieValueManager cookieValueManager;

    /**
     * Action to be performed on http GET method and path '/'.
     *
     * @param model holder for model attributes
     * @return view name
     */
    @RequestMapping(value = "/")
    public String welcome(Model model) {
        model.addAttribute("uploadedFiles", allFilesWithConversions());
        List<ProjectFile> webformsSortedList = webFormService.sortWebformsAlphabetically(allWebForms());
        model.addAttribute("allWebForms", webformsSortedList);
        String uploadForm = "uploadForm";
        if (!model.containsAttribute(uploadForm)) {
            model.addAttribute(uploadForm, new UploadForm());
        }
        return "index";
    }

    /**
     * Action to be performed on http GET method and path '/'.
     *
     * @param model   holder for model attributes
     * @param session http session
     * @return view name
     */
    @RequestMapping(value = "/sessionfiles")
    public String sessionfiles(Model model, HttpSession session) {
        return welcome(model);
    }

    /**
     * Redirects to welcome page after login.
     *
     * @param model holder for model attributes
     * @return view name
     */
    @RequestMapping(value = "/login")
    public String login(Model model) {
        return welcome(model);
    }

    /**
     * Shows page which allows to perform SingleSignOut.
     *
     * @return view name
     */
    @RequestMapping(value = "/logout")
    public String logout() {
        return "logout_all_apps";
    }

    /**
     * Upload action.
     *
     * @param uploadForm represents form used in UI, {@link UploadForm#userFiles} will be converted from
     *                   {@link org.springframework.web.multipart.MultipartFile}
     * @param result     binding result, contains validation errors
     * @param model      holder for model attributes
     * @return view name
     */
    @RequestMapping(value = "/uploadXml", method = RequestMethod.POST)
    public String upload(@Valid @ModelAttribute UploadForm uploadForm, BindingResult result, Model model) {
        if (!result.hasErrors()) {
            saveFiles(uploadForm);
        }
        return welcome(model);
    }

    /**
     * Upload action. If there is only one file uploaded and one form available for this file, redirect to this form.
     *
     * @param uploadForm represents form used in UI, {@link UploadForm#userFiles} will be converted from
     *                   {@link org.springframework.web.multipart.MultipartFile}
     * @param result     binding result, contains validation errors
     * @param model      holder for model attributes
     * @param request    http request
     * @return view name
     */
    @RequestMapping(value = "/uploadXmlWithRedirect", method = RequestMethod.POST)
    public String uploadWithRedirectToWebForm(@Valid @ModelAttribute UploadForm uploadForm, BindingResult result,
            Model model, HttpServletRequest request) {
        if (!result.hasErrors()) {
            saveFiles(uploadForm);
            Collection<UserFile> files = uploadForm.getUserFiles();
            if (files.size() == 1) {
                UserFile file = files.iterator().next();
                Collection<ProjectFile> availableWebForms = webFormService
                        .findWebFormsForSchemas(Arrays.asList(file.getXmlSchema()));
                if (availableWebForms.size() == 1) {
                    int fileId = file.getId();
                    ProjectFile webform = availableWebForms.iterator().next();
                    String webformPath = webformUrlProvider.getWebformPath(webform);
                    String contextPath = request.getContextPath();
                    String downloadUrl = contextPath + "/download/user_file?fileId=" + fileId;
                    return "redirect:" + webformPath + "fileId=" + fileId + "&instance=" + downloadUrl
                            + "&base_uri=" + contextPath;
                }
                model.addAttribute("message", "File '" + file.getName() + "' uploaded successfully");
            }
        }
        return welcome(model);
    }

    /**
     * Removes selected user files.
     *
     * @param selectedUserFile ids of files to be removed
     * @param model            holder for model attributes
     * @return view name
     */
    @RequestMapping(value = "/remove/files")
    public String removeUserFiles(@RequestParam(required = false) int[] selectedUserFile, Model model) {
        if (selectedUserFile != null) {
            userFileService.removeFilesById(selectedUserFile);
            model.addAttribute("message", "Selected files removed successfully");
        }
        return welcome(model);
    }

    /**
     * Populates model with user files that were selected to be changed.
     *
     * @param selectedUserFile ids of files to be edited
     * @param model            holder for model attributes
     * @return view name
     */
    @RequestMapping(value = "/edit")
    public String editUserFile(@RequestParam(required = false) List<Integer> selectedUserFile, Model model) {
        List<UserFile> userFiles = new ArrayList<UserFile>();

        for (Integer fileId : selectedUserFile) {
            userFiles.add(userFileService.getById(fileId));
        }

        model.addAttribute("userFileList", new UserFileList(userFiles));
        return welcome(model);
    }

    /**
     * Save edited user files to database.
     *
     * @param userFiles     list of user files to be persisted
     * @param bindingResult validation errors
     * @param model         holder for model attributes
     * @return view name
     */
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @Transactional
    public String saveUserFile(@Valid @ModelAttribute UserFileList userFiles, BindingResult bindingResult,
            Model model) {

        for (UserFile userFile : userFiles.getUserFiles()) {
            UserFile file = userFileService.getById(userFile.getId());
            file.setName(userFile.getName());
            userFileService.update(file);
        }
        model.addAttribute("userFileList", new UserFileList());
        model.addAttribute("message", "File(s) updated successfully");
        return welcome(model);
    }

    /**
     * Update file content action. The action is called from XForms and it returns XML formatted result.
     *
     * @param fileId  file id to update
     * @param request current request
     * @return response as application/xml generated by {@link org.springframework.oxm.jaxb.Jaxb2Marshaller}
     */
    @RequestMapping(value = "/saveXml", method = RequestMethod.POST)
    @ResponseBody
    @Transactional
    public XmlSaveResult saveXml(@RequestParam int fileId, HttpServletRequest request) {
        try {
            LOGGER.info("/saveXml fileId=" + fileId + "; sessionid="
                    + this.requestBasedUserIdProvider.getUserId(request));

            byte[] fileContent = getContentFromRequest(request);
            return updateFileContent(fileId, request, fileContent);
        } catch (Exception e) {
            LOGGER.error("Unable to save file: " + e.toString(), e);
            return XmlSaveResult.valueOfError(e.toString());
        }
    }

    /**
     * Update file content converting json back to XML.
     *
     * @param fileId  file id to update
     * @param request current request
     * @param model   holder for model attributes
     * @return redirect string
     */
    @RequestMapping(value = "/saveXml", consumes = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
    @ResponseBody
    @Transactional
    public XmlSaveResult saveJsonAsXml(@RequestParam int fileId, HttpServletRequest request, Model model) {

        try {
            LOGGER.info("/saveXml fileId=" + fileId + "; sessionid="
                    + this.requestBasedUserIdProvider.getUserId(request));

            byte[] xml = jsonToXMLConverter.convertJsonToXml(getContentFromRequest(request));
            XmlSaveResult xmlSaveResult = updateFileContent(fileId, request, xml);
            LOGGER.info("Converting json to XML ended up with result=" + xmlSaveResult);
            return xmlSaveResult;
        } catch (Exception e) {
            LOGGER.error("Unable to save file: " + e.toString(), e);
            return XmlSaveResult.valueOfError(e.toString());
        }
    }

    /**
     * This is STEP 1 in generating new WebForm. New file with form parameters will be saved to storage.
     *
     * @param formId  webform id
     * @param request current request
     * @return redirection URL of webform. Keeps user one the same page.
     * @throws FileNotAvailableException if empty instance URL is filled for selected webform, but the resource is not available.
     */
    @RequestMapping(value = "/startWebform")
    public String startWebFormSaveFile(@RequestParam int formId, HttpServletRequest request)
            throws FileNotAvailableException {
        userFileService.saveBasedOnWebForm(new UserFile(), webFormService.findActiveWebFormById(formId));
        String absolutePath = "";
        String baseUri = "&base_uri=";
        if (StringUtils.isNotEmpty(request.getParameter("base_uri"))) {
            baseUri += request.getParameter("base_uri");
            absolutePath = (request.getParameter("base_uri").startsWith("http")) ? request.getParameter("base_uri")
                    : "";
        } else {
            baseUri += request.getContextPath();
        }

        return "redirect:" + (StringUtils.isEmpty(absolutePath) ? "/" : absolutePath);
    }

    /**
     * This is STEP 2 in generating new WebForm. Form content will be loaded from storage and written to response. After that
     * response must be handled by {@link de.betterform.agent.web.filter.XFormsFilter}. Filter mapping in web.xml should match with
     * mapping of this method.
     *
     * @param formId   webform id
     * @param response current response
     * @throws IOException in case if writing of xForm to response failed
     */
    @RequestMapping(value = "/xform")
    @Transactional
    public void startWebFormWriteFormToResponse(@RequestParam int formId, HttpServletRequest request,
            HttpServletResponse response) throws IOException {

        String webCookie = cookieValueManager.getUserId(request);
        if (isEmpty(webCookie)) {
            // redirect to the exact same page if there is no webq cookie written yet
            // this solves the problem of xforms modules not recognizing the user, because they are rendered server-side
            // this way the cookie will be injected by the interceptor and the user will be recognized after the redirect
            LOGGER.info("WebQCookie not found, redirecting....");
            String redirect;
            StringBuffer requestURL = request.getRequestURL();
            String queryString = request.getQueryString();
            if (queryString == null) {
                redirect = requestURL.toString();
            } else {
                redirect = requestURL.append('?').append(queryString).toString();
            }
            response.sendRedirect(redirect);
            return;
        }

        ProjectFile webForm = webFormService.findWebFormById(formId);
        byte[] fileContent = webForm.getFileContent();
        response.setContentLength(fileContent.length);
        response.setContentType("application/xhtml+xml;charset=utf-8");
        OutputStream outputStream = response.getOutputStream();
        IOUtils.write(fileContent, outputStream);
        outputStream.flush();
    }

    /**
     * Returns FileInfo object in XML format. FileInfo holds public data about UserFile and relevant conversions. The returned XML
     * contains links to download, delete and convert the file.
     *
     * @param fileId   UserFile id
     * @param request  http request
     * @param response http response
     * @return response as application/xml generated by {@link org.springframework.oxm.jaxb.Jaxb2Marshaller}
     */
    @RequestMapping(value = "/file/info", method = RequestMethod.GET)
    @ResponseBody
    public FileInfo getFileInfo(@RequestParam int fileId, HttpServletRequest request,
            HttpServletResponse response) {

        UserFile userFile = userFileService.getById(fileId);
        FileInfo fileInfo = new FileInfo();
        if (userFile == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        } else {
            fileInfo = fileInfoConverter.convert(userFile);
        }
        return fileInfo;
    }

    /**
     * Updates file content in storage.
     *
     * @param fileId      file id to update
     * @param request     current request
     * @param fileContent new file content
     * @return save result
     */
    private XmlSaveResult updateFileContent(int fileId, HttpServletRequest request, byte[] fileContent) {
        UserFile file = userFileHelper.getUserFile(fileId, request);

        if (file == null) {
            return XmlSaveResult.valueOfError("File is not available.");
        }
        file.setContent(fileContent);
        if (file.isFromCdr()) {
            String restricted = request.getParameter("restricted");
            file.setApplyRestriction(StringUtils.isNotEmpty(restricted));
            file.setRestricted(Boolean.valueOf(restricted));
            file.setConversionId(request.getParameter("xsl"));
            return envelopeService.pushXmlFile(file);
        }
        userFileService.updateContent(file);
        return XmlSaveResult.valueOfSuccess();
    }

    /**
     * Gets content from request.
     *
     * @param request request to get content from
     * @return content as byte array
     */
    private byte[] getContentFromRequest(HttpServletRequest request) {
        InputStream input = null;
        try {
            input = request.getInputStream();
            return IOUtils.toByteArray(input);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    /**
     * Save files attached to upload form.
     *
     * @param uploadForm upload form
     */
    private void saveFiles(UploadForm uploadForm) {
        for (UserFile userFile : uploadForm.getUserFiles()) {
            userFileService.save(userFile);
        }
    }

    /**
     * Loads and sets conversions for files uploaded by user.
     *
     * @return all uploaded files with available conversions set.
     */
    private Collection<UserFile> allFilesWithConversions() {
        Collection<UserFile> userFiles = userFileService.allUploadedFiles();
        for (UserFile userFile : userFiles) {
            userFile.setAvailableConversions(conversionService.conversionsFor(userFile.getXmlSchema()));
        }
        return userFiles;
    }

    /**
     * Loads all active webforms.
     *
     * @return collection of active webforms.
     */
    private Collection<ProjectFile> allWebForms() {

        Collection<ProjectFile> allWebforms = webFormService.getAllActiveWebForms();
        if (allWebforms != null) {
            for (ProjectFile webform : allWebforms) {
                webform.setWebformLink(webformUrlProvider.getWebformPath(webform));
            }
        }
        return allWebforms;
    }
}