This section covers the ajax features provided by the portal.
Part of the Ajax capabilities are implemented in the layout framework which provide the structure for generating portal pages. The good news is that the existing layout only requires a few modifications in order to be ajaxified.
We will use as example an simplified version of the layout JSP provided in JBoss Portal 2.6 and outline what are the required changes that makes it an ajaxified layout:
<%@ taglib uri="/WEB-INF/theme/portal-layout.tld" prefix="p" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html;"/> <!-- inject the theme, default to the Renaissance theme if nothing is selected for the portal or the page --> <p:theme themeName="renaissance"/> <!-- insert header content that was possibly set by portlets on the page --> <p:headerContent/> </head> <body id="body"> <p:region regionName='AJAXScripts' regionID='AJAXScripts'/> <div id="portal-container"> <div id="sizer"> <div id="expander"> <div id="logoName"></div> <table border="0" cellpadding="0" cellspacing="0" id="header-container"> <tr> <td align="center" valign="top" id="header"> <!-- Utility controls --> <p:region regionName='dashboardnav' regionID='dashboardnav'/> <!-- navigation tabs and such --> <p:region regionName='navigation' regionID='navigation'/> <div id="spacer"></div> </td> </tr> </table> <div id="content-container"> <!-- insert the content of the 'left' region of the page, and assign the css selector id 'regionA' --> <p:region regionName='left' regionID='regionA'/> <!-- insert the content of the 'center' region of the page, and assign the css selector id 'regionB' --> <p:region regionName='center' regionID='regionB'/> <hr class="cleaner"/> </div> </div> </div> </div> <p:region regionName='AJAXFooter' regionID='AJAXFooter'/> </body> </html>
At runtime the portal combines the layout and the renderers in order create the markup returned to the web browser. The most used render set is the divRenderer. Renderers only need a modification in the deployment descriptor to indicate that they support ajax. Here is the declaration of the default divRenderer now in 2.6:
<renderSet name="divRenderer"> <set content-type="text/html"> <ajax-enabled>true</ajax-enabled> <region-renderer>org.jboss.portal.theme.impl.render.div.DivRegionRenderer </region-renderer> <window-renderer>org.jboss.portal.theme.impl.render.div.DivWindowRenderer </window-renderer> <portlet-renderer>org.jboss.portal.theme.impl.render.div.DivPortletRenderer </portlet-renderer> <decoration-renderer>org.jboss.portal.theme.impl.render.div.DivDecorationRenderer </decoration-renderer> </set> </renderSet>
You should notice the <ajax-enabled>true</ajax-enabled> which indicates that the render set supports ajaxification.
The ajaxification of the portal pages can be configured in a fine grained manner. Thanks to the portal object properties it is possible to control which pages support ajax and which page do not support ajax. The administrator must pay attention to the fact that property values are inherited in the object hierarchy.
That feature is only effective in dashboards as it requires the offer personalization of the page layout per user. By default the feature is enabled thanks to a property set on the dashboard object. It is possible to turn off that property if the administrator does not want to expose that feature to its user.
In the file jboss-portal.sar/conf/data/default-object.xml is declared and configured the creation of the dashboard portal:
<deployment> <parent-ref/> <if-exists>keep</if-exists> <context> <context-name>dashboard</context-name> <properties> ... <property> <name>theme.dyna.dnd_enabled</name> <value>true</value> </property> ... </properties> ... </context> </deployment>
The property theme.dyna.dnd_enabled is set to the value true which means that the dashboard object will provide the drag and drop feature.
Partial refresh is a very powerful feature which allows the portal to optimize the refreshing of portlets on a page. When one portlet is invoked, instead of redrawing the full page, the portal is able to detect which portlets needs to be refreshed and will update only these portlets.
Like with the drag and drop feature, partial page refresh is controlled via properties on portal objects. The name of the property is theme.dyna.partial_refresh_enabled and its values can be true or false. When this property is set on an object it is automatically inherited by the sub hierarchy located under that object. By default the drag and drop feature is positionned on the dashboard object and not on the rest of the portal objects.
<deployment> <parent-ref/> <if-exists>keep</if-exists> <context> <context-name>dashboard</context-name> <properties> ... <property> <name>theme.dyna.partial_refresh_enabled</name> <value>true</value> </property> ... </properties> ... </context> </deployment>
It is possible to change that behavior at runtime using the property editor of the management portlet. If you want to enable partial refreshing on the default portal you should set the property to true directly on the portal and all the pages in that portal will automatically inherit those properties.
By default any portlet will support partial refreshing. When does the portal performs partial page refreshing ? By default it is enabled for action and render links with the following exceptions. In those situations, the portal will prefer to perform a full page refresh:
Form GET are not handled, however it should not be an issue as this situation is discouraged by the Portlet specification. It however taken in account, just in case of. Here is an example of a Java Server Page that would do one:
<form action="<%= renderResponse.createActionURL() %>" method="get"> ... </form>
Form uploads are not handled.
It can happen that a portlet does not want to support partial refreshing, in those situations the jboss-portlet.xml can be used to control that behavior. Since 2.6 an ajax section has been added in order to configure ajax features related to the portlet.
<portlet> <portlet-name>MyPortletNoAjax</portlet-name> <ajax> <partial-refresh>false</partial-refresh> </ajax> </portlet>
The usage of the partial-refresh set to the value false means that the portlet will not be subject of a partial page refresh when it is invoked. However the portlet markup can still be subject to a partial rendering.
Partial refreshing of portlets has limitations both on the server side (portal) and on the client side (browser).
When partial refresh is activated, the state of a page can potentially become inconsistent. for example, if some objects are shared in the application scope of the session between portlets. When one portlet update a session object, the other portlet won't be refreshed and will still display content based on the previous value of the object in the session. To avoid that, partial refresh can be desactivated for certain portlets by adding <portlet-refresh>false<portlet-refresh> in the jboss-portlet.xml file.
The solution developped by JBoss Portal on the client side is built on top of DOM events emitted by the web browser when the user interracts with the page. If an interaction is done without an emission of an event then JBoss Portal will not be able to transform it into a partial refresh and it will result instead of a full refresh. This can happen with programmatic submission of forms.
<form id="<%= formId %>" action="<%= renderResponse.createActionURL() %>" method="post"> ... <select onclick="document.getElementById('<%= formId %>').submit()"> ... </select> ... </form>