Hi,
I’m trying to enable the multi-upload function on a generic frame (screen) that uses a generic filesDs collection datasource. This works fine but I’m not able to link the uploaded files to the parent object as the parent entity type differs per usage.
A description of the setup/implementation is given below.
File.class
// Generic package stuff left out
public class File extends StandardEntity {
private static final long serialVersionUID = -6474423184262399337L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "FILE_DESCRIPTOR_ID")
protected FileDescriptor fileDescriptor;
@Lob
@Column(name = "REMARKS")
protected String remarks;
@Column(name = "VERSION")
protected String version;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ENTITY_A_ID")
private A entityA;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ENTITY_A_ID")
private B entityB;
// Getters and setters left out
}
Note that entity types A and B could be anything having a many-to-one composition with File and thus imply a map field on File. Actually, there are some more entities that have such usages of File.
file-frame.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
class="com.company.app.web.file.FileFrame"
messagesPack="com.company.app.web.file">
<dsContext>
<!-- parent datasource is to provide a filesDs -->
</dsContext>
<layout expand="dropZone">
<vbox id="dropZone" margin="false,false,false,false" spacing="false" width="100%" expand="fileTable">
<table id="fileTable"
width="100%">
<actions>
<action id="create"/>
<action id="edit"/>
<action id="remove"/>
</actions>
<columns>
<column id="fileDescriptor"/>
<column id="version" width="200px"/>
<column id="updateTs" width="150px"/>
<column id="updatedBy" width="200px"/>
<column id="remarks"/>
</columns>
<rows datasource="filesDs"/>
<buttonsPanel>
<button action="fileTable.create"/>
<button action="fileTable.edit"/>
<button action="fileTable.remove"/>
<multiUpload id="multiUploadField" dropZone="dropZone"/>
</buttonsPanel>
</table>
</vbox>
</layout>
</window>
Note that the dropzone covers the entire table. The frame is typically included on the edit screen of the entity on one of the tabs:
A-edit.xml
<!-- other tabs left out -->
<tab id="tabFiles"
caption="msg://tab.Files"
expand="files"
margin="true,false,false,false">
<frame id="files"
screen="app$File.frame"/>
</tab>
FileFrame.class
// Generic package stuff left out
public class FileFrame extends AbstractFrame {
@Inject
private ComponentsFactory componentsFactory;
@Inject
private CollectionDatasource<File, UUID> filesDs;
@Inject
private Table<File> fileTable;
@Inject
private FileStorageService fileStorageService;
@Inject
private FileMultiUploadField multiUploadField;
@Inject
private FileUploadingAPI fileUploadingAPI;
@Inject
private DataSupplier dataSupplier;
@Inject
private Metadata metadata;
@Override
public void init(Map<String, Object> params) {
// Handle drag & drop upload for files
multiUploadField.addQueueUploadCompleteListener(() -> {
for (Map.Entry<UUID, String> entry : multiUploadField.getUploadsMap().entrySet()) {
UUID fileId = entry.getKey();
String fileName = entry.getValue();
FileDescriptor fd = fileUploadingAPI.getFileDescriptor(fileId, fileName);
// Save file to FileStorage
try {
fileUploadingAPI.putFileIntoStorage(fileId, fd);
} catch (FileStorageException e) {
throw new RuntimeException("Error saving file to FileStorage", e);
}
// Save file descriptor to database
dataSupplier.commit(fd);
// Add file to list
File f = metadata.create(File.class);
f.setFileDescriptor(fd);
// How to add reference to parent object ??
// e.g. f.setEntityA(parent) or f.setEntityB(parent)
filesDs.addItem(f);
}
showNotification(getMessage("Uploaded"), NotificationType.HUMANIZED);
multiUploadField.clearUploads();
});
multiUploadField.addFileUploadErrorListener(event ->
showNotification(getMessage("UploadError"), NotificationType.HUMANIZED));
}
}
When using the normal create button for the table, the references to the parent entity are all set without any problem. However, when dragging one or more files to the dropzone, I’m unable to set the proper parent entity field (see comments).
As each file is only linked to a single parent, a generic parent field -instead of entityA and entityB fields - would help out here. However, I’m unable to have the entity types A and B (and others) to use such a field for the composition mapping.
And yes, another solution would be to have a super class that has the files composition and have entity A and B inherit from it. That may be the best solution but implies major refactoring at this point which I’m not keen of doing - apart from problems that such an approach would have as well
Any suggestions? Thanks for any help!
-b