Tag Archives: IBM Content Navigator

Callback not working in the FileTracker functions

Status: fixed in 2.0.3.3

You might have noticed that when using the ecm/model/FileTracker class in IBM Content Navigator, the callback is never called.

For instance if you are using the following code:

FileTracker.downloadAndTrackFiles(documentInfoObj, function (response) {
    console.log("Never invoked");
});

the callback is never called. This is because there is a defect in the FileTracker processMessage function, it does not look correctly for the callback because of a = missing in the condition:

var callbackResponse;
if (response.responses && response.responses.length > 0) {
	var callbackResponse;
	for ( var i = 0; i < response.responses.length; i++) {
		if (response.responses[i].errorCode = this.SERVER_RESPONSE_CALLBACK) {
			callbackResponse = response.responses[i];
			break;
		}
	}
} else if (response.errorCode == this.SERVER_RESPONSE_CALLBACK) {
	callbackResponse = response;
}

This is fixed in Fix Pack 3 though (2.0.3.3), so you can either upgrade or use a plugin to do an aspect around and replace the function by the correct one, which is:

processMessage: function(json, showSuccessMessage) {
	var methodName = "processMessage";
	this.logEntry(methodName);

	var response = dojojson.fromJson(json);
	if (response.hasError) {
		var errorPrefix = "", inserts = [];
		var showError = true;
		if (response.errorCode == 7) {//ERROR_OPEN_FAILED
			errorPrefix = "runtime_file_tracking_file_not_found_error";
		} else if (response.errorCode == 3) {
			errorPrefix = "runtime_file_tracking_ioexception_error";
		} else if (response.errorCode == this.ERROR_NOT_TRACKED) {
			showError = false;
		} else if (response.errorCode == this.ERROR_OPEN_FAILED) {
			showError = true;
			errorPrefix = "runtime_file_tracking_open_error";

		} else if (response.errorCode == this.ERROR_SAVE_FILE_FAILED) {
			showError = true;
			errorPrefix = "runtime_file_tracking_save_file_error";

		} else if (response.errorCode == this.ERROR_SAVE_FILE_FAILED_AND_OPEN_FIALED) {
			showError = true;
			errorPrefix = "runtime_file_tracking_save_file_after_checkout_error";

		} else if (response.errorCode == this.ERROR_ENVIRONMENT_VARIABLE_PATH_NOT_FOUND) {
			showError = true;
			errorPrefix = "runtime_file_tracking_ev_file_path_not_found_error";

		} else if (response.errorCode == this.ERROR_OPEN_CONNECTION) {
			showError = true;
			errorPrefix = "runtime_file_tracking_ioexception_error";

		} else if (response.errorCode == this.ERROR_FOLDER_NOT_FOUND) {
			showError = true;
			errorPrefix = "runtime_file_tracking_exact_file_path_not_found_error";

		} else if (response.errorCode == this.ERROR_EXACT_PATH_NOT_FOUND) {
			showError = true;
			errorPrefix = "runtime_file_tracking_exact_file_path_not_found_error";

		} else if (response.errorCode == this.ERROR_CANNOT_CREATE_TRACKING) {
			showError = false;
			errorPrefix = "runtime_file_tracking_exact_file_path_not_found_error";

		} else if (response.errorCode == this.ERROR_DELETE_FILE_FAILED) {
			showError = true;
			errorPrefix = "runtime_file_tracking_cannot_delete_file_error";

		} else {
			showError = true;
			errorPrefix = "runtime_file_tracking_generic_error";
		}

		if (showError) {
			if (response.responses && response.responses[0].value) {
				inserts.push(response.responses[0].value);
			} else if (response.value) {
				inserts.push(response.value);
			}
			Desktop.addMessage(Message.createErrorMessage(errorPrefix, inserts, false));
		}

	} else {
		var successMessage = "";
		if (response.responses) {

			if (response.responses.length == 1 && ((response.responses[0].errorCode == this.ERROR_DELETE_FILE_FAILED || response.responses[0].errorCode == this.FOUND_TRACKED_RECORD_BY_FILE_PATH) || (response.responses[0].errorCode == this.FOUND_TRACKED_RECORD_BY_SCANNING) || (response.responses[0].errorCode == this.SUCCESSFULLY_TRACKED_FILE_USING_ADS))) {

				successMessage = string.substitute(ecm.messages.file_tracking_successfully_downloaded_document, [
					response.responses[0].originalDocumentName,
					response.responses[0].value
				]);
			} else if (response.responses.length > 1 && ((response.responses[0].errorCode == this.FOUND_TRACKED_RECORD_BY_FILE_PATH) || (response.responses[0].errorCode == this.FOUND_TRACKED_RECORD_BY_SCANNING) || (response.responses[0].errorCode == this.SUCCESSFULLY_TRACKED_FILE_USING_UD) || (response.responses[0].errorCode == this.SUCCESSFULLY_TRACKED_FILE_USING_ADS))) {

				var count = response.responses.length;
				var documentsDownloaded = [];
				for ( var i = 0; i < count; i++) {
					documentsDownloaded.push(response.responses[i].originalDocumentName);
				}
				successMessage = string.substitute(ecm.messages.file_tracking_successfully_downloaded_document, [
					documentsDownloaded.join(",")
				]);

			}
		}

		if (successMessage && successMessage.length > 0) {
			Desktop.addMessage(new Message({
				number: 0,
				level: 0,
				text: successMessage
			}));
		}

		var callbackResponse;
		if (response.responses && response.responses.length > 0) {
			var callbackResponse;
			for ( var i = 0; i < response.responses.length; i++) {
				if (response.responses[i].errorCode == this.SERVER_RESPONSE_CALLBACK) {
					callbackResponse = response.responses[i];
					break;
				}
			}
		} else if (response.errorCode == this.SERVER_RESPONSE_CALLBACK) {
			callbackResponse = response;
		}
		if (callbackResponse && callbackResponse.value) {
			var lookupId = callbackResponse.value.callbackId;
			if (lookupId && this.callbackMap[lookupId]) {
				var callbackFunc = this.callbackMap[lookupId];
				if (callbackFunc) {
					callbackFunc(callbackResponse.value.response);
				}
			}
		}

	}

	this.logExit(methodName);
	return response;
	//MessageFactory.createErrorMessage = function(messagePrefix, inserts, backgroundRequest);

},

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

How to install IBM CMIS

In its version 1.0, IBM CMIS was shipped as a separate application. But now, where can you get it and how can you install IBM CMIS? If you are looking for it in the Software Catalog from IBM, you won’t find it. And that’s normal because it is now part of IBM Content Navigator.

We’ll see how to install CMIS. You can follow this procedure when you install ICN, upgrade ICN, or even if you have already installed it, just re-open the configuration tool. The procedure start when you are starting the IBM Content Navigator Configuration and Deployment Tool. If you are installing/upgrading ICN, it will start by itself. If you have ICN already installed, you can launch this tool by running:
Continue reading

Developing with IBM Content Navigator

I really think IBM Content Navigator lacks a good documentation, especially the JavaScript model. This is definitely not as good as for other IBM’s products, like FileNet P8 for instance. That’s why I thought I would write small examples in the same way that IBM does for developers in the P8 documentation (Working with …).

Of course before looking for information is this post, I can’t recommend you enough the Red Book for developing with IBM Content Navigator, the Javadoc and the JSDoc. This is the first thing every developer should read. However as good as it is, what’s next might come handy for your developments.

Update: Actually the JavaScript model really needs more documentation/examples so I will split the page in several of them to keep this understandable.

Continue reading