I am missing a file "size" attribute in Jmix

Jmix version: 1.1.1
Jmix Studio plugin version: 1.1.4-213
IntelliJ IDEA 2021.3 CE - Build #IC-213.5744.223, built on November 27, 2021Operating System: macOS 12.0.1 (21A559)
File System: Case-Sensitive Journaled HFS+ (APFS)
Datebase: PostgreSQL 13

Hello Everyone

For your information, I performed my first CUBA-to-Jmix migration last weekend and am attempting to do all of the necessary manually refactoring in the meantime. I have 19 months of CUBA experience and about 19 hours of Jmix experience.

I am missing a file “size” attribute in Jmix, respectively in the FileRef class and need help. Here is my situation…

My application uses a membership model with different membership types: TRIAL, BASIC, ENANCED, ULTIMATE.

Each user has one instance of a Membership entity that stores their membership type and its restrictions. The restrictions for each type are defined in configuration attributes and copied to the Membership instance when the user choses the membership type that he wants or when he upgrades it at a later time.

In the Membership instance the application keeps track of the counts and limits of various profile instances that the user can create; let’s call them Profile-One, Profile-Two.

Therefore, in the Membership instance there are for example the following attributes:

profileOneLimit
profileOneCount
profileOneRemaining

profileTwoLimit
profileTwoCount
profileTwoRemaining

and since Profile-One has an image (.jpg) attribute and Profile-Two contains an audio file (.mp3) attribute, the Membership instance has the following further attributes:

storageLimit
storageUsed
storageRemaining

Easch Membership type provides for a different/larger amount of available storage.

In CUBA I use a TransactionalEventListener for each entity to keep track of the number of Profile-One and Profile-Two instances that are created and deleted and also how much storage is used by them or set free if they are deleted. Within the TransactionalEventListener the Membership attributes are updated and saved and in the UI screen controllers a check is done against the Membership attributes to either allow or prohibit the creation of a new instance of Profile-One or Profile-Two by the user.

In the screen controllers I also keep track of the size of the image and audio files that are uploaded, cleared or replaced before saving the entity. I use the Membership information in the screen controllers to set the maximum size of the file that can be uploaded and track this locally if someone clears a file, loads another one, clears it and so on and so on.

In CUBA counting the instances is not a problem and calculating the used storage is done using the FileDescriptor entity as an Association in each of Profile-One or Profile-Two instances and I can use fileDescriptor.getSize() to return the file’s size and use this information to calculate my used and remaining storage.

However, in Jmix the FileRef class, which to my understanding is the FileDescriptor replacement, does not have a size attribute and there is no reference to this in the documentation.

In “jmix-localfs/localfs/src/main/java/io/jmix/localfs/LocalFileStorage.java” I see that the function “public long saveStream(FileRef fileRef, InputStream inputStream)” returns “size” but this “size” information is not used in function “public FileRef saveStream(String fileName, InputStream inputStream)” This “size” information could be added to the fileRef instance in the function if the attribute actually existed.

Is there some specific reason why there is no “size” attribute in the FileRef class? Do you plan on adding it? When? If not, what would you recommend that I do to elegantly solve my problem?

Thanks in advance for your feedback.

Best regards
Chris

Hi Chris,

The FileRef class is not a separate entity as in CUBA but just a wrapper around the URI that is stored in the field which refers to the file. We’ve decided that the file size is irrelevant to the task of pointing to a file in the storage, and should not bloat the URI.

If you need to store the file size, just create a separate attribute in your entity that has a reference to the file. You can fill it when uploading the file, for example by getting the size of the file uploaded to the temporary storage by the FileStorageUploadField. Use fileStoragePutMode=“MANUAL” to get access to this intermediate store.

Regards,
Konstantin

Hi Konstantin

Thank you for the feedback. Understood. I’ll use the approach that you have suggested.

Best regards
Chris

Hi Konstantin

Here just an update to this situation; the problem is resolved.

Using…

@Subscribe("imageFileStorageUpload")
public void onImageFileStorageUploadFileUploadSucceed(SingleFileUploadField.FileUploadSucceedEvent event) {

long fileSize = event.getContentLength();
}

does not work; event.getContentLength() returns -1.

But the following does work (as one would expect):

@Subscribe("imageFileStorageUpload")
public void onImageFileStorageUploadFileUploadSucceed(SingleFileUploadField.FileUploadSucceedEvent event) {

File file = temporaryStorage.getFile(imageFileStorageUpload.getFileId());
inProfDc.getItem().setAudioFileSize(file.length()); 

/* other stuff, etc. */
}

This is paired with the following entity EventListener to retrieve the size information after a modification or deletion, so that I can track the storage used.

@EventListener
public void onInProfChangedBeforeCommit(EntityChangedEvent<InProf> event) {
    FileRef oldAudioFileRef = null;
    long oldAudioFileSize = 0;

   if (event.getType() != EntityChangedEvent.Type.CREATED) {
       AttributeChanges attributeChanges = event.getChanges();
       Set<String> attributes = attributeChanges.getAttributes();
       for (String attribute : attributes) {
           if (attribute.equals("audioFile")) {
               oldAudioFileRef = attributeChanges.getOldValue("audioFile");
           }
           if (attribute.equals("audioFileSize")) {
               oldAudioFileSize = attributeChanges.getOldValue("audioFileSize");
           }
       }
   }

  /* track values here, etc. */
}

Maybe this information might help others. Could be.

Best regards
Chris

2 Likes