Background
This week I was presented with an integration problem with ODEE 12.4 – specifically a third-party workflow program and Documaker Interactive (DI). The workflow program provides users with the business process workflow, and DI simply provides access to edit transactions via its direct-access URL. In case you’re not aware, with DI you can skip the Home screen and go directly into edit mode using a URL with some query string parameters. This is all documented in the product documentation on page 519. The problem presented was that the workflow program requires IE to run in compatibility mode, whereas DI and the underlying ADF components cannot work with compatibility mode turned on. As it happens, it may work, but you may have unintended results.
Investigation
One of the problems we noted was that using the direct access mode with DI would sometimes cause the browser process to crash and reload – the user almost never noticed this happening, but in this particular customer’s environment, the integration between the workflow application and DI would be lost. This manifested as an inability to use the DI toolbar to save documents, or the document would be loaded, but the home tab would have focus instead of the document tab, or sometimes the document would not load.
What I observed in this particular environment is that IE always had 3 processes: a parent 64-bit process, and two child 32-bit processes: one for the workflow application and one for DI. I noted that the process IDs would change for one of the 32-bit processes whenever this crash-and-reload situation occurred. After some additional investigation with the customer, we found that when closing an IE session (in this case, a DI window for a particular document transaction), the parent 64-bit process held on to the 32-bit child process for approximately 60 seconds after which it was terminated. The problem manifested when attempting to open a new document in another DI integration window before the previous 32-bit child process was terminated: IE would crash-and-reload in what I’m calling an "orphaned process", and we would observe the anomalous behavior in one of the flavors mentioned above. So,
Solution
Since we couldn’t find any way to force IE to terminate the 32-bit process on demand, our only option was not to terminate the process at all. In doing this, we would have to make sure that the integration would always use the same IE window for DI on a given user’s workstation. This meant that we needed to instruct users not to close any DI windows, but to instead leave it open and simply close the document tab when they completed it. They would be able to go back to their workflow application and select a new document. The significant change was to the workflow application itself: rather than a simple URL link to DI, we would have to do something a bit more creative in order to keep the IE processes from spawning new windows. Here’s how we did it.
The previous integration link in the workflow application was a simple anchor tag (the highlighted elements are unique for each transaction and would be dynamically replaced by the workflow application when generating the HTML):
<a href="https://servername:port/DocumakerCorrespondence/faces load?taskflow=edit&uniqueId=UID&docId=DOCID" target="_new">View Document</a>
The new integration link is almost the same, but includes a call to some client-side Javascript that does the magic.
<a href="#" onclick="openDocumaker(‘https://servername:port/DocumakerCorrespondence/faces load?taskflow=edit&uniqueId=UID&docId=DOCID‘);">View Document</a>
And finally, the Javascript magic – this simply forces each document to open in the same window, and then an <IFRAME> element is created with the source being the DI integration link. The workflow integration webpage maintains the handle to the IE window using the Javascript variable documakerWindow. If the variable is not initialized, then a new window is created. Finally, there’s a bit of Javascript to allow dynamic resizing of the <IFRAME> element whenever the window is resized.
<script>var documakerWindow, documakerFrame;
function openDocumaker(sUrl){
if (documakerWindow == null){
documakerWindow = window.open("","Documaker","resizable=yes,toolbar=no,status=yes");
documakerWindow.document.open();
documakerWindow.document.write("<script>function autoResize(){var f=document.getElementById(‘diframe’);var nw,nh;" +
"if(f){nh=f.contentWindow.document.body.scrollHeight;nw=f.contentWindow.document.body.scrollWidth;}f.height=(nh)+’px’;f.width=(nw)+’px’;}" +
"<\/script><iframe src=’"+sUrl+"’ width=100% height=100% id=diframe marginheight=0 frameborder=0 onLoad=’autoResize();" +
"document.getElementById(‘diframe’).parent.addEventListener(‘resize’,autoResize);’></iframe>");
documakerWindow.document.close();
documakerFrame = documakerWindow.document.getElementById(‘diframe’);
} else {
documakerFrame.src = sUrl;
}
documakerWindow.focus();
}</script>
Apologies in advance for the terrible layout. We’re moving to a new blogging platform soon, and hopefully it will be better for code representation. Anyway, this was a bit of a problem that took some concentrated debugging effort to figure out – that was most of the battle! In the end, this seems to have done the trick. Now it’s time for production roll-out!
Update
I did some additional experimentation to create a custom JSP tag that illustrates how you can make integration to Documaker Interactive even easier for developers. The model is still the same as discussed above – an anchor <a> tag and the corresponding JavaScript to facilitate opening a window with an IFRAME. The only difference now is that you can encapsulate the complexities of the Javascript and anchor (and even creating the URL to Documaker Interactive) inside a custom JSP tag that can be reused in your applications. If you want to try this yourself, you can download the source for this example here (note: it’s unsupported and offered without warranty of any kind).
Tag Usage Example
Implementation is four steps – first download the example code and extract it.
- Copy public_html/WEB-INF/dmkrint.tld to your web application (ideally in WEB-INF folder)
- Compile the Java files in src/oracle/documaker/integration. Copy the compiled classes to your WEB-INF/classes folder
- Add the TLD to your JSP page (example: <%@ taglib prefix="d" uri="WEB-INF/dmkrint.tld"%>)
- Add the taglib to your web.xml (see example in public_html/WEB-INF/web.xml)
- Implement the tag in your JSP, as shown below.
<d:interactive
mode="compose"
uid="b2304ad8-fb3c-428f-8077-f35e8dbcfbcb"
docid="TEST"
protocol="http"
host="192.168.1.72:7001"
app="DocumakerCorrespondence">View Document</d:interactive>
Attributes for the tag are:
- mode = [ inbox | edit | compose ] – the desired mode for Interactive to launch into. Edit goes into forms selection, Inbox goes to the Inbox, Compose goes into document composition with WIPedit.
- uid = The UniqueId of the document to edit. If you are implementing with DWS (web services) you will get this information in the response when submitting a request to generate a document.
- docid = The DocId (or key Id) of the document to edit. If you are implementing with DWS (web services) you will get this information in the response when submitting a request to generate a document.
- protocol = [ http | https ] – protocol for building URL to Documaker Interactive.
- host = The hostname and port if necessary for building URL to Documaker Interactive.
- app = The context root of the Interactive application (e.g. DocumakerCorrespondence)
- Tag body = the text to display in the anchor tag.
HTML Emitted by Tag
<a href="#" onclick="openDocumaker('http://192.168.1.72:7001/DocumakerCorrespondence/faces/load?taskflow=compose&uniqueId=b2304ad8-fb3c-428f-8077-f35e8dbcfbcb&docId=TEST'); ">View Document</a>
<script>var dW, dF;
function openDocumaker(s){
if(dW==null){
dW= window.open("", "Documaker", "resizable=yes,toolbar=no,status=yes");
dW.document.open();
dW.document.write("<script>function autoResize(){var f=document.getElementById('diframe');var nw,nh;if(f){nh=f.contentWindow.document.body.scrollHeight;nw=f.contentWindow.document.body.scrollWidth;}f.height=(nh)+'px';f.width=(nw)+'px'; }<\/script>" +
"iframe src='"+s+"' width=100% height=100% id=diframe marginheight=0 frameborder=0 onLoad='autoResize();document.getElementById('diframe').parent.addEventListener('resize',autoResize);'><\/iframe>");
dW.document.close();
dF= dW.document.getElementById('diframe');
}
else {
dF.src = sUrl;
}
dW.focus();
}
</script>