Transfer a file to your service

Some business logic can require to send a file from the client workstation to the server. Usually to improve performance by doing a server work instead of a client one, sometimes because it’s more convenient for the user or for the developer. I had to transfer a zip to do a zip-add after I noticed that deflating on the client and adding file one by one was to slow for our needs, although it worked fine.

Client side

On the client, we won’t use the function Request.invokePluginService as we usually do when invoking services. Instead, we are going to use Request.postFormToPluginService(pluginName, pluginServiceName, form, pluginParams), which allow posting data to our service. However the syntax differs, here we won’t pass our params in the requestParams attribute of the pluginParams argument, this time they all go in the form, which is a W3C FormData object, along with our W3C File. Here is the example.

var fd = new FormData();
fd.append('file', zipArchive);
fd.append(Constants.PARAM_FOLDER_ID, this.parentFolder.id);
fd.append(Constants.PARAM_REPOSITORY, this.parentFolder.repository.id);
fd.append(Constants.PARAM_SERVER_TYPE, this.parentFolder.repository.type);

var pluginParams = {
    requestCompleteCallback: lang.hitch(this, function (response) {
        this.parentFolder.refresh();
    })
};

Request.postFormToPluginService("GenericActionsPlugin", "AddZipService", fd, pluginParams);

This is all it takes on the client.

Server side

Now let’s see how to fetch this file and use it in our service.

ICN is still using Struts. That means we will use the FormFile interface to get our file (actually the stream). The FormFile is added as attribute of the request by the PluginAction class in charge to call your Plugin class so you can retrieve it with:

FileUploadActionForm uploadForm = (FileUploadActionForm) request.getAttribute(FileUploadActionForm.class.getName());
if (upload != null) {
    FormFile ff = (FormFile) uploadForm.getMultipartRequestHandler().getFileElements().get("file");
}

In order for this to work, you will have to add to your classpath the ICN classes. You can find them by deflating the ear file or going to your application server in the installed app, usually there will be the exploded ear there too. That could be more convenient to zip all WEB-INF/classes in a jar and add that to your classpath.

However, the other parameters are still retrieved with request.getParameter().

Then you can use the stream. If you need a file, even if in the ICN implementation FormFile, the file is actually stored in a WAS temp directory, this is not possible to get it so you’ll have to copy the stream in a temp file and use this file instead.

Here is the server side example corresponding to the client.

String repositoryId = (String) request.getParameter(Constants.PARAM_REPOSITORY);
String parentFolderIcnId = (String) request.getParameter(Constants.PARAM_FOLDER_ID);
String parentFolderId = P8Helper.getP8ID(parentFolderIcnId);

ObjectStore os = callbacks.getP8ObjectStore(repositoryId);

FileUploadActionForm uploadForm = (FileUploadActionForm) request.getAttribute(FileUploadActionForm.class.getName());
if (uploadForm != null) {
    FormFile ff = (FormFile) uploadForm.getMultipartRequestHandler().getFileElements().get("file");

    if (ff != null) {
        InputStream is = ff.getInputStream();
        // Do something with the stream
    }
}

Leave a Reply