Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Apache MyFaces Trinidad 1.2 Web Application Groundwork: Part 1

Save for later
  • 480 min read
  • 2009-11-30 00:00:00

article-image

Navigation

Navigation deals with all aspects of the user to moving from one part of an application to another. This includes the following means that the application must support, to allow the user moving to a certain functionality that is available through various kinds of links:

  • Support of movement invocation through mouse clicks on tree nodes or keyboard shortcuts on such nodes, for example, menu items such as tr:commandNavigationItem, tr:commandLink, and s:link
  • Support of movement invocation through mouse-clicks on buttons or keyboard shortcuts on such controls, for example, tr:commandButton, s:button, and s:link
  • Support of movement invocation through mouse-clicks on hyper links or keyboard shortcuts on such links, for example, tr:commandLink, and s:link
  • Support of movement invocation through mouse-clicks on icon links or buttons, or keyboard shortcuts on such links or buttons, for example, tr:image, tr:icon, and so on
  • Further support for other variations of similar means of direct manipulation, for example, select boxes or radio buttons that cause a form to change in a way that encompasses moving to another page with more or other fields

The following Image shows various means of navigation that all have to be considered (tree links, button clicks, selections and so on):

apache-myfaces-trinidad-12-web-application-groundwork-part-1-img-0

To keep such navigation as simple, and yet as effective as technically possible, we move away from the Struts-inspired JSF way of declaring the navigation by means of XML files, something also kept up by Seam. We take advantage of Trinidad's dialog framework. It allows navigation on the pure Java side so that Seam's pages.xml can concentrate on the general navigation aspects such as exception handling or security/authorization. Following advantages can be observed in such an approach:

  • Navigation declarations are kept simple and manageable thanks to a small pages.xml and yet no *.page.xml files are needed.
  • Navigation occurs only in two areas—the XHTML and the application-specific Seam component controllers.
  • Navigation always works the same way—first the model is set up and made available to the view by the controller, then the controller navigates to the view using the dialog framework. Finally, when the view is left, it is either closed (click on X), cancelled (click on Cancel), or accepted (click on OK) which is followed by post processing such as selecting and passing a value on to another object.

You can access all the required sources, tools or plugins, and the sample project setup here.

Thus, for instance, the login dialog is a real programmatic Trinidad dialog as it is called the following way:

@Begin(join=true)
public void doLogin(javax.faces.event.ActionEvent event)
{
FacesContext jsfCtx = FacesContext.getCurrentInstance();
// Create the dialog UIViewRoot
ViewHandler viewHandler = jsfCtx.getApplication().
getViewHandler();
UIViewRoot dialog = viewHandler.createView(
jsfCtx, "/login.xhtml");
RequestContext trCtx = RequestContext.getCurrentInstance();
trCtx.launchDialog(dialog,null, event.getComponent(),
false, null);
}

Whereby the XHTML does not use the standard Trinidad dialog command features, but passes control to above action listener:

<tr:form>
<tr:commandLink id="loginCommandLink" text="Login"
actionListener="#{controller.doLogin}"
rendered="#{not identity.loggedIn}" blocking="true"
/>
</tr:form>

The only occurrences of login.xhtml in pages.xml are in the general declaration of pages.xml and in the general error handling, but no other navigation of login.xhtml needs to be declared:

<pages 

xsi:schemaLocation="http://jboss.com/products/seam/pages
http://jboss.com/products/seam/pages-2.0.xsd"
login-view-id="/login.xhtml">
...
<exception class="org.jboss.seam.security.NotLoggedInException">
<redirect view-id="/login.xhtml">
<message>Please log in first</message>
</redirect>
</exception>

Finally, the dialog is closed, which is again done in a programmatic way for Trinidad dialogs:

