Sunday, June 4, 2017

ICN Known Issues - 4


Custom MIME Type not working

You want to use a new MIME Type in IBM Content Navigator, for example application/dita+xml. You did add a File Type filter under the settings panel from the administrator (DITA files using the dita MIME Type you just created).
ICN_customMIMEType
Then you used this file type filter to filter an entry template associated on a folder.
ICN_customMIMEType2
However the entry template is never displayed when adding a document. Instead you only see entry templates for Any type of file, or no entry template at all if you have none without filter.
ICN_customMIMEType3
Here we were expecting our entry template associated to the DITA file type filter
You’ve tried adding a MIME Type mapping to inform ICN in WebSphere virtual host, ICN’s web.xml and modify CE’s mimetypes.properties but nothing worked (well if you didn’t try these I can tell you it doesn’t).

Cause

ICN uses its own mapping to map file extension to MIME Type. They currently cannot me modified, therefore ICN when retrieving the MIME Type in the add wizard to not find any, therefore do not find any file type filters, and so cannot select the entry template you filtered with a file type.

How to fix it

Well there is not really a work around for this issue. The only way I found for now has been to write a plug-in injecting new MIME Types in the JavaScript object keeping all mapping on the client. This object is actually loaded with the desktop (meaning when loading the page). The plug-in does an aspect.after on the login method, so the code is called as soon as the user log in (we need him logged in to retrieve the plug-in configuration). You set all your new MIME Types in the plug-in configuration and then all ICN JavaScript functions will use this news values since they are injected in the desktop object.
I won’t give you the whole plug-in, because it is actually quite easy to write (this is only one service to retrieve the plug-in configuration, as given in the Red Book, and some aspect code in the main javascript file of the plug-in and that’s it). To help you, here is the JavaScript to inject the values into the desktop object:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Function to call when user log in
var _onLogin = function(repository) {
    _loadConfiguration();
};
// Function to inject our new MIME Types
var _injectMIMETypes = function(mimetypesArray) {
    // This is the object keeping all values hard coded on the server
    var mimeTypeDefs = ecm.model.desktop._mimeTypeDefs;
    for (var i in mimetypesArray) {
        var mt = mimetypesArray[i];
        var association = {
            mimeTypes:[mt.mimetype],
            extensions:mt.extensions,
            fileType:"file.type.unknown"
        };
        mimeTypeDefs.push(association);
    }
    // remove hook so we don't inject again if log out/log in
    if (signalMIMETypeFixPlugin) {
        signalMIMETypeFixPlugin.remove();
    }
}
// Retrieve plugin configuration from the server and store it
var _loadConfiguration = function() {
    Request.invokePluginService("MIMETypeFixPlugin", "GetConfigurationService", {
        requestCompleteCallback : function(response) {
            // Here we can inject the MIME Types in the desktop config
            _injectMIMETypes(response);
        }
    });
};
if (ecm.model.desktop.connected) {
    // already connected (ctrl F5 for instance), no need to hook just inject
    _loadConfiguration();
} else {
    // dojo/on won't work because desktop does not fire events,
    // using aspect to call our method at the end of the dektop.onLogin
    signalMIMETypeFixPlugin = aspect.after(ecm.model.desktop, "onLogin", _onLogin);
}
This will allow ICN to recognized your MIME Type, therefor the File Type and it will offer you the associated Entry Template. However it does not tell the Content Engine the MIME Type and you will still have a application/octets-stream in the repository. To get ride of that you can place the mimetypes.properties files of the CE (search it on your server) in the home folder of the user running the CE. Of course add it the new MIME Types you want at the end of the file and restart the platform.

Investigation

Warning: I removed some parts of the code because it doesn’t help the comprehension, and also because this code is under the IBM copyright. This is for understanding purpose only!
Here is the investigation I had, you can read it you are interested, don’t if you are not because it will be really boring!
I first saw this issue when adding a document, so I debugged and looked at how the file type filters were retrieved. Here is the method, in the ecm.js.jqz file. It actually is in the ecm.widget.dialog.AddContentItemDialog file before compression:
74527
74528
74529
74530
74531
74532
_getFileTypesForInputFiles:function () {
    ...
    mimeTypes = this._getMimeTypesForExtension(temp[temp.length - 1]);
    ...
    return fileTypes;
}
You can see it calls another method to find the MIME Type based on he file extension. Let’s take a look to this method:
74554
74555
74556
74557
74558
74559
74560
74561
74562
74563
74564
_getMimeTypesForExtension:function (extension) {
    var mimeTypeDefs = ecm.model.desktop._mimeTypeDefs;
    for (var i = 0; i < mimeTypeDefs.length; i++) {
        for (var j = 0; j < mimeTypeDefs[i].extensions.length; j++) {
            if (extension == mimeTypeDefs[i].extensions[j]) {
                return mimeTypeDefs[i].mimeTypes;
            }
        }
    }
    return result;
}
We can see clearly here that it uses the object ecm.model.desktop._mimeTypeDefs in the global scope. So the next trail to follow was to find where this object in instantiated. And it lead me to the callback of this method:
94449
94450
94451
94452
94453
94454
94455
loadDesktop:function (desktopId, callback, synchronous, useLastCache) {
    ...
    var request = Request.invokeService("getDesktop",..., function (response) {
        self._desktopLoaded(response, callback);
     }, false, synchronous);
     ....
));
Here we understand that it actually comes from a service, so the problem is on the server side, in the Java EE web application.
Last step of this investigation, on the server side, lead me do see that the response for the MIME Types mapping is filled by a hard-coded array:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(this.jsonObject = jsonObject).put("mimeTypeDefs", MimeTypeUtil.toJSONArray());
// Here is the toJSONArray method
public static JSONArray toJSONArray() {
    final JSONArray resultArray = new JSONArray();
    for (final MimeTypeDef mimeTypeDef : MimeTypeUtil.mimeTypeDefs) {
        final JSONObject mimeTypeObject = new JSONObject();
        ...
        resultArray.add(mimeTypeObject);
    }
    return resultArray;
}
// And here is the static array use, the problem is actually here, all MIME Types mapping are hard-coded, and these are the values we found on the client in the JavaScript object
MimeTypeUtil.mimeTypeDefs = new MimeTypeDef[] {
    new MimeTypeDef(
        new String[] {"application/afp", "application/vnd.ibm.afplinedata" },
        new String[] { "afp" },"file.type.afp.document", "icon.mime.afp"),
        ...)
};

ICN Known Issues - 4

Custom MIME Type not working Symptom You want to use a new MIME Type in IBM Content Navigator, for example application/dita+xml. You...