org.mitre.mpf.mvc.controller.ServerMediaController.java Source code

Java tutorial

Introduction

Here is the source code for org.mitre.mpf.mvc.controller.ServerMediaController.java

Source

/******************************************************************************
 * NOTICE                                                                     *
 *                                                                            *
 * This software (or technical data) was produced for the U.S. Government     *
 * under contract, and is subject to the Rights in Data-General Clause        *
 * 52.227-14, Alt. IV (DEC 2007).                                             *
 *                                                                            *
 * Copyright 2016 The MITRE Corporation. All Rights Reserved.                 *
 ******************************************************************************/

/******************************************************************************
 * Copyright 2016 The MITRE Corporation                                       *
 *                                                                            *
 * Licensed 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 org.mitre.mpf.mvc.controller;

import io.swagger.annotations.Api;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.comparator.LastModifiedFileComparator;
import org.apache.commons.io.comparator.NameFileComparator;
import org.apache.commons.lang3.tuple.Pair;
import org.mitre.mpf.mvc.model.DirectoryTreeNode;
import org.mitre.mpf.mvc.model.ServerMediaFile;
import org.mitre.mpf.mvc.model.ServerMediaFilteredListing;
import org.mitre.mpf.mvc.model.ServerMediaListing;
import org.mitre.mpf.wfm.util.IoUtils;
import org.mitre.mpf.wfm.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
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.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.util.stream.Collectors.toList;

@Api(value = "Server Media", description = "Server media retrieval")
@Controller
@Scope("request")
@Profile("website")
public class ServerMediaController {

    private static final Logger log = LoggerFactory.getLogger(ServerMediaController.class);

    public static final String DEFAULT_ERROR_VIEW = "error";
    public static final String SESSION_DIRECTORY_STRUCTURE = "DirectoryStructure";

    @Autowired
    private PropertiesUtil propertiesUtil;

    @Autowired
    private IoUtils ioUtils;

    private List<String> customExtensions = null;

    @PostConstruct
    public void postConstruct() {
        this.customExtensions = propertiesUtil.getServerMediaTreeCustomExtensions();
    }

    public static DirectoryTreeNode getAllDirectories(String nodePath, HttpSession session, boolean useSession,
            String uploadDir) {
        if (session.getAttribute(SESSION_DIRECTORY_STRUCTURE) != null && useSession) {
            log.debug("Using session directory structure");
            return (DirectoryTreeNode) session.getAttribute(SESSION_DIRECTORY_STRUCTURE);
        }

        DirectoryTreeNode node = null;
        try {
            node = DirectoryTreeNode.fillDirectoryTree(new DirectoryTreeNode(new File(nodePath)), uploadDir);
            session.setAttribute(SESSION_DIRECTORY_STRUCTURE, node);
        } catch (IOException e) {
            log.error("getAllDirectories error: " + e.getMessage());
        }

        return node;
    }

    @RequestMapping(value = { "/server/get-all-directories" }, method = RequestMethod.GET)
    @ResponseBody
    public DirectoryTreeNode getAllDirectories(HttpServletRequest request,
            @RequestParam(required = false) Boolean useUploadRoot,
            @RequestParam(required = false, defaultValue = "true") boolean useCache) {
        HttpSession session = request.getSession();
        String nodePath = propertiesUtil.getServerMediaTreeRoot();

        //if useUploadRoot is set it will take precedence over nodeFullPath
        DirectoryTreeNode node = getAllDirectories(nodePath, session, useCache,
                propertiesUtil.getRemoteMediaCacheDirectory().getAbsolutePath());
        if (useUploadRoot != null && useUploadRoot) {
            node = DirectoryTreeNode.find(node, propertiesUtil.getRemoteMediaCacheDirectory().getAbsolutePath());
        }
        return node;
    }

    @RequestMapping(value = { "/server/get-all-files" }, method = RequestMethod.GET)
    @ResponseBody
    public ServerMediaListing getAllFiles(@RequestParam(required = true) String fullPath,
            @RequestParam(required = false) boolean recurse) {
        File dir = new File(fullPath);
        if (!dir.isDirectory() && fullPath.startsWith(propertiesUtil.getServerMediaTreeRoot())) {
            return null;
        }

        List<ServerMediaFile> mediaFiles = new ArrayList<>();
        if (recurse) {
            mediaFiles = getRemoteMediaFilesRecursive(dir);
        } else {
            for (File file : dir.listFiles()) {
                if (file.isFile()) {
                    String mimeType = ioUtils.getMimeType(file.getAbsolutePath());
                    mediaFiles.add(new ServerMediaFile(file, mimeType));
                }
            }
        }
        return new ServerMediaListing(mediaFiles);
    }

    private List<ServerMediaFile> getRemoteMediaFilesRecursive(File root) {
        try {
            return Files.walk(root.toPath()).filter(Files::isRegularFile).map(Path::toFile)
                    .map(f -> Pair.of(f, ioUtils.getMimeType(f.getAbsolutePath())))
                    .filter(p -> p.getRight() != null).map(p -> new ServerMediaFile(p.getLeft(), p.getRight()))
                    .collect(toList());
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    //https://datatables.net/manual/server-side#Sent-parameters
    //draw is the counter of how many times it has called back
    //length is how many to return
    //start is offset from 0
    //search is string to filter
    @RequestMapping(value = { "/server/get-all-files-filtered" }, method = RequestMethod.POST)
    @ResponseBody
    public ServerMediaFilteredListing getAllFilesFiltered(
            @RequestParam(value = "fullPath", required = true) String fullPath,
            @RequestParam(value = "draw", required = false) int draw,
            @RequestParam(value = "start", required = false) int start,
            @RequestParam(value = "length", required = false) int length,
            @RequestParam(value = "search", required = false) String search,
            @RequestParam(value = "sort", required = false) String sort) {
        log.debug("Params fullPath:{} draw:{} start:{},length:{},search:{} ", fullPath, draw, start, length, search,
                sort);

        File dir = new File(fullPath);
        if (!dir.isDirectory() && fullPath.startsWith(propertiesUtil.getServerMediaTreeRoot()))
            return null;//security check

        File[] files = dir.listFiles(File::isFile);

        //sort it by filename modified date (most current first)
        if (sort != null && sort == "lastModified") {
            Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
        } else {
            Arrays.sort(files, NameFileComparator.NAME_INSENSITIVE_COMPARATOR
                    // Then make capital letters come before lowercase
                    .thenComparing(NameFileComparator.NAME_COMPARATOR));
        }

        //handle search
        if (search != null && search.length() > 0) {
            List<File> search_results = new ArrayList<File>();
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                if (files[i].getName().toLowerCase().contains(search.toLowerCase())) {
                    search_results.add(file);
                }
            }
            files = new File[search_results.size()];
            files = search_results.toArray(files);
        }

        //filter by approved list of content type
        List<File> contentFiltered = new ArrayList<File>();
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            if (ioUtils.isApprovedFile(file)) {
                contentFiltered.add(file);
            }
        }
        files = new File[contentFiltered.size()];
        files = contentFiltered.toArray(files);

        int records_total = files.length;
        int records_filtered = records_total;// Total records, after filtering (i.e. the total number of records after filtering has been applied - not just the number of records being returned for this page of data).

        //handle paging
        int end = start + length;
        end = (end > files.length) ? files.length : end;
        start = (start <= end) ? start : end;
        File[] filtered = Arrays.copyOfRange(files, start, end);

        List<ServerMediaFile> mediaFiles = new ArrayList<>();
        //build output
        for (int i = 0; i < filtered.length; i++) {
            File file = filtered[i];
            if (ioUtils.isApprovedFile(file)) {
                mediaFiles.add(new ServerMediaFile(file, ioUtils.getMimeType(file.getAbsolutePath())));
            }
        }

        return new ServerMediaFilteredListing(draw, records_filtered, records_total, mediaFiles);
    }

    /***
     *
     * @param response
     * @param nodeFullPath
     * @throws IOException
     * @throws URISyntaxException
      */
    @RequestMapping(value = "/server/node-image", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public void serve(HttpServletResponse response,
            @RequestParam(value = "nodeFullPath", required = true) String nodeFullPath)
            throws IOException, URISyntaxException {
        //TODO: this set of lines is also used in the MarkupController - create a single method
        File f = new File(nodeFullPath);
        if (f.canRead()) {
            FileUtils.copyFile(f, response.getOutputStream());
            response.flushBuffer();
        } else {
            response.setStatus(404);
        }

        //TODO: add an image to return that is file not available and error retrieving file 
        //to resources to use when there are issues

        //TODO: adjust the content type based on the image type
        //response.setContentLength(MediaType.);      
    }
}