com.haulmont.cuba.gui.upload.FileUploading.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.gui.upload.FileUploading.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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 com.haulmont.cuba.gui.upload;

import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.executors.TaskLifeCycle;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.haulmont.bali.util.Preconditions.checkNotNullArgument;

@Component(FileUploadingAPI.NAME)
public class FileUploading implements FileUploadingAPI, FileUploadingMBean {

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

    protected Map<UUID, File> tempFiles = new ConcurrentHashMap<>();

    /**
     * Upload buffer size.
     * Default: 64 KB
     */
    protected static final int BUFFER_SIZE = 64 * 1024;

    protected String tempDir;

    @Inject
    protected UuidSource uuidSource;

    @Inject
    protected TimeSource timeSource;

    @Inject
    protected FileLoader fileLoader;

    @Inject
    public void setConfiguration(Configuration configuration) {
        tempDir = configuration.getConfig(GlobalConfig.class).getTempDir();
    }

    @Override
    public UUID saveFile(byte[] data) throws FileStorageException {
        checkNotNullArgument(data, "No file content");

        UUID uuid = uuidSource.createUuid();
        File dir = new File(tempDir);
        File file = new File(dir, uuid.toString());
        try {
            if (file.exists()) {
                throw new FileStorageException(FileStorageException.Type.FILE_ALREADY_EXISTS,
                        file.getAbsolutePath());
            }

            boolean failed = false;
            try (FileOutputStream os = new FileOutputStream(file)) {
                os.write(data);
            } catch (Exception ex) {
                failed = true;
            } finally {
                if (!failed) {
                    tempFiles.put(uuid, file);
                }
            }
        } catch (RuntimeException e) {
            throw new FileStorageException(FileStorageException.Type.IO_EXCEPTION, file.getAbsolutePath());
        }

        return uuid;
    }

    @Override
    public UUID saveFile(InputStream stream, UploadProgressListener listener) throws FileStorageException {
        checkNotNullArgument(stream, "Null input stream for save file");

        UUID uuid = uuidSource.createUuid();
        File dir = new File(tempDir);
        File file = new File(dir, uuid.toString());
        if (file.exists()) {
            throw new FileStorageException(FileStorageException.Type.FILE_ALREADY_EXISTS, file.getAbsolutePath());
        }

        try {
            boolean failed = false;
            try (FileOutputStream fileOutput = new FileOutputStream(file)) {
                byte buffer[] = new byte[BUFFER_SIZE];
                int bytesRead;
                int totalBytes = 0;
                while ((bytesRead = stream.read(buffer)) > 0) {
                    fileOutput.write(buffer, 0, bytesRead);
                    totalBytes += bytesRead;
                    if (listener != null)
                        listener.progressChanged(uuid, totalBytes);
                }
            } catch (Exception ex) {
                failed = true;
                throw ex;
            } finally {
                if (!failed)
                    tempFiles.put(uuid, file);
            }
        } catch (Exception ex) {
            throw new FileStorageException(FileStorageException.Type.IO_EXCEPTION, file.getAbsolutePath(), ex);
        }
        return uuid;
    }

    @Override
    public UUID createEmptyFile() throws FileStorageException {
        FileInfo fileInfo = createFileInternal();
        return fileInfo.getId();
    }

    @Override
    public FileInfo createFile() throws FileStorageException {
        return createFileInternal();
    }

    protected FileInfo createFileInternal() throws FileStorageException {
        UUID uuid = uuidSource.createUuid();
        File dir = new File(tempDir);
        File file = new File(dir, uuid.toString());

        if (file.exists()) {
            throw new FileStorageException(FileStorageException.Type.FILE_ALREADY_EXISTS, file.getAbsolutePath());
        }

        try {
            if (file.createNewFile())
                tempFiles.put(uuid, file);
            else
                throw new FileStorageException(FileStorageException.Type.FILE_ALREADY_EXISTS,
                        file.getAbsolutePath());
        } catch (IOException ex) {
            throw new FileStorageException(FileStorageException.Type.IO_EXCEPTION, file.getAbsolutePath());
        }

        return new FileInfo(file, uuid);
    }

    @Override
    public UUID createNewFileId() throws FileStorageException {
        UUID uuid = uuidSource.createUuid();
        File dir = new File(tempDir);
        File file = new File(dir, uuid.toString());
        if (file.exists()) {
            throw new FileStorageException(FileStorageException.Type.FILE_ALREADY_EXISTS, file.getAbsolutePath());
        }
        tempFiles.put(uuid, file);
        return uuid;
    }

    @Override
    public File getFile(UUID fileId) {
        return tempFiles.get(fileId);
    }

    @Override
    public FileDescriptor getFileDescriptor(UUID fileId, String name) {
        File file = getFile(fileId);
        if (file == null) {
            return null;
        }
        Metadata metadata = AppBeans.get(Metadata.NAME);

        FileDescriptor fDesc = metadata.create(FileDescriptor.class);

        fDesc.setSize(file.length());
        fDesc.setExtension(FilenameUtils.getExtension(name));
        fDesc.setName(name);
        fDesc.setCreateDate(timeSource.currentTimestamp());

        return fDesc;
    }

