Being a member of the WebCenter ATEAM, we are often asked to performance tune a WebCenter custom portal application or a WebCenter Spaces deployment. Most of the time, the process is pretty much the same. For example, we often use tools like httpWatch and FireBug to monitor the application, and then perform load tests using JMeter or Selenium. In addition, there are the fine tuning of the different performance based tuning parameters that are outlined in the documentation and by blogs that have been written by my fellow ATEAMers (click on the "performance" tag in this ATEAM blog).
While performing the load test where the outcome produces a significant reduction in the systems resources (memory), one of the causes that plays a role in memory "leakage" is due to the implementation of the navigation menu UI. OOTB in both JDeveloper and WebCenter Spaces, there are sample (page) templates that include a "default" navigation menu. In WebCenter Spaces, this is through the SpacesNavigationModel taskflow region, and in a custom portal (i.e. pageTemplate_globe.jspx) the menu UI is contructed using standard ADF components. These sample menu UI's basically enable the underlying navigation model to visualize itself to some extent. However, due to certain limitations of these sample menu implementations (i.e. deeper sub-level of navigations items, look-n-feel, .etc), many customers have developed their own custom navigation menus using a combination of HTML, CSS and JQuery. While this is supported somewhat by the framework, it is important to know what are some of the best practices in ensuring that the navigation menu does not leak. In addition, in this blog I will point out a leak (BUG) that is in the sample templates.
OK, E.T. the suspence is killing me, what is this leak? Note: for those who don't know, info on E.T. can be found here
In both of the included templates, the example given for handling the navigation back to the "Home" page, will essentially provide a nice little memory leak every time the link is clicked. Let's take a look a simple example, which uses the default template in Spaces. The outlined section below is the "link", which is used to enable a user to navigation back quickly to the Group Space Home page.
When you (mouse) hover over the link, the browser displays the target URL. From looking initially at the proposed URL, this is the intended destination. Note: "home" in this case is the navigation model reference (id), that enables the display of the "pretty URL".
Next, notice the current URL, which is displayed in the browser. Remember, that PortalSiteHome = home. The other highlighted item adf.ctrl-state, is very important to the framework. This item is basically a persistent query parameter, which is used by the (ADF) framework to managing the current session and page instance. Without this parameter present, among other things, the browser back-button navigation will fail. In this example, the value for this parameter is currently 95K25i7dd_4. Next, through the navigation menu item, I will click on the Page2 link.
Inspecting the URL again, I can see that it reports that indeed the navigation is successful and the adf.ctrl-state is also in the URL.
For those that are wondering why the URL displays Page3.jspx, instead of Page2.jspx. Basically the (file) naming convention for pages created ar runtime in Spaces start at Page1, and then increment as you create additional pages. The name of the actual link (i.e. Page2) is the page "title" attribute. So the moral of the story is, unlike design time created pages, run time created pages the name of the file will 99% never match the name that appears in the link.
Next, is to click on the quick link for navigating back to the Home page.
Quick investigation yields that the navigation was indeed successful. In the browser's URL there is a home (pretty URL) reference, and there is also a reference to the adf.ctrl-state parameter. So what's the issue? Can you remember what the value was for the adf.ctrl-state? The current value is 3D95k25i7dd_149. However, the previous value was 95k25i7dd_4. Here is what happened. Remember when (mouse) hovering over the link produced the following target URL:
http://localhost:8888/webcenter/spaces/NavigationTest/home
This is great for the browser as this URL will navigate to the intended targer. However, what is missing is the adf.ctrl-state parameter. Since this parameter was not present upon navigation "within" the framework, the ADF framework produced another adf.ctrl-state (object). The previous adf.ctrl-state basically is orphaned while continuing to be alive in memory. Note: the auto-creation of the adf.ctrl state does happen initially when you invoke the Spaces application for the first time. The following is the line of code which produced the issue:
<af:goLink destination="#{boilerBean.globalLogoURIInSpace} ...
Here the boilerBean is responsible for returning the "string" url, which in this case is /spaces/NavigationTest/home. Unfortunately, again what is missing is adf.ctrl-state. Note: there are more than one instance of the goLinks in the sample templates.
So E.T. how can I correct this?
There are 2 simple fixes. For the goLink's destination, use the navigation model to return the actually "node" value, then use the goLinkPrettyUrl method to add the current adf.ctrl-state:
<af:goLink destination="#{navigationContext.defaultNavigationModel.node['home'].goLinkPrettyUrl}"} ... />
Note: the node value is the [navigation model id]
Using a goLink does solve the main issue. However, since the link basically does a redirect, some browsers like IE will produce a somewhat significant "flash". In a Spaces application, this may be an annoyance to the users. Another way to solve the leakage problem, and also remove the flash between navigations is to use a af:commandLink. For example, here is the code example for this scenario:
<af:commandLink id="pt_cl2asf" actionListener="#{navigationContext.processAction}" action="pprnav">
<f:attribute name="node" value="#{navigationContext.defaultNavigationModel.node['home']}"/>
</af:commandLink>
Here, the navigation node to where home is located is delivered by way of the attribute to the commandLink. The actual navigation is performed by the processAction, which is needing the "node" value.
E.T. OK, you solved the OOTB sample BUG, what about my custom navigation code?
I have seen many implementations of creating a navigation menu through custom code. In addition, there are some blog sites that also give detailed examples. The majority of these implementations are very similar. The code usually involves using standard HTML tags (i.e. DIVS, UL, LI, .,etc) and either CSS or JavaScript (JQuery) to produce the flyout/drop-down effect. The navigation links in these cases are standard <a href... > tags. Although, this type of approach is not fully accepted by the ADF community, it does work. The important thing to note here is that the <a> tag value must use the goLinkPrettyURL method of contructing the target URL. For example:
<a href="${contextRoot}${menu.goLinkPrettyUrl}">
The main reason why this type of approach is popular is that links that are created this way (also with using af:goLinks), the pages become crawlable by search engines. CommandLinks are currently not search friendly. However, in the case of a Spaces instance this may be acceptable. So in this use-case, af:commandLinks, which would replace the <a> (or goLink) tags. The example code given of the af:commandLink above is still valid. One last important item. If you choose to use af:commandLinks, special attention must be given to the scenario in which java script has been used to produce the flyout effect in the custom menu UI. In many cases that I have seen, the commandLink can only be invoked once, since there is a conflict between the custom java script with the ADF frameworks own scripting to control the view. The recommendation here, would be to use a pure CSS approach to acheive the dropdown effects.
One very important thing to note. Due to another BUG, the WebCenter environement must be patched to BP3 (patch p14076906). Otherwise the leak is still present using the goLinkPrettyUrl method.
Thanks E.T.! Now I can phone home and not worry about my application running out of resources due to my custom navigation!