com.haulmont.cuba.desktop.gui.components.DesktopFileUploadField.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.desktop.gui.components.DesktopFileUploadField.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.desktop.gui.components;

import com.haulmont.bali.util.ParamsMap;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.chile.core.model.utils.InstanceUtils;
import com.haulmont.cuba.core.app.FileStorageService;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.desktop.gui.executors.impl.DesktopBackgroundWorker;
import com.haulmont.cuba.desktop.sys.DesktopToolTipManager;
import com.haulmont.cuba.gui.backgroundwork.BackgroundWorkProgressWindow;
import com.haulmont.cuba.gui.components.AbstractAction;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.compatibility.FileUploadFieldListenerWrapper;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.data.impl.WeakItemChangeListener;
import com.haulmont.cuba.gui.data.impl.WeakItemPropertyChangeListener;
import com.haulmont.cuba.gui.executors.BackgroundTask;
import com.haulmont.cuba.gui.executors.TaskLifeCycle;
import com.haulmont.cuba.gui.export.ExportDisplay;
import com.haulmont.cuba.gui.export.FileDataProvider;
import com.haulmont.cuba.gui.upload.FileUploadingAPI;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.io.*;
import java.util.*;

import static com.haulmont.cuba.gui.ComponentsHelper.handleFilteredAttributes;
import static com.haulmont.cuba.gui.upload.FileUploadingAPI.FileInfo;

