JBoss.orgCommunity Documentation
This chapter demonstrates common development tasks described by the 329 specification.
When your application uses request attributes on a per request basis and you do not want that particular attribute to be managed in the extended bridge request scope, you must use the following configuration in your faces-config.xml. Below you will see that any attribute namespaced as foo.bar or any attribute beginning with foo.baz(wildcard) will be excluded from the bridge request scope and only be used per that application's request.
When javax.faces.STATE_SAVING_METHOD is set to "client", you must exclude the "com.sun.faces.*" attribute(s) in faces-config.xml. This can also be achieved by using the web.xml init-param "javax.portlet.faces.excludedRequestAttributes"
<application> <application-extension> <bridge:excluded-attributes> <bridge:excluded-attribute>foo.bar</bridge:excluded-attribute> <bridge:excluded-attribute>foo.baz.*</bridge:excluded-attribute> </bridge:excluded-attributes> </application-extension> </application>
A PortletMode represents a distinct render path within an application. There are three standard modes: view, edit, and help. The bridge's ExternalContext.encodeActionURL recognizes the query string parameter javax.portlet.faces.PortletMode and uses this parameter's value to set the portlet mode on the underlying portlet actionURL or response. Once processed it then removes this parameter from the query string. This means the following navigation rule causes one to render the \edit.jspx viewId in the portlet edit mode:
<navigation-rule> <from-view-id>/register.jspx</from-view-id> <navigation-case> <from-outcome>edit</from-outcome> <to-view-id>/edit.jspx?javax.portlet.faces.PortletMode=edit</to-view-id> </navigation-case> </navigation-rule>
By default a mode change will start in the mode's default view without any (prior) existing state. One common portlet pattern when returning to the mode one left after entering another mode (e.g.. view -> edit -> view) is to return to the last view (and state) of this origin mode. The bridge will explicitly encode the necessary information so that when returning to a prior mode it can target the appropriate view and restore the appropriate state. The session attributes maintained by the bridge are intended to be used by developers to navigate back from a mode to the last location and state of a prior mode. As such a developer needs to describe a dynamic navigation: "from view X return to the last view of mode y". This is most easily expressed via an EL expression. E.g.
<navigation-rule> <from-view-id>/edit.jspx*</from-view-id> <navigation-case> <from-outcome>view</from-outcome> <to-view-id>#{sessionScope['javax.portlet.faces.viewIdHistory.view']}</to-view-id> </navigation-case> </navigation-rule>
Depending on the bridge implementation, when using values from these session scoped attributes or any viewIds which may contain query string parameters it may be necessary to use the wildcard syntax when identifying the rule target. For example, the above
<to-view-id>
expression returns a viewId of the form
/viewId?javax.portlet.faces.PortletMode=view&....
Without wildcarding, when a subsequent navigation occurs from this new view, the navigation rules wouldn't resolve because there wouldn't be an exact match. Likewise, the above edit.jspx
<from-view-id>
is wildcarded because there are navigation rules that target it that use a query string:
<to-view-id> /edit.jspx?javax.portlet.faces.PortletMode=edit </to-view-id>
Developers are encouraged to use such wildcarding to ensure they execute properly in the broadest set of bridge implementations.
Since Seam page actions are called during RENDER_RESPONSE, there is no guarantee how many times your portlet will be rendered. So page actions should only be used for navigation related tasks and never perform operations with side effects, ie. all page actions must be idempotent. For code that should only be called once in this scenario, component based actions should be used instead. They are called at the INVOKE_APPLICATION phase which is performed in the portal ActionRequest (one time per submit).
If you're developing a Seam portlet you can now use pages.xml for all error handling.
The following configuration may be used to handle exceptions. This is also useful for handling session timeout and ViewExpiredExceptions.
Pay attention to the location element. It must contain the /faces/ mapping to work properly.
<error-page> <exception-type>javax.servlet.ServletException</exception-type> <location>/faces/error.xhtml</location> </error-page> <error-page> <exception-type>javax.faces.application.ViewExpiredException</exception-type> <location>/faces/error.xhtml</location> </error-page>
By default, error handling is sent to a standard servlet page for Ajax requests. To handle the error inside the portlet, use the following javascript:
<script type="text/javascript"> A4J.AJAX.onError = function(req,status,message){ window.alert("Custom onError handler "+message); } A4J.AJAX.onExpired = function(loc,expiredMsg){ if(window.confirm("Custom onExpired handler "+expiredMsg+" for a location: "+loc)){ return loc; } else { return false; } } </script>
Also, add the following to web.xml. Read more about these settings here Request Errors and Session Expiration Handling
<context-param> <param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name> <param-value>true</param-value> </context-param>
There are roughly 4 different ways to send messages, events, and parameters between portlets which are contained in different ears/wars or contained in the same war. The Portlet Container does not care if you have 2 portlets in the same war or if they are separated, because each portlet has a different HttpSession.
Of course, with the Portlet 2.0 spec, the recommended way to share a parameter or event payload between 2 or more portlets are the Section 3.4.2, “Public Render Parameters” and Section 3.4.1, “Sending and Receiving Events” mechanisms. This allows you to decouple your application from surgically managing objects in the PortletSession.APPLICATION_SCOPE.
But, if these do not meet your usecase or you have a different strategy, you can use one of the following methods.
Sometimes it makes sense to store your Seam components in the portlet APPLICATION_SCOPE. By default, these objects are stored in the PORTLET_SCOPE but with the annotation below, you can fish this class out of the PortletSession and use its values in other portlets across different Seam applications.
@PortletScope(PortletScope.ScopeType.APPLICATION_SCOPE)
Then you would pull the statefull object from the session:
YourSessionClass yourSessionClass = (YourSessionClass)getRenderRequest().getAttribute("javax.portlet.p./default/seamproject/seamprojectPortletWindow?textHolder");
This method is demonstrated in this video: Lesson 2: Portlet 1.0 Advanced Seam and RichFaces
If you need to access the PortletSession to simply share a parameter/value across multiple portlets, you can use the following to do so.
Object objSession = FacesContext.getCurrentInstance().getExternalContext().getSession(false); try { if (objSession instanceof PortletSession) { PortletSession portalSession = (PortletSession)objSession; portalSession.setAttribute("your parameter name","parameter value",PortletSession.APPLICATION_SCOPE); ...
Then, in your JSP or Facelets page, you can use:
#{httpSessionScope['your parameter name']}
For more information about which EL variables are provided by the bridge, read section 6.5.1 of the JSR-329 specification.
For linking to any JSF/Facelets page within your portlet web application, you may use the following.
<h:outputLink value="#{facesContext.externalContext.requestContextPath}/home.xhtml"> <f:param name="javax.portlet.faces.ViewLink" value="true"/> navigate to the test page </h:outputLink>
To link to a non JSF view (i.e. jboss.org) you can use the following parameter.
<h:commandLink actionListener="#{yourBean.yourListenr}"> <f:param name="javax.portlet.faces.DirectLink" value="true"/> navigate to the test page </h:commandLink>
Then in your backing bean, you must call a redirect().
FacesContext.getCurrentInstance().getExternalContext().redirect("http://www.jboss.org");
All EL variables found in the JSR-329 (Portlet 2.0) specification are available in the JBoss Portlet Bridge. For example, you can use the following to edit the portlet preferences on the UI.
<h:form> <h:inputText id="pref" required="true" value="#{mutablePortletPreferencesValues['userName'].value}" /> <h:commandButton actionListener="#{myBean.savePref}" value="Save Preferences" /> </h:form>
Then in your backing bean, you must call the PortletPreferences.store() method.
Object request = FacesContext.getCurrentInstance().getExternalContext().getRequest(); PortletRequest portletRequest = (PortletRequest)request; if (request instanceof PortletRequest) { try { PortletPreferences portletPreferences = portletRequest.getPreferences(); portletPreferences.store();
When you send events using the method described here Section 3.4.1, “Sending and Receiving Events”, you can also leverage the EventNavigationResult and return a JSF navigation rule. For Example, by returning a
new EventNavigationResult("fromAction","Outcome");
the fromAction can be a catch all like "/*" or a nav rule defined in your faces-config.xml and outcome can be the from-outcome node defined in the faces-config.xml navigation rule.