Gerald Nunn's Blog
« WebLogic Portal Analytics API | Main | Good introductory WLP and WSRP article »Best Practices for Links in WebLogic Portal
Friday, April 04, 2008
Introduction
A question that comes up from time to time is what is the best practice with respect to the format of URLs within links in a portlets. By links, we mean both links used in anchor tags and used when accessing resources, for example the src attribute in the img tag.
First a little background, there are three main styles used to construct a link in a web application. These are:
- Absolute. This is a link that contains the full URL including the scheme (http or https), domain and port. For example, http://www.yahoo.com/finance would be an example of an absolute link.
- Relative. This is a link that is relative to the current document, for example ../images/someimage.jpg.
- Root Relative. This is a variant of the relative style link, in this case the link is relative to the root of the web application. Links of this nature always start with a slash followed by the application's context root. An example of a root relative link would be /application/framework/skins/myskin/images/someimage.jpg where application is the context root of the web application.
Portal Links
When constructing links in WebLogic Portal the best practice in my opinion is to use root relative links. The problem with absolute links is that it can be difficult for the application to accurately determine what the front end scheme, domain and port is given the amount of infrastructure that could potentially be sitting between the WebLogic Portal server and the user's browser. This gets even more complicated to manage if users will access the site from different front ends. A root relative link eliminates this issue by leaving it to the browser to determine these parameters based on the URL of the current document.
Relative links have a different issue in that they are incompatible between a file mode (.portal) portal and a streaming desktop portal. In a file mode portal, the URL will look something like http://www.someserver.com/myapplication/myportal.portal. Therefore any relative links in the portal will be resolved against the http://www.someserver.com/myapplication address. Thus if you have a relative link of images/someimage.jpg the actual URL used by the browser to retrieve it is http://www.someserver.com/myapplication/images/someimage.jpg.
Now if you take that same code and run it in a streaming desktop you have a problem. A streaming desktop has a URL like http://www.someserver.com/myapplication/portal/desktop which means the previous link now gets resolved as http://www.someserver.com/myapplication/portal/desktop/images/someimage.jpg. Of course this will fail since the image cannot be found in that location.
Root relative links solve both issues rather neatly and are thus the best choice to use. One thing to keep in mind is that if you are constructing the URL manually make sure not to hard code the context path in the link. You should use the request.getContextPath() method or an equivalent so that if the context path of the application changes none of your links will break.
There is one minor exception to this and that is with respect to CSS files. A CSS file will often contain a link to an image, for example a background-url element that specifies the image to use for the background of an object. I prefer making these links relative instead of root relative for the simple reason that there is no easy way to dynamically insert the application's context path into the CSS. This is OK because the issue of file mode versus streaming mode portal URLs does not apply here, links in a CSS file are resolved according to the location of the CSS file not the document that referenced the CSS file. As a result the URL of the portal has no bearing on resolving image links within a CSS file.
beehive-url-template-config.xml
Staying with this discussion, those of you who have worked with Portal 9.2 or 10 know there is a file called beehive-url-template-config.xml that controls how Portal rewrites links. This template by default specifies that URLs be created as absolute links. This works well in simpler environents, but in more complex environments problems can occur when the Portal cannot properly deduce the correct parameters to use when building the absolute elements of the URL.
One option to work around this issue would be to hard-wire elements of the template file. For example, instead of using the {scheme} parameter simply hardwire in https instead if the portal is always accessed through SSL. This can work, but requires the creation of deployment plans when the absolute elements vary from environment to environment, for example differences between a test and a production environment. It can also be problematic when the portal can be accessed through multiple front ends, for example internal users go through a non-secure URL while external users go through a secure URL.
An alternative solution is to simply use a root relative version of the beehive-url-template-config.xml file. In this way we leave it to the browser to determine the scheme, domain and port based on the current URL. To make this change, switch to the merged projects view of your portal web application. Under WEB-INF, right click the beehive-url-template-config.xml file and select copy to project. Now edit the file to remove the scheme, domain and port from all entries. Here is an example of what the file looks like after the changes.
<?xml version="1.0" encoding="UTF-8"?>
<url-template-config xmlns="http://beehive.apache.org/netui/2004/server/url-template-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/servers/weblogic/url-template-config/8.0 url-template-config.xsd">
<url-template>
<name>default</name>
<value>
/{url:path}?{url:queryString}{url:currentPage}
</value>
</url-template>
<url-template>
<name>default-complete</name>
<value>
/{url:prefix}/{url:path}?{url:queryString}{url:currentPage}
</value>
</url-template>
<url-template>
<name>portlet-default</name>
<value>
/{url:path}?{url:queryString}{url:currentPage}
</value>
</url-template>
<url-template>
<name>portlet-secure-default</name>
<value>
/{url:path}?{url:queryString}{url:currentPage}
</value>
</url-template>
<url-template>
<name>portlet-action</name>
<value>
/{url:path}?{url:queryString}{url:currentPage}
</value>
</url-template>
<url-template>
<name>portlet-secure-action</name>
<value>
/{url:path}?{url:queryString}{url:currentPage}
</value>
</url-template>
<url-template>
<name>portlet-resource</name>
<value>
/{url:path}?{url:queryString}
</value>
</url-template>
<url-template>
<name>portlet-secure-resource</name>
<value>
/{url:path}?{url:queryString}
</value>
</url-template>
<!-- Templates for consuming remote portlets -->
<url-template>
<name>wsrp-default</name>
<value>
/{url:path}?{url:queryString}&wsrp-urlType={wsrp-urlType}&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-secureDefault</name>
<value>
/{url:path}?{url:queryString}&wsrp-urlType={wsrp-urlType}&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-blockingAction</name>
<value>
/{url:path}?{url:queryString}&wsrp-urlType=blockingAction&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-render</name>
<value>
/{url:path}?{url:queryString}&wsrp-urlType=render&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-resource</name>
<value>
/{url:path}/resource?{url:queryString}&wsrp-urlType=resource&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-secureBlockingAction</name>
<value>
/{url:path}?{url:queryString}&wsrp-urlType=blockingAction&wsrp-secureURL=true&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-secureRender</name>
<value>
/{url:path}?{url:queryString}&wsrp-urlType=render&wsrp-secureURL=true&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
</value>
</url-template>
<url-template>
<name>wsrp-secureResource</name>
<value>
/{url:path}/resource?{url:queryString}&wsrp-urlType=resource&wsrp-secureURL=true&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&{weblogic-passthru}
</value>
</url-template>
</url-template-config>
Posted by Gerald Nunn at 10:17 AM | Categories: WebLogic | Permalink
