In the Navigation Model of a WebCenter Portal application (11g), there is an option to define a navigation resource by "external link". In a normal case, you should NOT define any internal JSPX page using this option, but only if there is a need to navigate to a third party site - by what the name means, an external link. The internal JSPX page should be added to the Navigation Model by the "page" type.
The impact of defining internal JSPX page as an external link is, the redundant memory footprint due to the ADF control state token recreations every time this external link is clicked. ADF control token is an identifier used by the Controller to track user's state so that all in process task flows for the same user can be retrieved. Normally, this ADF control state should be not recreated for the same user. With the external link type, the navigation behaves like entering the application in a blank new context so every navigation with external link type will auto generate a new ADF control token. Within the same user session, the recreations of the ADF control token mean redundant memory use. The less negative thing is the ADF control state will be garbage collected after user session is invalidated. So this memory issue is only scoped within user sessions and will not accumulate over time - well this is assuming your application doesn't have a crazy long timeout setting nor your users would stay active for long time (long or short, is relative. It's impossible to name a threshold without doing some load testing and analyses on the application, as at the end of the day every application is different). In this regard, it's not a memory leak in time. However, when there is a high concurrency of users navigating the application, this issue could be a concern.
The main focus of this post is how to get around this memory issue with the external link type for internal JSPX page. You may ask what's the use case for this type of implementation - well, there is always some special unique use case down the road you might come across one day. Let's say one day you cannot use goLink and commandLink on the navigation model, but rather have to a programmatic redirect to some other page in your application with this ADF control state recreation issue.
The foremost thing is to understand the navigation model - why using navigation model API would keep the ADF control token intact throughout the application. Let's start with a new WebCenter Portal framework application and understand what navigation model API would do.
In the home.jspx page, add a navigation model goLink prettyURL syntax as the value of an output text like below.
It's basically printing out the navigation model prettyURL of the home page. When the page renders, you would see -
The navigation model prettyURL returns "/faces/home?_adf.ctrl-state=xxxxx". So the secret of navigation model capable of keeping the same ADF control token around is to attach it as a query string in the URL on every navigation.
After this is figured out, the rest should be easy. To use external link to reference an internal JSPX page, it's necessary to make the URL path relative so that your application can work properly on different environment. When defining an external link in navigation model, the URL field doesn't have the expression language facility (a nice popup that you can build objects using EL trees) but we still can use EL to construct the URL.
Using the home.jspx as an example, here is the syntax we should use:
#{request.scheme}://#{request.serverName}:#{request.serverPort}#{request.contextPath}/faces/home
Here is the External Link definition in the navigation model -
Note we need to add the "_adf.ctrl-state" URL parameter below. Alternatively, you can also define the URL parameters as part of the URL like
#{request.scheme}://#{request.serverName}:#{request.serverPort}#{request.contextPath}/faces/home?_adf.ctrl-state=#{facesContext.externalContext.requestParameterMap['_adf.ctrl-state']}
The source of the external link definition looks like below:
Note the actual prettyURL is not mandatory. "/faces/home" can also be replaced by "/faces/oracle/webcenter/portalapp/pages/home.jspx".
Now we can run the application. When clicking between the Home and "Home External Link", the ADF control state never changes.
The impact of defining internal JSPX page as an external link is, the redundant memory footprint due to the ADF control state token recreations every time this external link is clicked. ADF control token is an identifier used by the Controller to track user's state so that all in process task flows for the same user can be retrieved. Normally, this ADF control state should be not recreated for the same user. With the external link type, the navigation behaves like entering the application in a blank new context so every navigation with external link type will auto generate a new ADF control token. Within the same user session, the recreations of the ADF control token mean redundant memory use. The less negative thing is the ADF control state will be garbage collected after user session is invalidated. So this memory issue is only scoped within user sessions and will not accumulate over time - well this is assuming your application doesn't have a crazy long timeout setting nor your users would stay active for long time (long or short, is relative. It's impossible to name a threshold without doing some load testing and analyses on the application, as at the end of the day every application is different). In this regard, it's not a memory leak in time. However, when there is a high concurrency of users navigating the application, this issue could be a concern.
The main focus of this post is how to get around this memory issue with the external link type for internal JSPX page. You may ask what's the use case for this type of implementation - well, there is always some special unique use case down the road you might come across one day. Let's say one day you cannot use goLink and commandLink on the navigation model, but rather have to a programmatic redirect to some other page in your application with this ADF control state recreation issue.
The foremost thing is to understand the navigation model - why using navigation model API would keep the ADF control token intact throughout the application. Let's start with a new WebCenter Portal framework application and understand what navigation model API would do.
In the home.jspx page, add a navigation model goLink prettyURL syntax as the value of an output text like below.
It's basically printing out the navigation model prettyURL of the home page. When the page renders, you would see -
The navigation model prettyURL returns "/faces/home?_adf.ctrl-state=xxxxx". So the secret of navigation model capable of keeping the same ADF control token around is to attach it as a query string in the URL on every navigation.
After this is figured out, the rest should be easy. To use external link to reference an internal JSPX page, it's necessary to make the URL path relative so that your application can work properly on different environment. When defining an external link in navigation model, the URL field doesn't have the expression language facility (a nice popup that you can build objects using EL trees) but we still can use EL to construct the URL.
Using the home.jspx as an example, here is the syntax we should use:
#{request.scheme}://#{request.serverName}:#{request.serverPort}#{request.contextPath}/faces/home
Here is the External Link definition in the navigation model -
Note we need to add the "_adf.ctrl-state" URL parameter below. Alternatively, you can also define the URL parameters as part of the URL like
#{request.scheme}://#{request.serverName}:#{request.serverPort}#{request.contextPath}/faces/home?_adf.ctrl-state=#{facesContext.externalContext.requestParameterMap['_adf.ctrl-state']}
The source of the external link definition looks like below:
Note the actual prettyURL is not mandatory. "/faces/home" can also be replaced by "/faces/oracle/webcenter/portalapp/pages/home.jspx".
Now we can run the application. When clicking between the Home and "Home External Link", the ADF control state never changes.
Comments