3

I'm trying to use Vaadin 8 FileDropTarget with a Tomcat server. The example code is little bit long, but maybe it will fit here:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

import com.vaadin.server.StreamVariable;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.dnd.FileDropTarget;

import hu.dynaxpress.base.mvc.DynaAbstractController;

@SuppressWarnings({ "serial", "rawtypes" })
public class FileStreamController extends DynaAbstractController {

    private VerticalLayout layout;
    private ProgressBar progress;

    @Override
    protected void onInit() {
        super.onInit();
        System.err.println("FileStreamController.onInit");
    }

    @Override
    protected void onEnter() {
        System.err.println("FileStreamController.onEnter");
        // https://vaadin.com/docs/v8/framework/components/components-upload.html

        layout = new VerticalLayout();

        final Label infoLabel = new Label("DROP A FILE ON THIS TEXT");
        infoLabel.setWidth(240.0f, Unit.PIXELS);        

        final VerticalLayout dropPane = new VerticalLayout(infoLabel);
        dropPane.setComponentAlignment(infoLabel, Alignment.MIDDLE_CENTER);
        dropPane.addStyleName("drop-area");
        dropPane.setSizeUndefined();
        dropPane.setWidth("100%");

        progress = new ProgressBar();
        progress.setIndeterminate(false);
        progress.setVisible(false);
        progress.setWidth("100%");
        dropPane.addComponent(progress);        
        layout.addComponent(dropPane);

        new FileDropTarget<>(dropPane, fileDropEvent -> {
            final long fileSizeLimit = 20 * 1024 * 1024 * 1024; // 20GB

            fileDropEvent.getFiles().forEach(html5File -> {
                // html5File.getFileSize() always returns zero, but why?
                if (false && ( html5File.getFileSize() > fileSizeLimit) ) {
                    Notification.show(
                            "File rejected. Max size=" +fileSizeLimit+ ", actual="+html5File.getFileSize(),
                            Notification.Type.WARNING_MESSAGE);
                } else {
                    Label lbl = new Label(html5File.getFileName() + " size=" + html5File.getFileSize() + " " + html5File.getType());
                    lbl.setWidth("100%");
                    layout.addComponent(lbl);
                    final StreamVariable streamVariable = new StreamVariable() {

                        @Override
                        public OutputStream getOutputStream() {
                            try {
                                return new FileOutputStream("F:\\"+html5File.getFileName());
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                                throw new Error("F:\\"+html5File.getFileName());
                            } 
                        }

                        @Override
                        public boolean listenProgress() { return false; }

                        @Override
                        public void onProgress(final StreamingProgressEvent event) {
                            progress.setValue(
                                    event.getBytesReceived() / event.getContentLength()
                            );
                        }

                        @Override
                        public void streamingStarted(
                                final StreamingStartEvent event) {
                            progress.setVisible(true);
                            progress.setCaption(event.getFileName());
                        }

                        @Override
                        public void streamingFinished(
                                final StreamingEndEvent event) {
                            progress.setVisible(false);
                        }

                        @Override
                        public void streamingFailed(final StreamingErrorEvent event) {
                            progress.setVisible(false);
                        }

                        @Override
                        public boolean isInterrupted() { return false; }
                    };
                    html5File.setStreamVariable(streamVariable);
                    progress.setVisible(true);
                }
            });
        });

        setCompositionRoot(layout);     
    }


}

This code works, but it has terrible performance. In this MWE, the program writes all dropped files to the F:\ drive. It is a flash drive (I wanted to simulate streaming large files and see how much memory is consumed over time). But I found that this program writes out a 40MB file in 20 seconds. That is 2MB/sec speed. The server runs on localhost, the source file and the target F: drive are all on my local machine. If I simply copy the same file to the drive then it takes less than 2 seconds.

I have tried with another (very slow) flash drive too, and had similar results. When tomcat is streaming the file, then it is about 10-20 times slower.

Is there a way to make this faster? What am I doing wrong? I do not see any way to speed this up, because the streaming happens inside the component.

The second important (no related) question is that why can't I get the file size? See the comment in the code: "html5File.getFileSize() always returns zero, but why?" I have checked the POST headers from firefox debugger, and the browser sends the size of the file in an JSON/RPC call, before it sends the actual file data. So the server should know the file size before the first byte arrives.

nagylzs
  • 3,954
  • 6
  • 39
  • 70
  • Also tried to write 1.5GB file on a hard drive. Vaadin+Tomcat does 16.6MB/sec. A simple copy does 106MB/sec. My fried tried the same thing on Linux and it was much faster for him. – nagylzs Dec 12 '17 at 13:14
  • Also tried from Chrome, not just Firefox. There is no difference. – nagylzs Dec 12 '17 at 13:19
  • A friend of mine tried the very same example on Linux and for him, it wasn't slow. Looks like it is slow on windows only. But probably it is not an OS problem, because there are other programs I wrote and tested (on the same machine) and they were okay. – nagylzs Dec 13 '17 at 05:48
  • What happens if you do with the usual `Upload` component (https://vaadin.com/docs/v8/framework/components/components-upload.html)? Same speed limitation? – Steffen Harbich Dec 15 '17 at 14:02

0 Answers0