FileDescriptor Issues with Manual Upload

HI,

I have a CustomFileDescriptor Entity that is replacing the normal FileDescriptor. The CustomFileDescriptor has a couple of extra attributes.

I then have a Document Entity that has one string column and a composition link to the CustomFileDescriptor.

I have created a Screen for Browse and Edit of the Document Entity.

The edit screen I have removed the CustomFileDescriptor field from the FieldGroup and replaced this with some UI and code I got from following the Documentation on how to do a Manual upload. I’m doing the Manual upload because I want to set my custom properties on the CustomFileDescriptor Entity. I need these for my own file API implementation for FileCloud which was based off of the AWS code in CUBA.

This is the code in my edit screen

`

@Override
public void init(Map<String, Object> params) {
    uploadField.addFileUploadSucceedListener(event -> {
        FileDescriptor fd = uploadField.getFileDescriptor();
        CustomFileDescriptor cfd = (CustomFileDescriptor)fd;
        try {
            // save file to FileStorage
            cfd.setCustomField("WOOHOOOOO");
            fileUploadingAPI.putFileIntoStorage(uploadField.getFileId(), fd);
        } catch (FileStorageException e) {
            throw new RuntimeException("Error saving file to FileStorage", e);
        }
        // save file descriptor to database
        dataSupplier.commit(fd);
        showNotification("Uploaded file: " + uploadField.getFileName(), NotificationType.HUMANIZED);
    });

    uploadField.addFileUploadErrorListener(event ->
            showNotification("File upload error", NotificationType.HUMANIZED));
}

`

and this is my screen layout

`

<layout expand="windowActions"
        spacing="true">
    <fieldGroup id="fieldGroup"
                datasource="customFilesTestDs">
        <column width="250px">
            <field property="someImportantInfo"/>
        </column>
    </fieldGroup>
    <upload id="uploadField"
            clearButtonIcon="PICKERFIELD_CLEAR"
            datasource="customFilesTestDs"
            dropZone="dropZone"
            property="fileLink"
            showClearButton="true"
            showFileName="true"
            uploadButtonIcon="CLOUD_UPLOAD"/>
    <vbox id="dropZone"
          height="150px"
          spacing="true"
          stylename="dropzone-container">
        <label align="MIDDLE_CENTER"
               stylename="dropzone-description"
               value="Drop file here"/>
    </vbox>
    <frame id="windowActions"
           screen="editWindowActions"/>
</layout>

`

I’m getting this error.

image

I have tried both Composition and Association link to the CustomFileDescriptor, I have also tried commenting out this line of code dataSupplier.commit(fd); thinking the OK action would take care of it. I have linked the FileUpload to the dataset and property.

Nothing seems to make a difference.

Can anyone help?

Well I may have answered my own question finally.

When in doubt look through the Platform Source Code.

This code seems to work. It would be nice if anyone can confirm if I have done the right thing or perhaps missed anything?

@Override
public void init(Map<String, Object> params) {
    uploadField.addFileUploadSucceedListener(event -> {
        FileDescriptor fd = uploadField.getFileDescriptor();
        CustomFileDescriptor cfd = (CustomFileDescriptor)fd;
        try {
            // save file to FileStorage
            cfd.setCustomField("WOOHOOOOO");
            fileUploadingAPI.putFileIntoStorage(uploadField.getFileId(), fd);
        } catch (FileStorageException e) {
            throw new RuntimeException("Error saving file to FileStorage", e);
        }
        // save file descriptor to database
        //dataSupplier.commit(fd);
        FileDescriptor commitedDescriptor = commitFileDescriptor(fd);

        uploadField.setValue(commitedDescriptor);
        showNotification("Uploaded file: " + uploadField.getFileName(), NotificationType.HUMANIZED);
    });

    uploadField.addFileUploadErrorListener(event ->
            showNotification("File upload error", NotificationType.HUMANIZED));
}

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

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

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

Hi,
See the documentation for FileUploadField.
There is the fileStoragePutMode property which could be: MANUAL(is used by default) or IMMEDIATE.
In the MANUAL mode, do not specify datasource for the component. Fill the association attribute and commit the FileDescriptor manually. Something like this:

@Override
public void init(Map<String, Object> params) {  
    upload.addFileUploadSucceedListener(event -> {
        FileDescriptor fd = upload.getFileDescriptor();
        CustomFileDescriptor cfd = (CustomFileDescriptor) fd;
        try {
            fileUploadingAPI.putFileIntoStorage(upload.getFileId(), cfd);
        } catch (FileStorageException e) {
            throw new RuntimeException("Error saving file to FileStorage", e);
        }
       
        cfd.setAdditionalFld("woohoo");
        getItem().setFdLink(dataSupplier.commit(cfd));

    });

If you want to use IMMEDIATE mode of the upload field adjust datasource and property and do not commit the FileDescriptor manually.

        <upload id="upload"
                    fileStoragePutMode="IMMEDIATE"
                    datasource="documentDs"
                    property="fdLink"/>

The custom FiledDescriptor will be created with empty custom field, but it might be filled for instance on the Document saving.

@Override
    protected boolean preCommit() {
        CustomFileDescriptor cfd = getItem().getFdLink();
        cfd.setAdditionalFld("woohoo");
        return super.preCommit();
    }