    @Override
    public void deleteFile(UUID fileId) throws FileStorageException {
        File file = tempFiles.remove(fileId);
        if (file != null) {
            if (file.exists()) {
                boolean res = file.delete();
                if (!res)
                    log.warn("Could not delete temp file " + file.getAbsolutePath());
            }
        }
    }

    @Override
    public void deleteFileLink(String fileName) {
        Map<UUID, File> clonedFileMap = new HashMap<>(tempFiles);
        Iterator<Map.Entry<UUID, File>> iterator = clonedFileMap.entrySet().iterator();
        UUID forDelete = null;
        while ((iterator.hasNext()) && (forDelete == null)) {
            Map.Entry<UUID, File> fileEntry = iterator.next();
            if (fileEntry.getValue().getAbsolutePath().equals(fileName)) {
                forDelete = fileEntry.getKey();
            }
        }

        if (forDelete != null) {
            tempFiles.remove(forDelete);
        }
    }

    @Override
    public void putFileIntoStorage(UUID fileId, FileDescriptor fileDescr) throws FileStorageException {
        try {
            uploadFileIntoStorage(fileId, fileDescr, null);
        } catch (InterruptedException e) {
            // should never happen
            throw new FileStorageException(FileStorageException.Type.IO_EXCEPTION, fileDescr.getId().toString());
        }

        deleteFile(fileId);
    }

    protected void uploadFileIntoStorage(UUID fileId, FileDescriptor fileDescr,
            @Nullable UploadToStorageProgressListener listener) throws FileStorageException, InterruptedException {

        checkNotNullArgument(fileDescr);

        File file = getFile(fileId);
        if (file == null) {
            throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, fileDescr.getName());
        }

        long fileSize = file.length();

        Supplier<InputStream> inputStreamSupplier = () -> {
            try {
                return new FileInputStream(file);
            } catch (FileNotFoundException e) {
                throw new FileLoader.InputStreamSupplierException(
                        "Temp file is not found " + file.getAbsolutePath());
            }
        };

        if (listener != null) {
            fileLoader.saveStream(fileDescr, inputStreamSupplier, transferredBytes -> {
                try {
                    listener.progressChanged(fileId, transferredBytes, fileSize);
                } catch (InterruptedException ie) {
                    // if thread is already interrupted we will restore interrupted flag
                    Thread.currentThread().interrupt();
                }
            });
        } else {
            fileLoader.saveStream(fileDescr, inputStreamSupplier);
        }
    }

    @Override
    public FileDescriptor putFileIntoStorage(final TaskLifeCycle<Long> taskLifeCycle)
            throws FileStorageException, InterruptedException {

        checkNotNullArgument(taskLifeCycle);

        UUID fileId = (UUID) taskLifeCycle.getParams().get("fileId");
        String fileName = (String) taskLifeCycle.getParams().get("fileName");

        checkNotNull(fileId);
        checkNotNull(fileName);

        UploadToStorageProgressListener progressListener = (fileId1, uploadedBytes, totalBytes) -> taskLifeCycle
                .publish(uploadedBytes);

        FileDescriptor fileDescriptor = getFileDescriptor(fileId, fileName);
        uploadFileIntoStorage(fileId, fileDescriptor, progressListener);

        deleteFile(fileId);

        return fileDescriptor;
    }

    @Override
    public void clearTempDirectory() {
        try {
            File dir = new File(tempDir);
            File[] files = dir.listFiles();
            if (files == null)
                throw new IllegalStateException("Not a directory: " + tempDir);
            Date currentDate = timeSource.currentTimestamp();
            for (File file : files) {
                Date fileDate = new Date(file.lastModified());
                Calendar calendar = new GregorianCalendar();
                calendar.setTime(fileDate);
                calendar.add(Calendar.DAY_OF_YEAR, 2);
                if (currentDate.compareTo(calendar.getTime()) > 0) {
                    deleteFileLink(file.getAbsolutePath());
                    if (!file.delete()) {
                        log.warn(String.format("Could not remove temp file %s", file.getName()));
                    }
                }
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }
    }

    @Override
    public String showTempFiles() {
        StringBuilder builder = new StringBuilder();
        Map<UUID, File> clonedFileMap = new HashMap<>(tempFiles);
        for (Map.Entry<UUID, File> fileEntry : clonedFileMap.entrySet()) {
            builder.append(fileEntry.getKey().toString()).append(" | ");
            Date lastModified = new Date(fileEntry.getValue().lastModified());
            DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
            builder.append(formatter.format(lastModified)).append("\n");
        }
        return builder.toString();
    }

    /**
     * Listener to be notified about the progress of uploading file from the temporary storage
     * into middleware FileStorage.
     */
    interface UploadToStorageProgressListener {
        /**
         * @param fileId        temporary file ID
         * @param uploadedBytes current uploaded bytes count
         * @param totalBytes    total contents size
         */
        void progressChanged(UUID fileId, long uploadedBytes, long totalBytes) throws InterruptedException;
    }
}