public class DesktopFileUploadField extends DesktopAbstractUploadField<CubaFileUploadWrapper>
        implements FileUploadField {

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

    protected FileUploadingAPI fileUploading;
    protected Messages messages;
    protected ExportDisplay exportDisplay;

    protected FileContentProvider contentProvider;

    protected volatile boolean isUploadingState = false;

    protected String fileName;
    protected Button uploadButton;
    protected FileStoragePutMode mode = FileStoragePutMode.MANUAL;

    protected Datasource datasource;

    protected boolean updatingInstance;

    protected Datasource.ItemChangeListener itemChangeListener;
    protected Datasource.ItemChangeListener securityItemChangeListener;
    protected Datasource.ItemPropertyChangeListener itemPropertyChangeListener;

    protected UUID fileId;
    protected UUID tempFileId;

    protected List<FileUploadStartListener> fileUploadStartListeners; // lazily initialized list
    protected List<FileUploadFinishListener> fileUploadFinishListeners; // lazily initialized list
    protected List<FileUploadSucceedListener> fileUploadSucceedListeners; // lazily initialized list
    protected List<FileUploadErrorListener> fileUploadErrorListeners; // lazily initialized list

    protected List<BeforeValueClearListener> beforeValueClearListeners; // lazily initialized list
    protected List<AfterValueClearListener> afterValueClearListeners; // lazily initialized list

    protected FileDescriptor prevValue;

    public DesktopFileUploadField() {
        fileUploading = AppBeans.get(FileUploadingAPI.NAME);
        messages = AppBeans.get(Messages.NAME);
        exportDisplay = AppBeans.get(ExportDisplay.NAME);

        ComponentsFactory componentsFactory = AppBeans.get(ComponentsFactory.NAME);
        uploadButton = (Button) componentsFactory.createComponent(Button.NAME);
        final JFileChooser fileChooser = new JFileChooser();
        uploadButton.setAction(new AbstractAction("") {
            @Override
            public void actionPerform(Component component) {
                if (fileChooser.showOpenDialog(uploadButton.unwrap(JButton.class)) == JFileChooser.APPROVE_OPTION) {
                    uploadFile(fileChooser.getSelectedFile());
                }
            }
        });
        uploadButton.setCaption(messages.getMessage(getClass(), "export.selectFile"));

        initImpl();
    }

    protected void initImpl() {
        impl = new CubaFileUploadWrapper(uploadButton);
        impl.setFileNameButtonClickListener(() -> {
            FileDescriptor value = getValue();
            if (value == null)
                return;

            switch (mode) {
            case MANUAL:
                String name = getFileName();
                String fileName1 = StringUtils.isEmpty(name) ? value.getName() : name;
                exportDisplay.show(DesktopFileUploadField.this::getFileContent, fileName1);
                break;
            case IMMEDIATE:
                exportDisplay.show(value);
            }
        });
        impl.setClearButtonListener(this::clearButtonClicked);
    }

    protected void clearButtonClicked() {
        boolean preventClearAction = false;
        if (beforeValueClearListeners != null) {
            BeforeValueClearEvent beforeValueClearEvent = new BeforeValueClearEvent(this);
            for (BeforeValueClearListener listener : new ArrayList<>(beforeValueClearListeners)) {
                listener.beforeValueClearPerformed(beforeValueClearEvent);
            }
            preventClearAction = beforeValueClearEvent.isClearPrevented();
        }

        if (!preventClearAction) {
            setValue(null);
            fileName = null;
        }

        if (afterValueClearListeners != null) {
            AfterValueClearEvent afterValueClearEvent = new AfterValueClearEvent(this, !preventClearAction);
            for (AfterValueClearListener listener : new ArrayList<>(afterValueClearListeners)) {
                listener.afterValueClearPerformed(afterValueClearEvent);
            }
        }
    }

    protected void uploadFile(File file) {
        if (file.length() > getActualFileSizeLimit()) {
            String warningMsg = messages.formatMainMessage("upload.fileTooBig.message", file.getName(),
                    getFileSizeLimitString());
            getFrame().showNotification(warningMsg, Frame.NotificationType.WARNING);
        } else if (hasInvalidExtension(file.getName())) {
            String warningMsg = messages.formatMainMessage("upload.fileIncorrectExtension.message", file.getName());
            getFrame().showNotification(warningMsg, Frame.NotificationType.WARNING);
        } else {
            boolean success = true;
            try {
                isUploadingState = true;

                fileName = file.getName();
                fireFileUploadStart(file.getName(), file.length());

                FileInfo fileInfo = fileUploading.createFile();
                tempFileId = fileInfo.getId();
                File tmpFile = fileInfo.getFile();

                FileUtils.copyFile(file, tmpFile);

                fileId = tempFileId;
                saveFile(getFileDescriptor());

                isUploadingState = false;
            } catch (Exception ex) {
                success = false;
                try {
                    fileUploading.deleteFile(tempFileId);
                    tempFileId = null;
                } catch (FileStorageException e) {
                    throw new RuntimeException("Unable to delete file from temp storage", ex);
                }

                fireFileUploadError(file.getName(), file.length(), ex);
            } finally {
                fireFileUploadFinish(file.getName(), file.length());
            }

            if (success) {
                fireFileUploadSucceed(file.getName(), file.length());
            }
        }
    }

    protected void saveFile(FileDescriptor fileDescriptor) {
        switch (mode) {
        case MANUAL:
            setValue(fileDescriptor);
            break;
        case IMMEDIATE:
            BackgroundTask<Long, FileDescriptor> uploadProgress = new BackgroundTask<Long, FileDescriptor>(2400,
                    getFrame()) {
                @Override
                public Map<String, Object> getParams() {
                    return ParamsMap.of("fileId", fileId, "fileName", getFileName());
                }

                @Override
                public FileDescriptor run(final TaskLifeCycle<Long> taskLifeCycle) throws Exception {
                    return fileUploading.putFileIntoStorage(taskLifeCycle);
                }

                @Override
                public void done(FileDescriptor result) {
                    FileDescriptor descriptor = commitFileDescriptor(result);
                    setValue(descriptor);
                }
            };

            long fileSize = fileUploading.getFile(fileId).length();
            BackgroundWorkProgressWindow.show(uploadProgress,
                    messages.getMainMessage("FileUploadField.uploadingFile"), null, fileSize, true, true);
            break;
        }
    }

    protected FileDescriptor commitFileDescriptor(FileDescriptor fileDescriptor) {
        if (datasource != null) {
            return datasource.getDataSupplier().commit(fileDescriptor);
        }

        if (getFrame().getDsContext().getDataSupplier() != null) {
            return getFrame().getDsContext().getDataSupplier().commit(fileDescriptor);
        }

        return AppBeans.get(DataManager.class).commit(fileDescriptor);
    }

    @Override
    public void setWidth(String width) {
        super.setWidth(width);
        impl.setWidth(width);
    }

    @Override
    public void setHeight(String height) {
        super.setHeight(height);
        impl.setHeight(height);
    }

    protected boolean hasInvalidExtension(String name) {
        Set<String> permittedExtensions = getPermittedExtensions();
        if (permittedExtensions != null && !permittedExtensions.isEmpty()) {
            if (name.lastIndexOf(".") > 0) {
                String fileExtension = name.substring(name.lastIndexOf("."), name.length());
                return !permittedExtensions.contains(fileExtension.toLowerCase());
            } else {
                return true;
            }
        }
        return false;
    }

    @Override
    public String getFileName() {
        if (StringUtils.isEmpty(fileName))
            return null;

        String[] strings = fileName.split("[/\\\\]");
        return strings[strings.length - 1];
    }

    @Override
    public FileDescriptor getFileDescriptor() {
        if (fileId != null) {
            return fileUploading.getFileDescriptor(fileId, fileName);
        } else {
            return null;
        }
    }

    @Override
    public byte[] getBytes() {
        byte[] bytes = null;
        try {
            if (fileId != null) {
                File file = fileUploading.getFile(fileId);
                FileInputStream fileInputStream = new FileInputStream(file);
                ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
                IOUtils.copy(fileInputStream, byteOutput);
                bytes = byteOutput.toByteArray();
            }
        } catch (Exception e) {
            throw new RuntimeException("Unable to read file content from temp storage", e);
        }

        return bytes;
    }

    @Override
    public UUID getFileId() {
        return fileId;
    }

    @Override
    public void addListener(Listener listener) {
        FileUploadFieldListenerWrapper wrapper = new FileUploadFieldListenerWrapper(listener);

        addFileUploadStartListener(wrapper);
        addFileUploadErrorListener(wrapper);
        addFileUploadFinishListener(wrapper);
        addFileUploadSucceedListener(wrapper);
    }

    @Override
    public void removeListener(Listener listener) {
        FileUploadFieldListenerWrapper wrapper = new FileUploadFieldListenerWrapper(listener);

        removeFileUploadStartListener(wrapper);
        removeFileUploadErrorListener(wrapper);
        removeFileUploadFinishListener(wrapper);
        removeFileUploadSucceedListener(wrapper);
    }

    @Override
    protected void setCaptionToComponent(String caption) {
        super.setCaptionToComponent(caption);

        impl.setCaption(caption);
        requestContainerUpdate();
    }

    @Override
    public <T> T getValue() {
        return (T) prevValue;
    }

    @Override
    public void setValue(Object value) {
        DesktopBackgroundWorker.checkSwingUIAccess();

        if (!Objects.equals(prevValue, value)) {
            updateInstance(value);
            updateComponent((FileDescriptor) value);
            fireChangeListeners(value);
        } else {
            updateComponent(prevValue);
        }

        if (value == null || !PersistenceHelper.isNew(value)) {
            fileId = null;
            tempFileId = null;
        }
    }

    @Override
    protected void setEditableToComponent(boolean editable) {
        impl.setEditable(editable);
    }

    @Override
    public void setRequired(boolean required) {
        super.setRequired(required);
        impl.setRequired(required);
    }

    @Override
    public boolean isRequired() {
        return impl.isRequired();
    }

    @Override
    public void requestFocus() {
        super.requestFocus();
        uploadButton.requestFocus();
    }

    @Override
    public void setDescription(String description) {
        impl.setDescription(description);
        impl.setToolTipText(description);
        DesktopToolTipManager.getInstance().registerTooltip(impl);
        requestContainerUpdate();
    }

    @Override
    public String getDescription() {
        return impl.getDescription();
    }

    protected void fireFileUploadStart(String fileName, long contentLength) {
        if (fileUploadStartListeners != null && !fileUploadStartListeners.isEmpty()) {
            FileUploadStartEvent e = new FileUploadStartEvent(fileName, contentLength);
            for (FileUploadStartListener listener : new ArrayList<>(fileUploadStartListeners)) {
                listener.fileUploadStart(e);
            }
        }
    }

    protected void fireFileUploadFinish(String fileName, long contentLength) {
        if (fileUploadFinishListeners != null && !fileUploadFinishListeners.isEmpty()) {
            FileUploadFinishEvent e = new FileUploadFinishEvent(fileName, contentLength);
            for (FileUploadFinishListener listener : new ArrayList<>(fileUploadFinishListeners)) {
                listener.fileUploadFinish(e);
            }
        }
    }

    protected void fireFileUploadError(String fileName, long contentLength, Exception cause) {
        if (fileUploadErrorListeners != null && !fileUploadErrorListeners.isEmpty()) {
            FileUploadErrorEvent e = new FileUploadErrorEvent(fileName, contentLength, cause);
            for (FileUploadErrorListener listener : new ArrayList<>(fileUploadErrorListeners)) {
                listener.fileUploadError(e);
            }
        }
    }

    protected void fireFileUploadSucceed(String fileName, long contentLength) {
        if (fileUploadSucceedListeners != null && !fileUploadSucceedListeners.isEmpty()) {
            FileUploadSucceedEvent e = new FileUploadSucceedEvent(fileName, contentLength);
            for (FileUploadSucceedListener listener : new ArrayList<>(fileUploadSucceedListeners)) {
                listener.fileUploadSucceed(e);
            }
        }
    }

    @Override
    public void addFileUploadStartListener(FileUploadStartListener listener) {
        if (fileUploadStartListeners == null) {
            fileUploadStartListeners = new ArrayList<>();
        }
        if (!fileUploadStartListeners.contains(listener)) {
            fileUploadStartListeners.add(listener);
        }
    }

    @Override
    public void removeFileUploadStartListener(FileUploadStartListener listener) {
        if (fileUploadStartListeners != null) {
            fileUploadStartListeners.remove(listener);
        }
    }

    @Override
    public void addFileUploadFinishListener(FileUploadFinishListener listener) {
        if (fileUploadFinishListeners == null) {
            fileUploadFinishListeners = new ArrayList<>();
        }
        if (!fileUploadFinishListeners.contains(listener)) {
            fileUploadFinishListeners.add(listener);
        }
    }

    @Override
    public void removeFileUploadFinishListener(FileUploadFinishListener listener) {
        if (fileUploadFinishListeners != null) {
            fileUploadFinishListeners.remove(listener);
        }
    }

    @Override
    public void addFileUploadErrorListener(FileUploadErrorListener listener) {
        if (fileUploadErrorListeners == null) {
            fileUploadErrorListeners = new ArrayList<>();
        }
        if (!fileUploadErrorListeners.isEmpty()) {
            fileUploadErrorListeners.add(listener);
        }
    }

    @Override
    public void removeFileUploadErrorListener(FileUploadErrorListener listener) {
        if (fileUploadErrorListeners != null) {
            fileUploadErrorListeners.remove(listener);
        }
    }

    @Override
    public void addFileUploadSucceedListener(FileUploadSucceedListener listener) {
        if (fileUploadSucceedListeners == null) {
            fileUploadSucceedListeners = new ArrayList<>();
        }
        if (!fileUploadSucceedListeners.contains(listener)) {
            fileUploadSucceedListeners.add(listener);
        }
    }

    @Override
    public void removeFileUploadSucceedListener(FileUploadSucceedListener listener) {
        if (fileUploadSucceedListeners != null) {
            fileUploadSucceedListeners.remove(listener);
        }
    }

    protected void fireChangeListeners(Object newValue) {
        Object oldValue = prevValue;
        prevValue = (FileDescriptor) newValue;
        if (!Objects.equals(oldValue, newValue)) {
            fireValueChanged(oldValue, newValue);
        }
    }

    @Override
    public void setFileSizeLimit(long fileSizeLimit) {
        this.fileSizeLimit = fileSizeLimit;
    }

    @Override
    public InputStream getFileContent() {
        if (contentProvider != null) {
            return contentProvider.provide();
        }

        FileDescriptor fileDescriptor = getValue();
        switch (mode) {
        case MANUAL:
            if (fileId == null) {
                return new FileDataProvider(fileDescriptor).provide();
            }

            File file = fileUploading.getFile(fileId);
            if (file != null) {
                try {
                    return new FileInputStream(file);
                } catch (FileNotFoundException e) {
                    log.error("Unable to get content of {}", file, e);
                }
                return null;
            }

            FileStorageService fileStorageService = AppBeans.get(FileStorageService.NAME);

            try {
                if (fileStorageService.fileExists(fileDescriptor)) {
                    return new FileDataProvider(fileDescriptor).provide();
                }
            } catch (FileStorageException e) {
                log.error("Unable to get content of {}", fileDescriptor, e);
                return null;
            }
            break;
        case IMMEDIATE:
            if (fileDescriptor != null) {
                return new FileDataProvider(fileDescriptor).provide();
            }
        }
        return null;
    }

    @Override
    public void setContentProvider(FileContentProvider contentProvider) {
        this.contentProvider = contentProvider;
    }

    @Override
    public FileContentProvider getContentProvider() {
        return contentProvider;
    }

    @Override
    public String getAccept() {
        // do nothing
        return null;
    }

    @Override
    public void setAccept(String accept) {
        // do nothing
    }

    @Override
    public Datasource getDatasource() {
        return datasource;
    }

    @Override
    public MetaProperty getMetaProperty() {
        return metaProperty;
    }

    @Override
    public MetaPropertyPath getMetaPropertyPath() {
        return metaPropertyPath;
    }

    @Override
    public void setDatasource(Datasource datasource, String property) {
        this.datasource = datasource;

        if (datasource == null) {
            setValue(null);
            return;
        }

        MetaClass metaClass = datasource.getMetaClass();
        resolveMetaPropertyPath(metaClass, property);

        itemChangeListener = e -> {
            if (updatingInstance)
                return;
            FileDescriptor descriptor = InstanceUtils.getValueEx(e.getItem(), metaPropertyPath.getPath());
            updateComponent(descriptor);
            fireChangeListeners(descriptor);
        };
        // noinspection unchecked
        datasource.addItemChangeListener(new WeakItemChangeListener(datasource, itemChangeListener));

        itemPropertyChangeListener = e -> {
            if (updatingInstance)
                return;
            if (e.getProperty().equals(metaPropertyPath.toString())) {
                updateComponent((FileDescriptor) e.getValue());
                fireChangeListeners(e.getValue());
            }
        };
        // noinspection unchecked
        datasource.addItemPropertyChangeListener(
                new WeakItemPropertyChangeListener(datasource, itemPropertyChangeListener));

        initRequired(metaPropertyPath);

        if ((datasource.getState() == Datasource.State.VALID) && (datasource.getItem() != null)) {
            Object newValue = InstanceUtils.getValueEx(datasource.getItem(), metaPropertyPath.getPath());
            FileDescriptor fileDescriptor = (FileDescriptor) newValue;
            updateComponent(fileDescriptor);
            fireChangeListeners(newValue);
        }

        if (metaProperty.isReadOnly()) {
            setEditable(false);
        }

        handleFilteredAttributes(this, this.datasource, metaPropertyPath);
        securityItemChangeListener = e -> handleFilteredAttributes(this, this.datasource, metaPropertyPath);
        // noinspection unchecked
        this.datasource
                .addItemChangeListener(new WeakItemChangeListener(this.datasource, securityItemChangeListener));

        initBeanValidator();
    }

    protected void updateInstance(Object value) {
        updatingInstance = true;
        try {
            if (datasource != null && metaProperty != null && datasource.getItem() != null) {
                datasource.getItem().setValueEx(metaPropertyPath.toString(), value);
            }
        } finally {
            updatingInstance = false;
        }
    }

    protected void updateComponent(FileDescriptor fileDescriptor) {
        if (fileDescriptor != null) {
            impl.setFileName(fileDescriptor.getName());
        } else {
            impl.setFileName(null);
        }
    }

    @Override
    public boolean isShowFileName() {
        return impl.isShowFileName();
    }

    @Override
    public void setShowFileName(boolean showFileName) {
        impl.setShowFileName(showFileName);
    }

    @Override
    public FileStoragePutMode getMode() {
        return mode;
    }

    @Override
    public void setMode(FileStoragePutMode mode) {
        this.mode = mode;
    }

    /*
     * Upload button
     */
    @Override
    public String getUploadButtonCaption() {
        return impl.getUploadButtonCaption();
    }

    @Override
    public void setUploadButtonCaption(String caption) {
        impl.setUploadButtonCaption(caption);
    }

    @Override
    public void setUploadButtonIcon(String icon) {
        impl.setUploadButtonIcon(icon);
    }

    @Override
    public String getUploadButtonIcon() {
        return impl.getUploadButtonIcon();
    }

    @Override
    public void setUploadButtonDescription(String description) {
        impl.setUploadButtonDescription(description);
    }

    @Override
    public String getUploadButtonDescription() {
        return impl.getUploadButtonDescription();
    }

    /*
     * Clear button
     */
    @Override
    public void setShowClearButton(boolean showClearButton) {
        impl.setShowClearButton(showClearButton);
    }

    @Override
    public boolean isShowClearButton() {
        return impl.isShowClearButton();
    }

    @Override
    public void setClearButtonCaption(String caption) {
        impl.setClearButtonCaption(caption);
    }

    @Override
    public String getClearButtonCaption() {
        return impl.getClearButtonCaption();
    }

    @Override
    public void setClearButtonIcon(String icon) {
        impl.setClearButtonIcon(icon);
    }

    @Override
    public String getClearButtonIcon() {
        return impl.getClearButtonIcon();
    }

    @Override
    public void setClearButtonDescription(String description) {
        impl.setClearButtonDescription(description);
    }

    @Override
    public String getClearButtonDescription() {
        return impl.getClearButtonDescription();
    }

    @Override
    public void addBeforeValueClearListener(BeforeValueClearListener listener) {
        if (beforeValueClearListeners == null) {
            beforeValueClearListeners = new ArrayList<>();
        }
        if (!beforeValueClearListeners.contains(listener)) {
            beforeValueClearListeners.add(listener);
        }
    }

    @Override
    public void removeBeforeValueClearListener(BeforeValueClearListener listener) {
        if (beforeValueClearListeners != null) {
            beforeValueClearListeners.remove(listener);
        }
    }

    @Override
    public void addAfterValueClearListener(AfterValueClearListener listener) {
        if (afterValueClearListeners == null) {
            afterValueClearListeners = new ArrayList<>();
        }
        if (!afterValueClearListeners.contains(listener)) {
            afterValueClearListeners.add(listener);
        }
    }

    @Override
    public void removeAfterValueClearListener(AfterValueClearListener listener) {
        if (afterValueClearListeners != null) {
            afterValueClearListeners.remove(listener);
        }
    }

    @Override
    public void commit() {
        // do nothing
    }

    @Override
    public void discard() {
        // do nothing
    }

    @Override
    public boolean isBuffered() {
        // do nothing
        return false;
    }

    @Override
    public void setBuffered(boolean buffered) {
        // do nothing
    }

    @Override
    public boolean isModified() {
        // do nothing
        return false;
    }
}