Tag Archives: service

Customize the progress message of your service

By default, in IBM Content Navigator, the progress message when you are invoking a plug-in’s service is always Working… However, you may want something more meaningful. Give a progressMessage attribute to the plugin parameters doesn’t work because the Request class overwrite it anyway. You have to define one of the following attribute in the messages list.

  • progress_message_repositoryType_serviceName
  • progress_message_serviceName

Here is an example:

var serviceParams = {};
serviceParams[Constants.PARAM_REPOSITORY] = repository.id;
serviceParams[Constants.PARAM_SERVER_TYPE] = repository.type;
serviceParams[Constants.PARAM_FOLDER_ID] = items[0].id;
ecm.messages.progress_message_PrimeReleaseService = "Priming " + items[0].name + "...";

Request.invokePluginService("GenericActionsPlugin", "PrimeReleaseService", {
    requestCompleteCallback: lang.hitch(this, function (response) {
        this.displayResults(response);
    }),
    requestParams : serviceParams
});

Push updates from an ICN service to your client with CometD

One feature I really miss in ICN right now is a 2 ways communication channel between service and client. At this moment, you call your service and then it returns something when the execute method is done. That creates an issue, because users have no patience… More than one minute on the same loading spinner and you can be sure most of them will refresh the page thinking ICN crashed. That won’t stop your service, but if this one is not done by the time the user comes back, he will run the service again…

So here is a way to push information from the server to the client.

Principle

I used CometD to implement that because ICN is already shipped with some CometD client libraries (actually not all of them, discussed below)). The reason for that is ICN uses CometD for the Sync and Share feature. That way we don’t need to add any library to the client. About the server, the PluginService class is not a servlet or a web service, it is actually called by a Struts action so forget about asynchronous servlet, websocket and so on since we are not master of our servlet. On the other hand, we can’t change the navigator application either (well we could and redeploy but we want to be update proof), so we can’t add support for any “push” framework and ICN doesn’t have that natively. That’s why I’ve decided to use another light web application to achieve that. Here is the schema to help you understand how it works.

ICN_CometD_push
Continue reading

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
    }
}