public void closeDialog()
{
Identity id = (Identity)Contexts.lookupInStatefulContexts(
org.jboss.seam.security.identity");
id.login();
RequestContext trCtx = RequestContext.getCurrentInstance();
trCtx.returnFromDialog(null,null);
}

This time, we do not need to deal with an event and close it by the simpler JSF action reference:

<div class="actionButtons">
<tr:commandButton text="Login" action="#{controller.closeDialog}" />
</div>

To understand the dialog logic behind above processes let us take a look at the general principles of the dialog framework that Trinidad provides.

Trinidad's Dialog Framework

The Apache MyFaces Trinidad Dialog Framework is an inheritance that stems back from the days of Oracle's ADF and UIX frameworks. It was the main way to navigate across dialogs, moving from page to page, from popup dialog to main browser dialog window, and so on. It offers a declarative way that works by using the conventional pages declarations as known from the pure JSF side, also in combination with Seam's pages.xml. Furthermore, it allows navigation in a purely programmatic manner as can be seen in the preceding examples. Nowadays, the dialog framework provided with Trinidad still counts as an alternative to the usual approach based in declaring pages and referencing them from within the application. Moreover, its uniform approach of dealing with both kinds of navigation, popup windows, and main browser windows remains as yet another attractive characteristic. For both reasons, we want to take advantage of this technique and concentrate on the purely programmatic side. For the declarative, please refer to http://myfaces.apache.org/trinidad/devguide/dialogs.html.

Programmatically creating a dialog

To create a dialog only the invocation of a method called launchDialog is required. It is a method provided by Trinidad's RequestContext object:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $15.99/month. Cancel anytime

public abstract void launchDialog(UIViewRoot dialogRoot,java.util.Map
dialogParameters, UIComponent source,
boolean useWindow, Map windowProperties);

So the developer needs to provide the following parameters:

  • A JSF component tree (the UIViewRoot dialogRoot)
  • Some objects to pass to the dialog, see the upcoming sub section
  • A JSF component from which the dialog is initiated and which receives a Trinidad ReturnEvent when the dialog to be shown is finished (closed)
  • A Boolean flag to set the display type, popup, or main window
  • The size of the pop-up window that is only required if the display type is a pop-up window which is set by putting integer objects into this map with keys width and height for window width and height respectively

In above example, we can see that:

ViewHandler viewHandler = jsfCtx.getApplication().getViewHandler();
UIViewRoot dialog = viewHandler.createView(jsfCtx, "/login.xhtml");
RequestContext trCtx = RequestContext.getCurrentInstance();
trCtx.launchDialog(dialog,null, event.getComponent(), false, null);

The JSF view handler is applied to create the new component tree based on the current JSF Faces context and the specific page to be shown in the dialog, which is the usual way. Next, in the actual call of the launchDialog method, we can see the purely programmatic approach without passing any objects to the dialog to be launched. Furthermore, we can see that because it is inside an action event listener of a commandLink, the dialog activity is linked with that link component. In other words, once the dialog is finished, a ReturnEvent is raised and handled by a respective return event listener on that component.

Providing the data flow from dialog to dialog

There are two alternatives to pass objects to a dialog and back:

  • Using Trinidad's page flow scope
  • Using Seam's scopes

The first way is sort of built-in to Trinidad dialogs because above dialogParameters is a map of parameters that is going to populate a newly created pageFlowScope map solely created for the upcoming dialog. This map also includes all the objects that stem from the currently available pageFlowScope. One could also think of it as a nested scope because once the dialog is finished, this map is not available anymore; therefore, any modifications to this newly nested scope will not be preserved once the dialog is closed.

The second way would be consistent with the rest of the web application is if the other parts use such important Seam scopes as conversation. Generally, it is more advisable to prefer one of both and avoid a mixture. In this article we take advantage of page flow scopes as Trinidad is in the foreground.

Returning from a dialog

Once the dialog is cancelled, or the activity accepted and finished, the application must link to Trinidad's standard closing process which is calling the returnFromDialog method of RequestContext. For example, the closeWindow needs to apply Trinidad's RequestContext:

RequestContext trCtx = RequestContext.getCurrentInstance();
trCtx.returnFromDialog(null,null);

This is a special case because the returnFromDialog method's signature is defined as follows:

public abstract void returnFromDialog(Object returnValue, 
Map<Object,Object>
returnParameters);

Generally, while invoking the returnFromDialog method, one provides return objects as dialog results, that is, for instance the result of a selection. Therefore, it is perfectly normal to return a single object as returnValue while returnParameters may remain null. In any case, the ReturnEvent object provides two methods to access such dialog results:

  • public Object getReturnValue(): This method yields the object that has been passed as the first parameter of the invocation of returnFromDialog
  • public Map<Object, Object> getReturnParameters(): This method yields the map that has been passed as the second parameter of the invocation of returnFromDialog

In the case of our simple closeDialog method, no parameters are passed back as Seam's login procedure does it all for us, and we do not need to pass anything back as it is saved by Seam in its identity object.

In the following section, we will see the specific example which is in our web sample application.